From 6bb05dc4b2d7922191a6e92bd0253361e21eeef6 Mon Sep 17 00:00:00 2001
From: Zahen Malla Osman <zahen.malla-osman@abolis.fr>
Date: Fri, 22 Feb 2019 11:51:23 +0100
Subject: [PATCH 01/10] Put back package.json in dist.

"A package must contain a package.json file in order to be published to the npm registry":
https://docs.npmjs.com/about-packages-and-modules#about-packages
---
 dist/package.json | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 gulpfile.js       |  8 +++++++-
 2 files changed, 56 insertions(+), 1 deletion(-)
 create mode 100644 dist/package.json

diff --git a/dist/package.json b/dist/package.json
new file mode 100644
index 0000000..4f0efc3
--- /dev/null
+++ b/dist/package.json
@@ -0,0 +1,49 @@
+{
+  "name": "plate-map",
+  "version": "1.0.2",
+  "description": "JavaScript Plate Layout is an open source tool developed collaboratively by [Chai Biotechnologies](www.chaibio.com) and [New England Biolabs](www.neb.com) for visualizing and editing the layout of scientific assay plates.",
+  "scripts": {
+    "build.dist": "gulp build.dist",
+    "build.dev": "gulp build.dev",
+    "serve.dev": "gulp serve.dev",
+    "build.prod": "gulp build.prod",
+    "serve.prod": "gulp serve.prod",
+    "start": "gulp serve.dev"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/nebiolabs/plate-map.git"
+  },
+  "main": "dist/js/plate-map.js",
+  "style": "dist/css/plate-map.css",
+  "keywords": [],
+  "author": "Langhorst, Brad <Langhorst@neb.com>",
+  "license": "AGPL-3.0-only",
+  "bugs": {
+    "url": "https://github.com/nebiolabs/plate-map/issues"
+  },
+  "homepage": "https://github.com/nebiolabs/plate-map#readme",
+  "dependencies": {
+    "bootstrap": "^4.1.3",
+    "clipboard": "^2.0.4",
+    "fabric": "^2.6.0",
+    "jquery": "^3.3.1",
+    "jquery-ui-dist": "^1.12.1",
+    "popper.js": "^1.14.7",
+    "select2": "^3.5.1"
+  },
+  "devDependencies": {
+    "browser-sync": "^2.26.3",
+    "del": "^3.0.0",
+    "gulp": "^4.0.0",
+    "gulp-clean-css": "^4.0.0",
+    "gulp-concat": "^2.6.1",
+    "gulp-connect": "^5.7.0",
+    "gulp-htmlmin": "^5.0.1",
+    "gulp-inject": "^5.0.2",
+    "gulp-rename": "^1.4.0",
+    "gulp-uglify": "^3.0.1",
+    "merge-stream": "^1.0.1",
+    "run-sequence": "^2.2.1"
+  }
+}
diff --git a/gulpfile.js b/gulpfile.js
index b8dba8e..af87bc4 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -99,6 +99,7 @@ gulp.task('config.pack', async () => {
     config.source.css = PATH.source.app.css;
     config.source.js = PATH.source.app.js;
     config.source.js.push('!src/js/example.js');
+    config.source.json = PATH.source.app.json;
     config.destination.css = PATH.destination.pack.css;
     config.destination.js = PATH.destination.pack.js;
     config.destination.root = PATH.destination.pack.root;
@@ -130,6 +131,11 @@ gulp.task('copy.img', () => {
         .pipe(gulp.dest(config.destination.css));
 });
 
+gulp.task('copy.package.json', () => {
+   return gulp.src(config.source.json)
+       .pipe(gulp.dest(config.destination.root));
+});
+
 gulp.task('inject.prod', () => {
     return gulp.src(config.source.html)
         .pipe(inject(gulp.src([`${config.destination.css}/*.min.css`, `${config.destination.js}/*.min.js`], {read: false}),
@@ -176,7 +182,7 @@ gulp.task('server.prod', async () => {
     });
 });
 
-gulp.task('build.dist', gulp.series('config.pack', 'clean', 'css', 'js'));
+gulp.task('build.dist', gulp.series('config.pack', 'clean', 'css', 'js', 'copy.package.json'));
 
 gulp.task('build.dev', gulp.series('config.dev', 'clean', 'copy.src', 'copy.img', 'inject.dev'));
 

From 441e6a9b31bc4bcfaac72ba234f7db0011e27885 Mon Sep 17 00:00:00 2001
From: Zahen Malla Osman <zahen.malla-osman@abolis.fr>
Date: Fri, 22 Feb 2019 12:12:58 +0100
Subject: [PATCH 02/10] Fix serve.dev in gulpfile.js

---
 gulpfile.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/gulpfile.js b/gulpfile.js
index af87bc4..bcb554c 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -171,8 +171,7 @@ gulp.task('inject.dev', () => {
 
 gulp.task('server.dev', async () => {
     browserSync.init({server: PATH.destination.dev.root});
-    gulp.watch([PATH.source.app.css, PATH.source.app.js], ['build.dev'])
-        .on('change', browserSync.reload);
+    gulp.watch(PATH.source.app.css.concat(PATH.source.app.js), gulp.series('build.dev', browserSync.reload));
 });
 
 gulp.task('server.prod', async () => {

From 51faff617e0e57fd339f5674a02436c10dc8dd0d Mon Sep 17 00:00:00 2001
From: Zahen Malla Osman <zahen.malla-osman@abolis.fr>
Date: Fri, 1 Mar 2019 12:10:44 +0100
Subject: [PATCH 03/10] Remove package.json from dist again

---
 dist/package.json | 49 -----------------------------------------------
 gulpfile.js       | 11 ++---------
 2 files changed, 2 insertions(+), 58 deletions(-)
 delete mode 100644 dist/package.json

diff --git a/dist/package.json b/dist/package.json
deleted file mode 100644
index 4f0efc3..0000000
--- a/dist/package.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  "name": "plate-map",
-  "version": "1.0.2",
-  "description": "JavaScript Plate Layout is an open source tool developed collaboratively by [Chai Biotechnologies](www.chaibio.com) and [New England Biolabs](www.neb.com) for visualizing and editing the layout of scientific assay plates.",
-  "scripts": {
-    "build.dist": "gulp build.dist",
-    "build.dev": "gulp build.dev",
-    "serve.dev": "gulp serve.dev",
-    "build.prod": "gulp build.prod",
-    "serve.prod": "gulp serve.prod",
-    "start": "gulp serve.dev"
-  },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/nebiolabs/plate-map.git"
-  },
-  "main": "dist/js/plate-map.js",
-  "style": "dist/css/plate-map.css",
-  "keywords": [],
-  "author": "Langhorst, Brad <Langhorst@neb.com>",
-  "license": "AGPL-3.0-only",
-  "bugs": {
-    "url": "https://github.com/nebiolabs/plate-map/issues"
-  },
-  "homepage": "https://github.com/nebiolabs/plate-map#readme",
-  "dependencies": {
-    "bootstrap": "^4.1.3",
-    "clipboard": "^2.0.4",
-    "fabric": "^2.6.0",
-    "jquery": "^3.3.1",
-    "jquery-ui-dist": "^1.12.1",
-    "popper.js": "^1.14.7",
-    "select2": "^3.5.1"
-  },
-  "devDependencies": {
-    "browser-sync": "^2.26.3",
-    "del": "^3.0.0",
-    "gulp": "^4.0.0",
-    "gulp-clean-css": "^4.0.0",
-    "gulp-concat": "^2.6.1",
-    "gulp-connect": "^5.7.0",
-    "gulp-htmlmin": "^5.0.1",
-    "gulp-inject": "^5.0.2",
-    "gulp-rename": "^1.4.0",
-    "gulp-uglify": "^3.0.1",
-    "merge-stream": "^1.0.1",
-    "run-sequence": "^2.2.1"
-  }
-}
diff --git a/gulpfile.js b/gulpfile.js
index bcb554c..0025657 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -16,8 +16,7 @@ const PATH = {
         app: {
             css: ['src/css/*.css'],
             js: ['src/js/*.js'],
-            html: 'src/index.html',
-            json: 'package.json'
+            html: 'src/index.html'
         },
         dependencies: {
             css: [
@@ -99,7 +98,6 @@ gulp.task('config.pack', async () => {
     config.source.css = PATH.source.app.css;
     config.source.js = PATH.source.app.js;
     config.source.js.push('!src/js/example.js');
-    config.source.json = PATH.source.app.json;
     config.destination.css = PATH.destination.pack.css;
     config.destination.js = PATH.destination.pack.js;
     config.destination.root = PATH.destination.pack.root;
@@ -131,11 +129,6 @@ gulp.task('copy.img', () => {
         .pipe(gulp.dest(config.destination.css));
 });
 
-gulp.task('copy.package.json', () => {
-   return gulp.src(config.source.json)
-       .pipe(gulp.dest(config.destination.root));
-});
-
 gulp.task('inject.prod', () => {
     return gulp.src(config.source.html)
         .pipe(inject(gulp.src([`${config.destination.css}/*.min.css`, `${config.destination.js}/*.min.js`], {read: false}),
@@ -181,7 +174,7 @@ gulp.task('server.prod', async () => {
     });
 });
 
-gulp.task('build.dist', gulp.series('config.pack', 'clean', 'css', 'js', 'copy.package.json'));
+gulp.task('build.dist', gulp.series('config.pack', 'clean', 'css', 'js'));
 
 gulp.task('build.dev', gulp.series('config.dev', 'clean', 'copy.src', 'copy.img', 'inject.dev'));
 

From 7466d0ce379ec8302f7c815177ac9b8679293229 Mon Sep 17 00:00:00 2001
From: Zahen Malla Osman <zahen.malla-osman@abolis.fr>
Date: Fri, 8 Feb 2019 17:38:23 +0100
Subject: [PATCH 04/10] Scroll to group in the bottom table on single well
 selection

---
 README.md                      |   16 +-
 dist/css/plate-map.css         |  491 ----
 dist/css/plate-map.min.css     |    2 -
 dist/css/plate-map.min.css.map |    1 -
 dist/js/plate-map.js           | 4360 --------------------------------
 dist/js/plate-map.min.js       |    2 -
 dist/js/plate-map.min.js.map   |    1 -
 src/js/bottom-table.js         |    2 +-
 src/js/engine.js               |    4 +-
 src/js/example.js              |    1 +
 src/js/fabric-events.js        |    3 +
 src/js/plate-layout.js         |  582 +++--
 12 files changed, 324 insertions(+), 5141 deletions(-)
 delete mode 100644 dist/css/plate-map.css
 delete mode 100644 dist/css/plate-map.min.css
 delete mode 100644 dist/css/plate-map.min.css.map
 delete mode 100755 dist/js/plate-map.js
 delete mode 100755 dist/js/plate-map.min.js
 delete mode 100644 dist/js/plate-map.min.js.map

diff --git a/README.md b/README.md
index c3cba77..2cdd6c0 100644
--- a/README.md
+++ b/README.md
@@ -467,20 +467,10 @@ options for subfield id `raw_value` will be `["unit1", "unit2"]` , which is used
 ## Requirements
 **Note** that this project was tested with _Node_ v9.10.1 and _NPM_ v5.6.0.
 
-If this is your first time, start by installing the npm dependencies: `npm install`
+If this is your first time:
+1. install the (os) dependencies of the `canvas` library: https://www.npmjs.com/package/canvas/v/1.6.11
+2. run `npm install` in this directory
 
-Building this project also requires the libraries _gif_lib_ and _jpeg_lib_ (required the _Canvas_ npm package).
-
-- On Linux/Ubuntu :
-    ```bash
-    sudo apt install libgif-dev
-    sudo apt install libjpeg-dev
-    ```
-- On Mac OS :
-    ```bash
-    brew install giflib
-    brew install libjpeg
-    ```
    
 ## Project Structure
 ```
diff --git a/dist/css/plate-map.css b/dist/css/plate-map.css
deleted file mode 100644
index f44a69c..0000000
--- a/dist/css/plate-map.css
+++ /dev/null
@@ -1,491 +0,0 @@
-@import url(http://fonts.googleapis.com/css?family=Roboto);
-
-.plate-setup-container {
-  width: 1024px;
-  height: 768px;
-  position: relative;
-  float: left;
-}
-
-.plate-setup-wrapper {
-  position: absolute;
-  top: 0;
-  left: 0;
-  bottom: 0;
-  right: 0;
-  flex-direction: column;
-  background-color: #f5f5f5;
-}
-
-.plate-setup-top-section {
-  height: 540px;
-  top: 0;
-  left: 0;
-  right: 0;
-  position: absolute;
-}
-
-.plate-setup-top-left {
-  width: 674px;
-  top: 0;
-  bottom: 0;
-  position: absolute;
-}
-
-.plate-setup-top-right {
-  left: 674px;
-  top: 0;
-  bottom: 0;
-  right: 0;
-  position: absolute;
-}
-
-.plate-setup-overlay-container {
-  height: 32px;
-  top: 10px;
-  left: 16px;
-  right: 16px;
-  position: inherit;
-  background-color: #464646;
-  border-radius: 2px;
-  display: flex;
-  justify-content: space-between;
-  align-items: baseline;
-  vertical-align: middle;
-}
-
-.plate-setup-overlay-radio-container {
-  width: 32px;
-  height: 32px;
-}
-
-.plate-setup-overlay-text-container {
-  color: white;
-  font-size: 12px;
-  line-height: 30px;
-  height: 32px;
-  font-family: "Roboto", Arial, sans-serif;
-  margin: 2px 8px;
-  flex: 1 1 auto;
-}
-
-.plate-setup-overlay-button-container, .plate-setup-overlay-bottom-button-container {
-  flex: 0 0 auto;
-  display: flex;
-  flex: 1 1 0;
-}
-
-.plate-setup-button {
-  height: 23px;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  border: none;
-  background-color: white;
-  border-radius: 2px;
-  margin-right: 4px;
-  flex: 1 0 0;
-  white-space: nowrap;
-}
-
-.plate-setup-clicked-button {
-  height: 23px;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  border: none;
-  background-color: aquamarine;
-  border-radius: 2px;
-  margin-right: 4px;
-  flex: 1 0 0;
-  white-space: nowrap;
-}
-
-
-.plate-setup-canvas-container {
-  top: 52px;
-  left: 16px;
-  right: 16px;
-  bottom: 10px;
-  position: absolute;
-}
-
-.plate-setup-tab-container {
-  position: absolute;
-  top:10px;
-  left:10px;
-  bottom: 10px;
-  right: 10px;
-  background-color: white;
-  border: solid 1px #e1e1e1;
-}
-
-.plate-setup-tab-head {
-  left: 0;
-  right: 0;
-  height: 23px;
-  border-bottom: solid 1px #e1e1e1;
-  background-color: #f5f5f5;
-  display: flex;
-}
-
-.plate-setup-tab {
-  height: 23px;
-  background-color: #ebebeb;
-  border-right: solid 1px #e1e1e1;
-  cursor: pointer;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 10px;
-  text-align: center;
-  padding: 5px;
-  box-sizing: border-box;
-  flex: 1 1 auto;
-  white-space: nowrap;
-  overflow: hidden;
-}
-
-.plate-setup-tab:last-child {
-  border-right: none;
-}
-
-.plate-setup-tab-selected {
-  height: 24px;
-  background-color: white;
-  color: #00506e;
-  flex-shrink: 0;
-}
-
-.plate-setup-tab-data-container {
-  left: 0;
-  right: 0;
-  height: 442px;
-  border-bottom: solid 1px #e1e1e1;
-  position: absolute;
-  font-family: "Roboto", Arial, sans-serif;
-}
-
-.plate-setup-data-div {
-  top: 0;
-  left: 0;
-  bottom: 0;
-  right: 0;
-  position: absolute;
-  background-color: white;
-  overflow: auto;
-}
-
-.plate-setup-well-attr-container {
-  top: 472px;
-  left: 0;
-  right: 0;
-  height: 20px;
-  box-sizing: border-box;
-  padding: 0px 16px;
-  color: #00506e;
-  text-align: center;
-  position: absolute;
-  font-size: 10px;
-  font-family: "Roboto", Arial, sans-serif;
-}
-
-.plate-setup-preset-container {
-  top: 490px;
-  left: 0;
-  right: 0;
-  height: 22px;
-  position: absolute;
-  box-sizing: border-box;
-  padding: 0px 16px;
-  text-align: center;
-  display: flex;
-  justify-content: center;
-}
-
-.plate-setup-prest-tab {
-  display: inline-block;
-  flex-basis: 50px;
-  padding: 0 5px;
-  margin: 0 1px;
-  height: 20px;
-  background-color: white;
-  border: solid 1px #e1e1e1;
-  border-radius: 2px;
-  cursor: pointer;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 10px;
-  text-align: center;
-}
-
-.plate-setup-prest-tab-selected {
-  display: inline-block;
-  flex-basis: 50px;
-  padding: 0 5px;
-  margin: 0 1px;
-  height: 20px;
-  background-color: #e1e1e1;
-  border: solid 1px #e1e1e1;
-  border-radius: 2px;
-  cursor: pointer;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 11px;
-  text-align: center;
-  color: #00506e;
-}
-
-.plate-setup-prest-tab-div {
-  padding-top: 3px;
-}
-
-.plate-setup-tab-default-field {
-  display: flex;
-  padding: 10px 16px 0 16px;
-}
-
-.plate-setup-tab-field-left-side {
-  width: 32px;
-  padding-top: 16px;
-}
-
-.plate-setup-tab-field-right-side {
-  flex: 1;
-}
-
-.plate-setup-tab-name {
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  display: inline-block;
-  line-height: 16px;
-}
-
-.plate-setup-tab-name-singleSelect {
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  margin-top: 5px;
-}
-
-
-.plate-setup-tab-name-missing {
-  height: 20px;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  background: red;
-}
-
-
-.plate-setup-tab-field-container, .plate-setup-tab-field-container-singleSelect {
-  width: 100%;
-  display: flex;
-}
-
-.plate-setup-tab-input, .plate-setup-tab-select-field, .plate-setup-tab-multiplex-single-select-field {
-  height: 28px;
-  flex: 1 1 auto;
-  width: 30px;
-  margin: auto;
-}
-
-.plate-setup-tab-multiselect-field {
-  min-height: 28px;
-  flex: 1 1 auto;
-  width: 30px;
-}
-
-.plate-setup-tab-label-select-field, .plate-setup-tab-unit {
-  width: 130px;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  height: 28px;
-  box-sizing: border-box;
-  padding-left: 5px;
-}
-
-.plate-setup-tab-unit {
-  font-family: "Roboto", Arial, sans-serif;
-  line-height: 26px;
-  color: #444;
-  white-space: nowrap;
-}
-
-.plate-setup-tab-check-box {
-  cursor: pointer;
-  border: 1px solid gray;
-  display: inline-block;
-  height: 16px;
-  width: 16px;
-  text-align: center;
-  line-height: 16px;
-}
-
-.plate-setup-bottom-control-container {
-  top: 0;
-  left: 0;
-  right: 0;
-  height: 32px;
-  background-color: #464646;
-  position: absolute;
-  display: flex;
-  justify-content:space-between;
-  align-items: baseline;
-  vertical-align: middle;
-}
-
-.plate-setup-bottom-container {
-  top: 540px;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  position: absolute;
-  background-color: #e1e1e1;
-}
-
-.plate-setup-bottom-table-container {
-  top: 32px;
-  left: 0;
-  bottom: 0;
-  right: 0;
-  position: absolute;
-  overflow: auto;
-}
-
-
-.plate-setup-bottom-table {
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 14px;
-  border-collapse: collapse;
-  width: 100%;
-}
-
-.plate-setup-bottom-table th {
-  border: solid #c2c2c2 1px;
-  padding: 5px 10px;
-  font-weight: bold;
-  font-size: 12px;
-  text-align: left;
-}
-
-.plate-setup-bottom-table td {
-  border: solid #c2c2c2 1px;
-  padding: 5px 10px;
-  background-color: white;
-}
-
-.plate-setup-color-text {
-  font-size: 14px;
-  border: none;
-  border-radius: 2px;
-  padding: 3px 15px;
-  background-color: WHITE;
-  margin-right: 4px;
-}
-
-.plate-setup-bottom-id {
-  width: 40px;
-  text-align: center;
-  background-image: linear-gradient(to right, rgba(255,255,255,0.3), transparent)
-}
-
-input.invalid {
-  background-color: pink;
-}
-
-.plate-setup-remove-all-button-container {
-  text-align: left;
-}
-
-.plate-setup-remove-all-button{
-  width: 100%;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  text-overflow: ellipsis;
-  text-align: left;
-  white-space: nowrap;
-  border: 1px solid #aaa;
-  border-top: none;
-  color: #444;
-  background-color: #fff;
-  background-image: linear-gradient(to top, #eee 0%, #fff 50%);
-}
-/* Modal Content */
-
-.modal {
-  display: none; /* Hidden by default */
-  position: fixed; /* Stay in place */
-  z-index: 2000; /* Sit on top */
-  padding-top: 100px; /* Location of the box */
-  left: 0;
-  top: 0;
-  width: 100%; /* Full width */
-  height: 100%; /* Full height */
-  overflow: auto; /* Enable scroll if needed */
-  background-color: rgb(0,0,0); /* Fallback color */
-  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
-}
-
-.modal-content {
-  font-family: 'Roboto', sans-serif;
-  font-size: 14px;
-  background-color: #fefefe;
-  margin: auto;
-  padding: 20px;
-  border: 1px solid #888;
-}
-
-.delete-dialog .modal-content {
-  width: 550px;
-}
-
-.modal-content > * {
-  width: 100%;
-}
-
-.dialog-buttons {
-  margin-top: 10px;
-  display: inline-block;
-  text-align: right;
-}
-
-.dialog-buttons button {
-  margin-left: 4px;
-}
-
-.plate-popout-table {
-  border-collapse: collapse;
-  width: 100%;
-  border: 1px solid black;
-  padding: 5px;
-}
-
-.plate-popout-th {
-  text-align: left;
-  background-color: white;
-  color: black;
-  font-size: 12px;
-  border: 1px solid black;
-  padding: 5px;
-}
-
-.plate-popout-tr:hover {
-  background-color: #f5f5f5;
-  border: 1px solid black;
-  padding: 5px;
-}
-
-.plate-popout-td {
-  text-align: left;
-  font-size: 11px;
-  border: 1px solid black;
-  padding: 5px;
-}
-
-.plate-field-warning-image{
-  vertical-align: baseline;
-  margin: 0px 0 0px;
-}
-
-.pop-out-text {
-  position: fixed;
-  display: none;
-  background: white;
-  border: 1px solid;
-  float: left;
-  margin-top: -44px;
-  z-Index: 99999 !important;
-}
diff --git a/dist/css/plate-map.min.css b/dist/css/plate-map.min.css
deleted file mode 100644
index d7ff6e2..0000000
--- a/dist/css/plate-map.min.css
+++ /dev/null
@@ -1,2 +0,0 @@
-@import url(http://fonts.googleapis.com/css?family=Roboto);.plate-setup-container{width:1024px;height:768px;position:relative;float:left}.plate-setup-wrapper{position:absolute;top:0;left:0;bottom:0;right:0;flex-direction:column;background-color:#f5f5f5}.plate-setup-top-section{height:540px;top:0;left:0;right:0;position:absolute}.plate-setup-top-left{width:674px;top:0;bottom:0;position:absolute}.plate-setup-top-right{left:674px;top:0;bottom:0;right:0;position:absolute}.plate-setup-overlay-container{height:32px;top:10px;left:16px;right:16px;position:inherit;background-color:#464646;border-radius:2px;display:flex;justify-content:space-between;align-items:baseline;vertical-align:middle}.plate-setup-overlay-radio-container{width:32px;height:32px}.plate-setup-overlay-text-container{color:#fff;font-size:12px;line-height:30px;height:32px;font-family:Roboto,Arial,sans-serif;margin:2px 8px;flex:1 1 auto}.plate-setup-overlay-bottom-button-container,.plate-setup-overlay-button-container{flex:0 0 auto;display:flex;flex:1 1 0}.plate-setup-button{height:23px;font-family:Roboto,Arial,sans-serif;font-size:12px;border:none;background-color:#fff;border-radius:2px;margin-right:4px;flex:1 0 0;white-space:nowrap}.plate-setup-clicked-button{height:23px;font-family:Roboto,Arial,sans-serif;font-size:12px;border:none;background-color:#7fffd4;border-radius:2px;margin-right:4px;flex:1 0 0;white-space:nowrap}.plate-setup-canvas-container{top:52px;left:16px;right:16px;bottom:10px;position:absolute}.plate-setup-tab-container{position:absolute;top:10px;left:10px;bottom:10px;right:10px;background-color:#fff;border:solid 1px #e1e1e1}.plate-setup-tab-head{left:0;right:0;height:23px;border-bottom:solid 1px #e1e1e1;background-color:#f5f5f5;display:flex}.plate-setup-tab{height:23px;background-color:#ebebeb;border-right:solid 1px #e1e1e1;cursor:pointer;font-family:Roboto,Arial,sans-serif;font-size:10px;text-align:center;padding:5px;box-sizing:border-box;flex:1 1 auto;white-space:nowrap;overflow:hidden}.plate-setup-tab:last-child{border-right:none}.plate-setup-tab-selected{height:24px;background-color:#fff;color:#00506e;flex-shrink:0}.plate-setup-tab-data-container{left:0;right:0;height:442px;border-bottom:solid 1px #e1e1e1;position:absolute;font-family:Roboto,Arial,sans-serif}.plate-setup-data-div{top:0;left:0;bottom:0;right:0;position:absolute;background-color:#fff;overflow:auto}.plate-setup-well-attr-container{top:472px;left:0;right:0;height:20px;box-sizing:border-box;padding:0 16px;color:#00506e;text-align:center;position:absolute;font-size:10px;font-family:Roboto,Arial,sans-serif}.plate-setup-preset-container{top:490px;left:0;right:0;height:22px;position:absolute;box-sizing:border-box;padding:0 16px;text-align:center;display:flex;justify-content:center}.plate-setup-prest-tab{display:inline-block;flex-basis:50px;padding:0 5px;margin:0 1px;height:20px;background-color:#fff;border:solid 1px #e1e1e1;border-radius:2px;cursor:pointer;font-family:Roboto,Arial,sans-serif;font-size:10px;text-align:center}.plate-setup-prest-tab-selected{display:inline-block;flex-basis:50px;padding:0 5px;margin:0 1px;height:20px;background-color:#e1e1e1;border:solid 1px #e1e1e1;border-radius:2px;cursor:pointer;font-family:Roboto,Arial,sans-serif;font-size:11px;text-align:center;color:#00506e}.plate-setup-prest-tab-div{padding-top:3px}.plate-setup-tab-default-field{display:flex;padding:10px 16px 0 16px}.plate-setup-tab-field-left-side{width:32px;padding-top:16px}.plate-setup-tab-field-right-side{flex:1}.plate-setup-tab-name{font-family:Roboto,Arial,sans-serif;font-size:12px;display:inline-block;line-height:16px}.plate-setup-tab-name-singleSelect{font-family:Roboto,Arial,sans-serif;font-size:12px;margin-top:5px}.plate-setup-tab-name-missing{height:20px;font-family:Roboto,Arial,sans-serif;font-size:12px;background:red}.plate-setup-tab-field-container,.plate-setup-tab-field-container-singleSelect{width:100%;display:flex}.plate-setup-tab-input,.plate-setup-tab-multiplex-single-select-field,.plate-setup-tab-select-field{height:28px;flex:1 1 auto;width:30px;margin:auto}.plate-setup-tab-multiselect-field{min-height:28px;flex:1 1 auto;width:30px}.plate-setup-tab-label-select-field,.plate-setup-tab-unit{width:130px;overflow:hidden;text-overflow:ellipsis;height:28px;box-sizing:border-box;padding-left:5px}.plate-setup-tab-unit{font-family:Roboto,Arial,sans-serif;line-height:26px;color:#444;white-space:nowrap}.plate-setup-tab-check-box{cursor:pointer;border:1px solid gray;display:inline-block;height:16px;width:16px;text-align:center;line-height:16px}.plate-setup-bottom-control-container{top:0;left:0;right:0;height:32px;background-color:#464646;position:absolute;display:flex;justify-content:space-between;align-items:baseline;vertical-align:middle}.plate-setup-bottom-container{top:540px;left:0;right:0;bottom:0;position:absolute;background-color:#e1e1e1}.plate-setup-bottom-table-container{top:32px;left:0;bottom:0;right:0;position:absolute;overflow:auto}.plate-setup-bottom-table{font-family:Roboto,Arial,sans-serif;font-size:14px;border-collapse:collapse;width:100%}.plate-setup-bottom-table th{border:solid #c2c2c2 1px;padding:5px 10px;font-weight:700;font-size:12px;text-align:left}.plate-setup-bottom-table td{border:solid #c2c2c2 1px;padding:5px 10px;background-color:#fff}.plate-setup-color-text{font-size:14px;border:none;border-radius:2px;padding:3px 15px;background-color:#fff;margin-right:4px}.plate-setup-bottom-id{width:40px;text-align:center;background-image:linear-gradient(to right,rgba(255,255,255,.3),transparent)}input.invalid{background-color:pink}.plate-setup-remove-all-button-container{text-align:left}.plate-setup-remove-all-button{width:100%;font-family:Roboto,Arial,sans-serif;font-size:12px;text-overflow:ellipsis;text-align:left;white-space:nowrap;border:1px solid #aaa;border-top:none;color:#444;background-color:#fff;background-image:linear-gradient(to top,#eee 0,#fff 50%)}.modal{display:none;position:fixed;z-index:2000;padding-top:100px;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,.4)}.modal-content{font-family:Roboto,sans-serif;font-size:14px;background-color:#fefefe;margin:auto;padding:20px;border:1px solid #888}.delete-dialog .modal-content{width:550px}.modal-content>*{width:100%}.dialog-buttons{margin-top:10px;display:inline-block;text-align:right}.dialog-buttons button{margin-left:4px}.plate-popout-table{border-collapse:collapse;width:100%;border:1px solid #000;padding:5px}.plate-popout-th{text-align:left;background-color:#fff;color:#000;font-size:12px;border:1px solid #000;padding:5px}.plate-popout-tr:hover{background-color:#f5f5f5;border:1px solid #000;padding:5px}.plate-popout-td{text-align:left;font-size:11px;border:1px solid #000;padding:5px}.plate-field-warning-image{vertical-align:baseline;margin:0 0 0}.pop-out-text{position:fixed;display:none;background:#fff;border:1px solid;float:left;margin-top:-44px;z-Index:99999!important}
-/*# sourceMappingURL=plate-map.min.css.map */
\ No newline at end of file
diff --git a/dist/css/plate-map.min.css.map b/dist/css/plate-map.min.css.map
deleted file mode 100644
index 1d3e613..0000000
--- a/dist/css/plate-map.min.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["plate-layout.css"],"names":[],"mappings":"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","file":"plate-map.min.css","sourcesContent":["@import url(http://fonts.googleapis.com/css?family=Roboto);\n\n.plate-setup-container {\n  width: 1024px;\n  height: 768px;\n  position: relative;\n  float: left;\n}\n\n.plate-setup-wrapper {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  flex-direction: column;\n  background-color: #f5f5f5;\n}\n\n.plate-setup-top-section {\n  height: 540px;\n  top: 0;\n  left: 0;\n  right: 0;\n  position: absolute;\n}\n\n.plate-setup-top-left {\n  width: 674px;\n  top: 0;\n  bottom: 0;\n  position: absolute;\n}\n\n.plate-setup-top-right {\n  left: 674px;\n  top: 0;\n  bottom: 0;\n  right: 0;\n  position: absolute;\n}\n\n.plate-setup-overlay-container {\n  height: 32px;\n  top: 10px;\n  left: 16px;\n  right: 16px;\n  position: inherit;\n  background-color: #464646;\n  border-radius: 2px;\n  display: flex;\n  justify-content: space-between;\n  align-items: baseline;\n  vertical-align: middle;\n}\n\n.plate-setup-overlay-radio-container {\n  width: 32px;\n  height: 32px;\n}\n\n.plate-setup-overlay-text-container {\n  color: white;\n  font-size: 12px;\n  line-height: 30px;\n  height: 32px;\n  font-family: \"Roboto\", Arial, sans-serif;\n  margin: 2px 8px;\n  flex: 1 1 auto;\n}\n\n.plate-setup-overlay-button-container, .plate-setup-overlay-bottom-button-container {\n  flex: 0 0 auto;\n  display: flex;\n  flex: 1 1 0;\n}\n\n.plate-setup-button {\n  height: 23px;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  border: none;\n  background-color: white;\n  border-radius: 2px;\n  margin-right: 4px;\n  flex: 1 0 0;\n  white-space: nowrap;\n}\n\n.plate-setup-clicked-button {\n  height: 23px;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  border: none;\n  background-color: aquamarine;\n  border-radius: 2px;\n  margin-right: 4px;\n  flex: 1 0 0;\n  white-space: nowrap;\n}\n\n\n.plate-setup-canvas-container {\n  top: 52px;\n  left: 16px;\n  right: 16px;\n  bottom: 10px;\n  position: absolute;\n}\n\n.plate-setup-tab-container {\n  position: absolute;\n  top:10px;\n  left:10px;\n  bottom: 10px;\n  right: 10px;\n  background-color: white;\n  border: solid 1px #e1e1e1;\n}\n\n.plate-setup-tab-head {\n  left: 0;\n  right: 0;\n  height: 23px;\n  border-bottom: solid 1px #e1e1e1;\n  background-color: #f5f5f5;\n  display: flex;\n}\n\n.plate-setup-tab {\n  height: 23px;\n  background-color: #ebebeb;\n  border-right: solid 1px #e1e1e1;\n  cursor: pointer;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 10px;\n  text-align: center;\n  padding: 5px;\n  box-sizing: border-box;\n  flex: 1 1 auto;\n  white-space: nowrap;\n  overflow: hidden;\n}\n\n.plate-setup-tab:last-child {\n  border-right: none;\n}\n\n.plate-setup-tab-selected {\n  height: 24px;\n  background-color: white;\n  color: #00506e;\n  flex-shrink: 0;\n}\n\n.plate-setup-tab-data-container {\n  left: 0;\n  right: 0;\n  height: 442px;\n  border-bottom: solid 1px #e1e1e1;\n  position: absolute;\n  font-family: \"Roboto\", Arial, sans-serif;\n}\n\n.plate-setup-data-div {\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  position: absolute;\n  background-color: white;\n  overflow: auto;\n}\n\n.plate-setup-well-attr-container {\n  top: 472px;\n  left: 0;\n  right: 0;\n  height: 20px;\n  box-sizing: border-box;\n  padding: 0px 16px;\n  color: #00506e;\n  text-align: center;\n  position: absolute;\n  font-size: 10px;\n  font-family: \"Roboto\", Arial, sans-serif;\n}\n\n.plate-setup-preset-container {\n  top: 490px;\n  left: 0;\n  right: 0;\n  height: 22px;\n  position: absolute;\n  box-sizing: border-box;\n  padding: 0px 16px;\n  text-align: center;\n  display: flex;\n  justify-content: center;\n}\n\n.plate-setup-prest-tab {\n  display: inline-block;\n  flex-basis: 50px;\n  padding: 0 5px;\n  margin: 0 1px;\n  height: 20px;\n  background-color: white;\n  border: solid 1px #e1e1e1;\n  border-radius: 2px;\n  cursor: pointer;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 10px;\n  text-align: center;\n}\n\n.plate-setup-prest-tab-selected {\n  display: inline-block;\n  flex-basis: 50px;\n  padding: 0 5px;\n  margin: 0 1px;\n  height: 20px;\n  background-color: #e1e1e1;\n  border: solid 1px #e1e1e1;\n  border-radius: 2px;\n  cursor: pointer;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 11px;\n  text-align: center;\n  color: #00506e;\n}\n\n.plate-setup-prest-tab-div {\n  padding-top: 3px;\n}\n\n.plate-setup-tab-default-field {\n  display: flex;\n  padding: 10px 16px 0 16px;\n}\n\n.plate-setup-tab-field-left-side {\n  width: 32px;\n  padding-top: 16px;\n}\n\n.plate-setup-tab-field-right-side {\n  flex: 1;\n}\n\n.plate-setup-tab-name {\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  display: inline-block;\n  line-height: 16px;\n}\n\n.plate-setup-tab-name-singleSelect {\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  margin-top: 5px;\n}\n\n\n.plate-setup-tab-name-missing {\n  height: 20px;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  background: red;\n}\n\n\n.plate-setup-tab-field-container, .plate-setup-tab-field-container-singleSelect {\n  width: 100%;\n  display: flex;\n}\n\n.plate-setup-tab-input, .plate-setup-tab-select-field, .plate-setup-tab-multiplex-single-select-field {\n  height: 28px;\n  flex: 1 1 auto;\n  width: 30px;\n  margin: auto;\n}\n\n.plate-setup-tab-multiselect-field {\n  min-height: 28px;\n  flex: 1 1 auto;\n  width: 30px;\n}\n\n.plate-setup-tab-label-select-field, .plate-setup-tab-unit {\n  width: 130px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  height: 28px;\n  box-sizing: border-box;\n  padding-left: 5px;\n}\n\n.plate-setup-tab-unit {\n  font-family: \"Roboto\", Arial, sans-serif;\n  line-height: 26px;\n  color: #444;\n  white-space: nowrap;\n}\n\n.plate-setup-tab-check-box {\n  cursor: pointer;\n  border: 1px solid gray;\n  display: inline-block;\n  height: 16px;\n  width: 16px;\n  text-align: center;\n  line-height: 16px;\n}\n\n.plate-setup-bottom-control-container {\n  top: 0;\n  left: 0;\n  right: 0;\n  height: 32px;\n  background-color: #464646;\n  position: absolute;\n  display: flex;\n  justify-content:space-between;\n  align-items: baseline;\n  vertical-align: middle;\n}\n\n.plate-setup-bottom-container {\n  top: 540px;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  position: absolute;\n  background-color: #e1e1e1;\n}\n\n.plate-setup-bottom-table-container {\n  top: 32px;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  position: absolute;\n  overflow: auto;\n}\n\n\n.plate-setup-bottom-table {\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 14px;\n  border-collapse: collapse;\n  width: 100%;\n}\n\n.plate-setup-bottom-table th {\n  border: solid #c2c2c2 1px;\n  padding: 5px 10px;\n  font-weight: bold;\n  font-size: 12px;\n  text-align: left;\n}\n\n.plate-setup-bottom-table td {\n  border: solid #c2c2c2 1px;\n  padding: 5px 10px;\n  background-color: white;\n}\n\n.plate-setup-color-text {\n  font-size: 14px;\n  border: none;\n  border-radius: 2px;\n  padding: 3px 15px;\n  background-color: WHITE;\n  margin-right: 4px;\n}\n\n.plate-setup-bottom-id {\n  width: 40px;\n  text-align: center;\n  background-image: linear-gradient(to right, rgba(255,255,255,0.3), transparent)\n}\n\ninput.invalid {\n  background-color: pink;\n}\n\n.plate-setup-remove-all-button-container {\n  text-align: left;\n}\n\n.plate-setup-remove-all-button{\n  width: 100%;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  text-overflow: ellipsis;\n  text-align: left;\n  white-space: nowrap;\n  border: 1px solid #aaa;\n  border-top: none;\n  color: #444;\n  background-color: #fff;\n  background-image: linear-gradient(to top, #eee 0%, #fff 50%);\n}\n/* Modal Content */\n\n.modal {\n  display: none; /* Hidden by default */\n  position: fixed; /* Stay in place */\n  z-index: 2000; /* Sit on top */\n  padding-top: 100px; /* Location of the box */\n  left: 0;\n  top: 0;\n  width: 100%; /* Full width */\n  height: 100%; /* Full height */\n  overflow: auto; /* Enable scroll if needed */\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */\n}\n\n.modal-content {\n  font-family: 'Roboto', sans-serif;\n  font-size: 14px;\n  background-color: #fefefe;\n  margin: auto;\n  padding: 20px;\n  border: 1px solid #888;\n}\n\n.delete-dialog .modal-content {\n  width: 550px;\n}\n\n.modal-content > * {\n  width: 100%;\n}\n\n.dialog-buttons {\n  margin-top: 10px;\n  display: inline-block;\n  text-align: right;\n}\n\n.dialog-buttons button {\n  margin-left: 4px;\n}\n\n.plate-popout-table {\n  border-collapse: collapse;\n  width: 100%;\n  border: 1px solid black;\n  padding: 5px;\n}\n\n.plate-popout-th {\n  text-align: left;\n  background-color: white;\n  color: black;\n  font-size: 12px;\n  border: 1px solid black;\n  padding: 5px;\n}\n\n.plate-popout-tr:hover {\n  background-color: #f5f5f5;\n  border: 1px solid black;\n  padding: 5px;\n}\n\n.plate-popout-td {\n  text-align: left;\n  font-size: 11px;\n  border: 1px solid black;\n  padding: 5px;\n}\n\n.plate-field-warning-image{\n  vertical-align: baseline;\n  margin: 0px 0 0px;\n}\n\n.pop-out-text {\n  position: fixed;\n  display: none;\n  background: white;\n  border: 1px solid;\n  float: left;\n  margin-top: -44px;\n  z-Index: 99999 !important;\n}\n"]}
\ No newline at end of file
diff --git a/dist/js/plate-map.js b/dist/js/plate-map.js
deleted file mode 100755
index 8ab5e1c..0000000
--- a/dist/js/plate-map.js
+++ /dev/null
@@ -1,4360 +0,0 @@
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.addDataOnChange = function() {
-    // This object is invoked when something in the tab fields change
-    return {
-
-      _addAllData: function(data) {
-        // Method to add data when something changes in the tabs. Its going to be tricky , just starting.
-        if (this.allSelectedObjects) {
-          var noOfSelectedObjects = this.allSelectedObjects.length;
-          var wells = [];
-          for (var objectIndex = 0; objectIndex < noOfSelectedObjects; objectIndex++) {
-            var tile = this.allSelectedObjects[objectIndex];
-            var well;
-            if (tile.index in this.engine.derivative) {
-              well = this.engine.derivative[tile.index];
-            } else {
-              well = $.extend(true, {}, this.defaultWell); 
-              this.engine.derivative[tile.index] = well; 
-            }
-            var processedData = this.processWellData(data, well, noOfSelectedObjects, wells);
-            wells = processedData.wells;
-            well = processedData.well;
-            var empty = this.engine.wellEmpty(well);
-            if (empty) {
-              if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {
-                var wellCopy = JSON.parse(JSON.stringify(well));
-                var defaultValue = this.emptyWellWithDefaultVal;
-                for (var key in defaultValue){
-                  if (key in wellCopy){
-                    wellCopy[key] = defaultValue[key];
-                    this._applyFieldData(key, defaultValue[key]);
-                  }
-                }
-                this.engine.derivative[tile.index] = wellCopy;
-              } else {
-                delete this.engine.derivative[tile.index];
-              }
-            }
-          }
-        }
-        // update multiplex remove all field
-        this._getAllMultipleVal(wells);
-        this.applyFieldWarning(wells);
-        // create well when default field is sent for the cases when user delete all fields during disabledNewDeleteWell mode
-        this._colorMixer();
-        this.derivativeChange();
-      },
-
-      processWellData: function(newData, curWell, noOfSelectedObjects, wellList) {
-
-        if (!wellList){
-          wellList = [];
-        }
-        for (var id in newData) {
-          var v;
-          if (newData[id] !== undefined && newData[id] !== null ) {
-            if (newData[id].multi){
-              var curData = newData[id];
-              var preData = curWell[id];
-              var newDt = this._getMultiData(preData, curData, id, noOfSelectedObjects);
-              // need to replace newData
-              v = JSON.parse(JSON.stringify(newDt));
-            } else {
-              v = JSON.parse(JSON.stringify(newData[id]));
-            }
-          } else {
-            v = JSON.parse(JSON.stringify(newData[id]));
-          }
-          curWell[id] = v;
-          wellList.push(curWell);
-        }
-
-        return {
-          well: curWell,
-          wells: wellList
-        }
-      },
-
-      _getMultiData: function(preData, curData, fieldId, noOfSelectedObjects) {
-        var addNew = curData.added;
-        var removed = curData.removed;
-        if (addNew) {
-          if (preData){
-            if (addNew.value) {
-              var add = true;
-              for (var listIdx in preData) {
-                var multiplexData = preData[listIdx];
-                // for cases when the add new data exist in well
-                if (multiplexData[fieldId].toString() === addNew.id.toString()) {
-                  add = false;
-                  // update subfield value
-                  preData = preData.map(function(val) {
-                    if (val[fieldId].toString() === addNew.id.toString()) {
-                      for (var subFieldId in val) {
-                        // over write previous data if only one well is selected
-                        if (subFieldId in addNew.value && subFieldId !== fieldId){
-                          if (noOfSelectedObjects === 1) {
-                            val[subFieldId] = addNew.value[subFieldId];
-                          } else if (addNew.value[subFieldId]) {
-                            val[subFieldId] = addNew.value[subFieldId];
-                          }
-                        }
-                      }
-                    }
-                    return val;
-                  })
-                }
-              }
-              if (add) {
-                preData.push(addNew.value);
-              }
-            } else if (preData.indexOf(addNew) < 0) {
-              preData.push(addNew);
-            }
-          } else {
-            preData = [];
-            if (addNew.value) {
-              preData.push(addNew.value);
-            } else if (addNew){
-              preData.push(addNew);
-            }
-          }
-        }
-
-        var removeListIndex = function(preData, removeIndex) {
-          var newPreData = [];
-          for (var idx in preData) {
-            if (parseInt(idx) !== parseInt(removeIndex)){
-              newPreData.push(preData[idx]);
-            }
-          }
-          return newPreData;
-        };
-
-        if (removed) {
-          var removeIndex;
-          // for multiplex field
-          if (removed.value) {
-            for (var listIdx in preData) {
-              var multiplexData = preData[listIdx];
-              if (multiplexData[fieldId].toString() === removed.id.toString()) {
-                removeIndex = listIdx;
-              }
-            }
-            // remove nested element
-            preData = removeListIndex(preData, removeIndex);
-          } else {
-            if (preData){
-              removeIndex = preData.indexOf(removed);
-              if (removeIndex >= 0) {
-                preData = removeListIndex(preData, removeIndex);
-              }
-            }
-          }
-        }
-        if (preData && (preData.length == 0)) {
-          preData = null; 
-        }
-        return preData
-      },
-
-      _colorMixer: function() {
-        if (!this.undoRedoActive) {
-            var data = this.createObject();
-            this.addToUndoRedo(data);
-        }
-        this.engine.searchAndStack(); 
-        this.engine.applyColors();
-        this.mainFabricCanvas.renderAll();
-      },
-
-      derivativeChange: function(){
-          this._trigger("updateWells", null, this.createObject());
-      },
-
-      createObject: function() {
-        var derivative = $.extend(true, {}, this.engine.derivative); 
-        var checkboxes = this.globalSelectedAttributes.slice(); 
-        var selectedAreas = this.selectedAreas.slice(); 
-        var focalWell = this.focalWell;
-
-        return {
-          "derivative": derivative,
-          "checkboxes": checkboxes,
-          "selectedAreas": selectedAreas,
-          "focalWell": focalWell,
-          "requiredField": this.requiredField
-        };
-      }
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.addDataToFields = function() {
-
-    return {
-
-      _addDataToTabFields: function(values) {
-        // Configure how data is added to tab fields
-        for (var id in values) {
-          this._applyFieldData(id, values[id]);
-        }
-      },
-
-      _applyFieldData: function(id, v) {
-        this.fieldMap[id].setValue(v); 
-      }
-    }
-  }
-})(jQuery, fabric)
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.addTabData = function() {
-
-    return {
-
-      fieldList: [], 
-      fieldMap: {},
-      autoId: 1,
-
-      _addTabData: function() {
-          // Here we may need more changes because attributes format likely to change
-          var tabData = this.options.attributes.tabs;
-          var that = this;
-          this.requiredField = [];
-          var multiplexFieldArray = [];
-          tabData.forEach(function (tab, tabPointer) {
-            if (tab["fields"]) {
-              var tabFields = tab["fields"];
-              var fieldArray = [];
-              var fieldArrayIndex = 0;
-              // Now we look for fields in the json
-              for (var field in tabFields) {
-                var data = tabFields[field];
-
-                if (!data.id) {
-                  data.id = "Auto" + that.autoId++;
-                  console.log("Field autoassigned id " + data.id);
-                }
-                if (!data.type) {
-                  data.type = "text";
-                  console.log("Field " + data.id + " autoassigned type " + data.type);
-                }
-
-                var field_val;
-                if (data.type === "multiplex") {
-                  field_val = that._makeMultiplexField(data, tabPointer, fieldArray);
-                  multiplexFieldArray.push(field_val);
-                } else {
-                  field_val = that._makeRegularField(data, tabPointer, fieldArray, true);
-                  if (data.type === "multiselect") {
-                    multiplexFieldArray.push(field_val);
-                  }
-                };
-              }
-
-              that.allDataTabs[tabPointer]["fields"] = fieldArray;
-            } else {
-              console.log("unknown format in field initialization");
-            }
-          });
-          that.multipleFieldList = multiplexFieldArray;
-      },
-
-      _makeSubField: function (data, tabPointer, fieldArray) {
-        var that = this;
-        if (!data.id) {
-          data.id = "Auto" + that.autoId++;
-          console.log("Field autoassigned id " + data.id);
-        }
-        if (!data.type) {
-          data.type = "text";
-          console.log("Field " + data.id + " autoassigned type " + data.type);
-        }
-        var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
-        var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
-        var wrapperDivRightSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-right-side");
-        var nameContainer = that._createElement("<div></div>").addClass("plate-setup-tab-name").text(data.name);
-        var fieldContainer = that._createElement("<div></div>").addClass("plate-setup-tab-field-container");
-
-        $(wrapperDivRightSide).append(nameContainer);
-        $(wrapperDivRightSide).append(fieldContainer);
-        $(wrapperDiv).append(wrapperDivLeftSide);
-        $(wrapperDiv).append(wrapperDivRightSide);
-        $(that.allDataTabs[tabPointer]).append(wrapperDiv);
-
-        var field = {
-          id: data.id,
-          name: data.name,
-          root: wrapperDiv,
-          data: data,
-          required: data.required || false
-        };
-
-        fieldArray.push(field);
-        that.fieldMap[data.id] = field;
-
-        return field;
-      },
-
-      _makeRegularField: function (data, tabPointer, fieldArray, checkbox){
-          var that = this;
-          var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
-          var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
-          var wrapperDivRightSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-right-side ");
-          var nameContainer = that._createElement("<div></div>").addClass("plate-setup-tab-name").text(data.name);
-          var fieldContainer = that._createElement("<div></div>").addClass("plate-setup-tab-field-container");
-
-          wrapperDivRightSide.append(nameContainer);
-          wrapperDivRightSide.append(fieldContainer);
-          wrapperDiv.append(wrapperDivLeftSide);
-          wrapperDiv.append(wrapperDivRightSide);
-          that.allDataTabs[tabPointer].append(wrapperDiv);
-
-          var field = {
-            id: data.id,
-            name: data.name,
-            root: wrapperDiv,
-            data: data,
-            required: data.required
-          };
-
-          if (field.required) {
-            that.requiredField.push(field.id);
-          }
-
-          fieldArray.push(field);
-          that.fieldList.push(field);
-          that.fieldMap[field.id] = field;
-
-          // Adding checkbox
-          if (checkbox) {
-            that._addCheckBox(field);
-          }
-          that._createField(field);
-
-          field.onChange = function () {
-            var v = field.getValue();
-            var data = {};
-            data[field.id] = v;
-            that._addAllData(data);
-          };
-          return field;
-      },
-
-      _makeMultiplexField: function (data, tabPointer, fieldArray) {
-        var that = this;
-        var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
-        var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
-        var wrapperDivRightSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-right-side ");
-        var nameContainer = that._createElement("<div></div>").addClass("plate-setup-tab-name").text(data.name);
-        var fieldContainer = that._createElement("<div></div>").addClass("plate-setup-tab-field-container");
-
-        wrapperDivRightSide.append(nameContainer);
-        wrapperDivRightSide.append(fieldContainer);
-        wrapperDiv.append(wrapperDivLeftSide);
-        wrapperDiv.append(wrapperDivRightSide);
-        that.allDataTabs[tabPointer].append(wrapperDiv);
-
-        var field = {
-          id: data.id,
-          name: data.name,
-          root: wrapperDiv,
-          data: data,
-          required: data.required
-        };
-
-        fieldArray.push(field);
-        that.fieldList.push(field);
-        that.fieldMap[data.id] = field;
-
-        var subFieldList = [];
-        //create subfields
-        var requiredSubField = [];
-        for (var subFieldKey in data.multiplexFields) {
-          var subFieldData = data.multiplexFields[subFieldKey];
-          var subField = that._makeSubField(subFieldData, tabPointer, fieldArray);
-          subFieldList.push(subField);
-
-          // stores required  subField
-          if (subFieldData.required) {
-            requiredSubField.push(subField.id);
-          }
-        }
-
-        //store required field
-        if (field.required || requiredSubField.length) {
-          this.requiredField.push ({
-            multiplexId: field.id,
-            subFields: requiredSubField
-          });
-        }
-
-        field.subFieldList = subFieldList;
-        that._createField(field);
-        that._addCheckBox(field);
-
-        subFieldList.forEach(function (subfield) {
-          subfield.mainMultiplexField = field;
-          fieldArray.push(subfield);
-          that._createField(subfield);
-          that._addCheckBox(subfield);
-          delete that.defaultWell[subfield.id];
-          // overwrite subField setvalue
-          subfield.onChange = function () {
-            var v = subfield.getValue();
-            var mainRefField = subfield.mainMultiplexField;
-            var curId = mainRefField.singleSelectValue();
-            //var curDataLs = mainRefField.detailData;
-            var curVal = {};
-            curVal[mainRefField.id] = curId;
-            //append subfields
-            curVal[subfield.id] = v;
-            var returnVal = {
-              id: curId,
-              value: curVal
-            };
-
-            field._changeMultiFieldValue(returnVal, null);
-            var curDataLs = mainRefField.detailData;
-            if (curDataLs !== null) {
-              curId = mainRefField.singleSelectValue(); 
-              curDataLs = curDataLs.map(function(curData) {
-                if (curData[mainRefField.id] === curId) {
-                  curData[subfield.id] = v;
-                }
-                return curData;
-              });
-            }
-            mainRefField.detailData = curDataLs;
-          };
-
-        });
-
-        field.getValue = function(){
-          var v = field.input.select2('data');
-          if (v.length) {
-            return v.map(function (i) {
-              return i.id;
-            });
-          }
-          return null;
-        };
-
-        return field;
-      }
-    }
-  }
-
-})(jQuery, fabric);
-
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.addWarningMsg = function () {
-    // For those check boxes associated with every field in the tab
-    return {
-      fieldWarningMsg: function (field, text, include) {
-        var that = this;
-        var imgId = "fieldWarning" + field.id;
-        var img = $("<span>").html(that._assets.warningImg).attr("id", imgId).addClass("plate-field-warning-image");
-        //field.root.find(".plate-setup-tab-name").append('<img id="theImg" src="theImg.png" />')
-        if (include) {
-          if (field.root.find("#" + imgId).length <= 0){
-            field.root.find(".plate-setup-tab-name").text(" " + field.name);
-            field.root.find(".plate-setup-tab-name").prepend(img);
-
-            var popText = $("<div/>").addClass("pop-out-text");
-            popText.text(text);
-            field.root.find(".plate-setup-tab-name").append(popText);
-
-            $("#" + imgId).hover(function (e) {
-              popText[0].style.display = 'flex';
-            }, function () {
-              popText.hide();
-            });
-          }
-
-
-        } else {
-          if (field.root.find("#" + imgId).length > 0) {
-            field.root.find(".plate-setup-tab-name").text(field.name);
-            $("#" + imgId).remove();
-          }
-        }
-      },
-
-      removeWarningMsg: function (field, text, include) {
-        var that = this;
-        var imgId = "fieldWarning" + field.id;
-        var img = $("<span>").html(that._assets.warningImg).attr("id", imgId).addClass("plate-field-warning-image");
-        //field.root.find(".plate-setup-tab-name").append('<img id="theImg" src="theImg.png" />')
-        if (include) {
-          field.root.find(".plate-setup-tab-name").append(img);
-
-          var popText = $("<div/>").addClass("pop-out-text");
-          popText.text(text);
-          field.root.find(".plate-setup-tab-name").append(popText);
-
-          $("#" + imgId).hover(function (e) {
-            popText[0].style.display = 'inline-block';
-          }, function () {
-            popText.hide();
-          });
-
-        } else {
-          $("#" + imgId).remove();
-          if (field.root.find("#" + imgId).length > 0) {
-            //field.root.find(".plate-setup-tab-name").remove(img);
-            $("#" + imgId).remove();
-          }
-        }
-      },
-
-      applyFieldWarning: function(wells) {
-        var that = this;
-        var req = 0;
-        var fill = 0;
-        var fieldData = {};
-        that.fieldList.forEach(function(field){
-          fieldData[field.id] = [];
-        });
-        wells.forEach(function(well){
-          if (!that.engine.wellEmpty(well)){
-            for (var fieldId in fieldData) {
-              if (fieldId in well) {
-                fieldData[fieldId].push(well[fieldId]);
-              } else {
-                fieldData[fieldId].push(null);
-              }
-            }
-          }
-        });
-        for (var i = 0; i < that.fieldList.length; i++) {
-          var field = that.fieldList[i];
-          if (field.applyMultiplexSubFieldColor){
-            field.applyMultiplexSubFieldColor(fieldData[field.id]);
-          } else {
-            if (field.required) {
-              var include = false;
-              fieldData[field.id].forEach(function(val){
-                // for multiselect
-                if (val instanceof Array) {
-                  if (val.length === 0) {
-                    include = true;
-                  }
-                } else {
-                  if (val === null) {
-                    include = true;
-                  }
-                }
-              });
-              //field.root.find(".plate-setup-tab-name").css("background", color);
-              that.fieldWarningMsg(field, "required field", include);
-            }
-          }
-        }
-      }
-    }
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.bottomTable = function() {
-    // for bottom table
-    return {
-      _bottomScreen: function() {
-        this.bottomContainer = this._createElement("<div></div>").addClass("plate-setup-bottom-container");
-        this.bottomTableContainer = this._createElement("<div></div>").addClass("plate-setup-bottom-table-container");
-        this.bottomTable = this._createElement("<table></table>").addClass("plate-setup-bottom-table");
-        this.bottomTableContainer.append(this.bottomTable);
-        this.bottomContainer.append(this.bottomTableContainer);
-        this.container.append(this.bottomContainer);
-      },
-
-      addBottomTableHeadings: function() {
-
-        this.bottomRow = this._createElement("<tr></tr>");
-
-        var singleField = this._createElement("<th></th>")
-          .text("Group");
-        this.bottomRow.prepend(singleField);
-        // Now we append all the captions at the place.
-        this.bottomTable.empty();
-        this.bottomTable.append(this.bottomRow);
-
-        this.rowCounter = 1;
-
-        for (var i = 0; i < this.globalSelectedAttributes.length; i++) {
-          var attr = this.globalSelectedAttributes[i];
-          var field = this.fieldMap[attr];
-          var singleField = this._createElement("<th></th>").text(field.name);
-          this.bottomRow.append(singleField);
-          this.rowCounter = this.rowCounter + 1;
-        }
-
-        this.adjustFieldWidth(this.bottomRow);
-      },
-
-      tileAttrText: function(tile, attr) {
-        var well = this.engine.derivative[tile.index];
-        var field = this.fieldMap[attr];
-        return field.getText(well[attr]);
-      },
-
-      addBottomTableRow: function(color, singleStack) {
-        var that = this;
-        var modelTile = this.allTiles[singleStack[0]];
-        var row = this._createElement("<tr></tr>");
-        var plateIdDiv = this._createElement("<td></td>").addClass("plate-setup-bottom-id");
-        var numberText = this._createElement("<button/>");
-        numberText.addClass("plate-setup-color-text");
-        numberText.text(color);
-        plateIdDiv.append(numberText);
-
-        numberText.click(function(evt){
-          var addressToSelect = singleStack.map(function(addressIdx){
-            return that.indexToAddress(addressIdx)
-          });
-          if (evt.ctrlKey) {
-            that.getSelectedAddress().forEach(function(val){
-              if (addressToSelect.indexOf(val) < 0){
-                addressToSelect.push(val);
-              }
-            })
-          }
-          that.setSelectedWell(addressToSelect);
-          that._trigger("selectedWells", null, {selectedAddress: that.getSelectedAddress()});
-        });
-
-        if (color > 0) {
-          color = ((color - 1) % (this.colorPairs.length - 1)) + 1;
-        }
-        var colorStops = this.colorPairs[color];
-
-        plateIdDiv.css("background", "linear-gradient(to right, " + colorStops[0] + " , " + colorStops[1] + ")");
-
-        row.append(plateIdDiv);
-
-        for (var i = 0; i < this.globalSelectedAttributes.length; i++) {
-          var attr = this.globalSelectedAttributes[i];
-          var text = this.tileAttrText(modelTile, attr);
-          var dataDiv = this._createElement("<td></td>").text(text);
-          row.append(dataDiv);
-        }
-        this.bottomTable.append(row);
-        this.adjustFieldWidth(row);
-      },
-
-      bottomForFirstTime: function() {
-        this.addBottomTableHeadings();
-        // This is executed for the very first time.. !
-        var row = this._createElement("<tr></tr>");
-
-        var colorStops = this.colorPairs[0];
-        var plateIdDiv = this._createElement("<td></td>");
-        plateIdDiv.css("background", "-webkit-linear-gradient(left, " + colorStops[0] + " , " + colorStops[1] + ")");
-        row.append(plateIdDiv);
-        this.bottomTable.append(row);
-        this.createExportButton();
-      },
-
-      adjustFieldWidth: function(row) {
-
-        var length = this.rowCounter;
-        if ((length) * 150 > 1024) {
-          row.css("width", (length) * 152 + "px");
-        }
-      },
-
-      downloadCSV: function(csv, filename) {
-        var csvFile;
-        var downloadLink;
-
-        // CSV file
-        csvFile = new Blob([csv], {
-          type: "text/csv"
-        });
-
-        // Download link
-        downloadLink = document.createElement("a");
-
-        // File name
-        downloadLink.download = filename;
-
-        // Create a link to the file
-        downloadLink.href = window.URL.createObjectURL(csvFile);
-
-        // Hide download link
-        downloadLink.style.display = "none";
-
-        // Add the link to DOM
-        document.body.appendChild(downloadLink);
-
-        // Click download link
-        downloadLink.click();
-      },
-
-      exportData: function(format) {
-        var data = [];
-        var rows = document.querySelectorAll("table tr");
-
-        var colorLocMap = {};
-        var colorLocIdxMap = this.engine.stackUpWithColor;
-        var dim = this.getDimensions();
-        var that = this;
-        for (var colorIdx in colorLocIdxMap) {
-          colorLocMap[colorIdx] = colorLocIdxMap[colorIdx].map(function (locIdx) {
-            return that.indexToAddress(locIdx, dim);
-          })
-        }
-
-        for (var i = 0; i < rows.length; i++) {
-          var row = [],
-            cols = rows[i].querySelectorAll("td, th");
-
-          for (var j = 0; j < cols.length; j++) {
-            var v = "";
-            if (cols[j].innerText) {
-              if (format === "csv") {
-                v = '"' + cols[j].innerText.replace(/"/g, '""') + '"';
-              } else {
-                v = cols[j].innerText;
-              }
-            }
-            row.push(v);
-
-            // add location column
-            if (i === 0 && j === 0) {
-              if (format === "csv") {
-                row.push('"Location"');
-              } else if (format === 'clipboard') {
-                row.push("Location");
-              }
-
-            }
-            if (i !== 0 && j === 0) {
-              var loc = '';
-              if (colorLocMap[parseInt(cols[j].innerText)]) {
-                if (format === "csv") {
-                  loc = '"' + colorLocMap[parseInt(cols[j].innerText)].join(",") + '"';
-                } else if (format === 'clipboard') {
-                  loc = colorLocMap[parseInt(cols[j].innerText)].join(",");
-                }
-              }
-              row.push(loc);
-            }
-          }
-
-          if (format === "csv") {
-            data.push(row.join(","));
-          } else if (format === 'clipboard') {
-            data.push(row.join("\t"));
-            //data.push(row);   // for text type
-          }
-
-        }
-        if (format === "csv") {
-          // Download CSV file
-          this.downloadCSV(data.join("\n"), 'table.csv');
-        } else if (format === 'clipboard') {
-          //return formatTableToString(data);   // for text type
-          return data.join("\n");
-        }
-      },
-
-      createExportButton: function() {
-        var that = this;
-        var overlayContainer = $("<div>").addClass("plate-setup-bottom-control-container");
-
-        var descriptionDiv = $("<div>").addClass("plate-setup-overlay-text-container");
-        descriptionDiv.text("Color groups");
-        overlayContainer.append(descriptionDiv);
-
-        var buttonContainer = $("<div>").addClass("plate-setup-overlay-bottom-button-container");
-
-        // create export csv option
-        var exportButton = $("<button/>").addClass("plate-setup-button");
-        exportButton.text("Export CSV");
-        buttonContainer.append(exportButton);
-
-        exportButton.click(function() {
-          that.exportData('csv');
-          exportButton.text("Exported");
-          exportButton[0].classList.remove("plate-setup-button");
-          exportButton.addClass("plate-setup-clicked-button");
-          setTimeout(resetExportText, 3000);
-        });
-
-        function resetExportText() {
-          exportButton.text("Export CSV");
-          exportButton[0].classList.remove("plate-setup-clicked-button");
-          exportButton.addClass("plate-setup-button");
-        }
-
-        // creat clipboard option, CLipboard is an external js file located in vendor/asset/javascripts
-        var clipboardButton = $("<button/>").addClass("plate-setup-button");
-        clipboardButton.text("Copy To Clipboard");
-        buttonContainer.append(clipboardButton);
-
-        var clipboard = new ClipboardJS(clipboardButton.get(0), {
-          text: function() {
-            return that.exportData("clipboard");
-          }
-        });
-
-        clipboard.on('success', function(e) {
-          clipboardButton.text("Copied as tab-delimited format");
-          clipboardButton[0].classList.remove("plate-setup-button");
-          clipboardButton.addClass("plate-setup-clicked-button");
-          setTimeout(resetClipboardText, 3000);
-        });
-
-        function resetClipboardText() {
-          clipboardButton.text("Copy To Clipboard");
-          clipboardButton[0].classList.remove("plate-setup-clicked-button");
-          clipboardButton.addClass("plate-setup-button");
-        }
-
-        clipboard.on('error', function(e) {
-          clipboardButton.text("Failed to copy table to clipboard: browser may be incompatible");
-          setTimeout(resetClipboardText, 3000);
-        });
-
-        overlayContainer.append(buttonContainer);
-        $(".plate-setup-bottom-container").prepend(overlayContainer);
-      }
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.canvas = function() {
-    //
-    return {
-
-      allSelectedObjects: null, // Contains all the selected objets, when click and drag.
-
-      allPreviouslySelectedObjects: null,
-
-      colorPointer: 0,
-
-      goldenRatio: 0.618033988749895,
-
-      _createCanvas: function() {
-        this.normalCanvas = this._createElement("<canvas>").attr("id", "DNAcanvas");
-        $(this.canvasContainer).append(this.normalCanvas);
-      },
-
-      _initiateFabricCanvas: function() {
-        var w = this.canvasContainer.width(); 
-        var h = this.canvasContainer.height(); 
-
-        this._setCanvasArea(w, h);
-
-        this.mainFabricCanvas = new fabric.Canvas('DNAcanvas', {
-            backgroundColor: '#f5f5f5',
-            selection: false,
-            stateful: false,
-            hoverCursor: "pointer",
-            renderOnAddRemove: false,
-          })
-          .setWidth(w)
-          .setHeight(h);
-      },
-
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.checkBox = function() {
-    // For those check boxes associated with every field in the tab
-    return {
-
-      globalSelectedAttributes: [],
-
-      _addCheckBox: function(field) {
-        var checkImage = $("<span>").html(this._assets.dontImg).addClass("plate-setup-tab-check-box bg-light")
-          .data("clicked", false);
-        checkImage.data("linkedFieldId", field.id);
-        field.root.find(".plate-setup-tab-field-left-side").empty().append(checkImage);
-        this._applyCheckboxHandler(checkImage); // Adding handler for change the image when clicked
-        field.checkbox = checkImage;
-      },
-
-      _applyCheckboxHandler: function(checkBoxImage) {
-        // We add checkbox handler here, thing is it s not checkbox , its an image and we change
-        // source
-        var that = this;
-        checkBoxImage.click(function(evt, machineClick) {
-          var checkBox = $(this);
-
-          var changes = {};
-          changes[checkBox.data("linkedFieldId")] = !checkBox.data("clicked");
-
-          that.changeCheckboxes(changes);
-        });
-      },
-
-      changeSubFieldsCheckboxes: function(field, changes) {
-        var that = this;
-        var subFieldToInclude = [];
-
-        field.subFieldList.forEach(function(subField) {
-          var checkImage = subField.checkbox;
-          var fieldId = checkImage.data("linkedFieldId");
-          var clicked = checkImage.data("clicked");
-          if (fieldId in changes) {
-            clicked = Boolean(changes[fieldId]);
-          }
-          checkImage.data("clicked", clicked);
-          if (clicked) {
-            checkImage.html(that._assets.doImg);
-            subFieldToInclude.push(subField.id);
-          } else {
-            checkImage.html(that._assets.dontImg);
-          }
-        });
-        return subFieldToInclude;
-      },
-
-      changeCheckboxes: function(changes) {
-        var gsa = [];
-        var multiplexCheckedSubField = {};
-        for (var i = 0; i < this.fieldList.length; i++) {
-          var field = this.fieldList[i];
-          if (field.checkbox) {
-            if (field.subFieldList) {
-              multiplexCheckedSubField[field.id] = this.changeSubFieldsCheckboxes(field, changes);
-            }
-
-            var checkImage = field.checkbox;
-            var fieldId = checkImage.data("linkedFieldId");
-            var clicked = checkImage.data("clicked");
-            if (fieldId in changes) {
-              clicked = Boolean(changes[fieldId]);
-            }
-            checkImage.data("clicked", clicked);
-            if (clicked) {
-              gsa.push(fieldId);
-              checkImage.html(this._assets.doImg);
-            } else {
-              checkImage.html(this._assets.dontImg);
-            }
-          }
-        }
-        this.globalSelectedMultiplexSubfield = multiplexCheckedSubField;
-        this.globalSelectedAttributes = gsa;
-        this._clearPresetSelection();
-        this._colorMixer();
-      },
-
-      setSubFieldCheckboxes: function(field, fieldIds) {
-        var that = this;
-        var subFieldToInclude = [];
-        field.subFieldList.forEach(function(subField) {
-          var checkImage = subField.checkbox;
-          var fieldId = checkImage.data("linkedFieldId");
-          var clicked = fieldIds.indexOf(fieldId) >= 0;
-          checkImage.data("clicked", clicked);
-          if (clicked) {
-            checkImage.html(that._assets.doImg);
-            subFieldToInclude.push(subField.id);
-          } else {
-            checkImage.html(that._assets.dontImg);
-          }
-        });
-        return subFieldToInclude;
-      },
-
-      setCheckboxes: function(fieldIds) {
-        fieldIds = fieldIds || [];
-        var gsa = [];
-        var multiplexCheckedSubField = {};
-
-        for (var i = 0; i < this.fieldList.length; i++) {
-          var field = this.fieldList[i];
-          if (field.checkbox) {
-            // special handling for multiplex field
-            if (field.subFieldList) {
-              multiplexCheckedSubField[field.id] = this.setSubFieldCheckboxes(field, fieldIds);
-            }
-
-            var checkImage = field.checkbox;
-            var fieldId = checkImage.data("linkedFieldId");
-            var clicked = fieldIds.indexOf(fieldId) >= 0;
-            checkImage.data("clicked", clicked);
-            if (clicked) {
-              gsa.push(fieldId);
-              checkImage.html(this._assets.doImg);
-            } else {
-
-              checkImage.html(this._assets.dontImg);
-            }
-          }
-        }
-        this.globalSelectedMultiplexSubfield = multiplexCheckedSubField;
-        this.globalSelectedAttributes = gsa;
-        this._clearPresetSelection();
-        this._colorMixer();
-      }
-
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.colorManager = function() {
-
-    return {
-        // See these are color pairs for the gradient.
-      colorPairs: [
-        ["#e6e6e6", "#808080"],
-        ["#66e8ff", "#0082c8"],
-        ["#ff7fb1", "#e6194b"],
-        ["#a2ffb1", "#3cb44b"],
-        ["#f784ff", "#911eb4"],
-        ["#ffe897", "#f58231"],
-        ["#6666ff", "#0000FF"],
-        ["#ffff7f", "#ffe119"],
-        ["#acffff", "#46f0f0"],
-        ["#ff98ff", "#f032e6"],
-        ["#ffffa2", "#d2f53c"],
-        ["#ffffff", "#fabebe"],
-        ["#66e6e6", "#008080"],
-        ["#ffffff", "#e6beff"],
-        ["#ffd48e", "#aa6e28"],
-        ["#e66666", "#800000"],
-        ["#ffffff", "#aaffc3"],
-        ["#e6e666", "#808000"],
-        ["#ffffff", "#ffd8b1"],
-        ["#66a9ef", "#004389"],
-        ["#ff6672", "#a7000c"],
-        ["#66db72", "#00750c"],
-        ["#b866db", "#520075"],
-        ["#ffa966", "#b64300"],
-        ["#ffff66", "#c0a200"],
-        ["#6dffff", "#07b1b1"],
-        ["#ff66ff", "#b100a7"],
-        ["#f9ff66", "#93b600"],
-        ["#ffe5e5", "#bb7f7f"],
-        ["#66a7a7", "#004141"],
-        ["#ffe5ff", "#a77fc0"],
-        ["#d19566", "#6b2f00"],
-        ["#ffffef", "#c0bb89"],
-        ["#d1ffea", "#6bc084"],
-        ["#a7a766", "#414100"],
-        ["#ffffd8", "#c09972"],
-        ["#a5ffff", "#3fc1ff"],
-        ["#ffbef0", "#ff588a"],
-        ["#e1fff0", "#7bf38a"],
-        ["#ffc3ff", "#d05df3"],
-        ["#ffffd6", "#ffc170"],
-        ["#a5a5ff", "#3f3fff"],
-        ["#ffffbe", "#ffff58"],
-        ["#ebffff", "#85ffff"],
-        ["#ffd7ff", "#ff71ff"],
-        ["#a5ffff", "#3fbfbf"],
-        ["#ffffcd", "#e9ad67"],
-        ["#ffa5a5", "#bf3f3f"],
-        ["#ffffa5", "#bfbf3f"]
-      ]
-    }
-  }
-
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.createCanvasElements = function() {
-    // this class manages creating all the elements within canvas
-    return {
-
-      scaleFactor: 1, 
-
-      baseSizes: {
-        spacing: 48, 
-        tile_radius: 22, 
-        center_radius_complete: 10, 
-        center_radius_incomplete: 14, 
-        label_size: 14, 
-        label_spacing: 24, 
-        text_size: 13,
-        stroke: 0.5, 
-        gap: 2
-      }, 
-
-      _setCanvasArea: function(w, h) {
-        this.scaleFactor = Math.min(
-           h / (this.dimensions.rows * this.baseSizes.spacing + this.baseSizes.label_spacing), 
-           w / (this.dimensions.cols * this.baseSizes.spacing + this.baseSizes.label_spacing));
-
-        var sizes = {}
-        for (var prop in this.baseSizes) {
-          sizes[prop] = this.baseSizes[prop] * this.scaleFactor; 
-        }
-        this.sizes = sizes; 
-      }, 
-
-      _canvas: function() {
-        // Those 1,2,3 s and A,B,C s
-        this._fixRowAndColumn();
-
-        // All those circles in the canvas.
-        this._putCircles();
-      },
-
-      _fixRowAndColumn: function() {
-        var cols = this.dimensions.cols;
-        var rows = this.dimensions.rows;
-
-        var spacing = this.sizes.spacing;
-        var d1 = this.sizes.label_spacing / 2;
-        var d2 = this.sizes.label_spacing + this.sizes.spacing / 2; 
-        var fontSize = this.sizes.label_size; 
-
-        // For column
-        var top = d1; 
-        var left = d2;  
-        for (var i = 1; i <= cols; i++) {
-          var tempFabricText = new fabric.IText(i.toString(), {
-            fill: 'black',
-            originX: 'center',
-            originY: 'center',
-            fontSize: fontSize,
-            top: top,
-            left: left,
-            fontFamily: '"Roboto", Arial, sans-serif',
-            selectable: false,
-            fontWeight: "400"
-          });
-          left += spacing; 
-
-          this.mainFabricCanvas.add(tempFabricText);
-        }
-
-        // for row
-        top = d2; 
-        left = d1; 
-        for (var i = 1; i <= rows; i++) {
-          var tempFabricText = new fabric.IText(this.rowIndex[i-1], {
-            fill: 'black',
-            originX: 'center',
-            originY: 'center',
-            fontSize: fontSize,
-            top: top,
-            left: left,
-            fontFamily: '"Roboto", Arial, sans-serif',
-            selectable: false,
-            fontWeight: "400"
-          });
-          top += spacing; 
-
-          this.mainFabricCanvas.add(tempFabricText);
-        }
-      },
-
-      _putCircles: function() {
-        var cols = this.dimensions.cols;
-        var rows = this.dimensions.rows;
-
-        var tileCounter = 0;
-        for (var row = 0; row < rows; row++) {
-          for (var col = 0; col < cols; col++) {
-            var index = this.allTiles.length; 
-            var tile = this._createTile(row, col); 
-            tile.index = tileCounter++; 
-            this.allTiles.push(tile);
-            this.mainFabricCanvas.add(tile.background);
-            this.mainFabricCanvas.add(tile.highlight);
-            this.mainFabricCanvas.add(tile.circle);
-            this.mainFabricCanvas.add(tile.circleCenter);
-            this.mainFabricCanvas.add(tile.circleText);
-          }
-        }
-
-        this._addLargeRectangleOverlay();
-        this._fabricEvents();
-      },
-
-      _createTile: function (row, col) {
-        var tile = {}; 
-
-        tile.visible = false; 
-        tile.colorIndex = null; 
-        tile.row = row; 
-        tile.col = col; 
-        tile.address = this.rowIndex[row] + (col + 1); 
-
-        var top = (row + 1) * this.sizes.spacing;
-        var left = (col + 1) * this.sizes.spacing; 
-
-        tile.background = new fabric.Circle({
-          top: top,
-          left: left,
-          radius: this.sizes.tile_radius,
-          originX: 'center',
-          originY: 'center',
-          hasControls: false,
-          hasBorders: false,
-          lockMovementX: true,
-          lockMovementY: true,
-          evented: false,
-        });
-
-        tile.background.setGradient("fill", {
-          type: "radial",
-          x1: this.sizes.tile_radius, 
-          x2: this.sizes.tile_radius, 
-          y1: this.sizes.tile_radius + this.sizes.gap,
-          y2: this.sizes.tile_radius + this.sizes.gap,
-          r1: this.sizes.tile_radius - this.sizes.gap,
-          r2: this.sizes.tile_radius,
-          colorStops: {
-            0: 'rgba(0,0,0,0.1)',
-            1: 'rgba(0,0,0,0.2)'
-          }
-        });
-
-        tile.highlight = new fabric.Rect({
-          originX: 'center',
-          originY: 'center',
-          top: top,
-          left: left,
-          width: this.sizes.spacing,
-          height: this.sizes.spacing,
-          fill: "rgba(0,0,0,0.4)",
-          evented: false,
-          visible: false
-        });
-
-        tile.circle = new fabric.Circle({
-          originX: 'center',
-          originY: 'center',
-          top: top,
-          left: left,
-          radius: this.sizes.tile_radius,
-          stroke: 'gray',
-          strokeWidth: this.sizes.stroke,
-          evented: false, 
-          visible: false
-        });
-
-        tile.circleCenter = new fabric.Circle({
-          originX: 'center',
-          originY: 'center',
-          top: top,
-          left: left,
-          radius: this.sizes.center_radius_incomplete,
-          fill: "white",
-          stroke: 'gray',
-          strokeWidth: this.sizes.stroke,
-          evented: false,
-          visible: false
-        });
-
-        tile.circleText = new fabric.IText("", {
-          originX: 'center',
-          originY: 'center',
-          top: top,
-          left: left,
-          fill: 'black',
-          fontFamily: '"Roboto", Arial, sans-serif',
-          fontSize: this.sizes.text_size,
-          lockScalingX: true,
-          lockScalingY: true,
-          evented: false,
-          visible: false
-        });
-
-        return tile; 
-      }, 
-
-      setTileComplete: function (tile, complete) {
-        if (complete) {
-          tile.circleCenter.radius = this.sizes.center_radius_complete;
-          tile.circleText.fill = "black";
-          tile.circleText.fontWeight = 'normal';
-        } else {
-          tile.circleCenter.radius = this.sizes.center_radius_incomplete;
-          tile.circleText.fill = "red";
-          tile.circleText.fontWeight = 'bold';
-        }
-      }, 
-
-      setTileVisible: function (tile, visible) {
-        tile.visible = visible;
-        tile.circle.visible = tile.visible;
-        tile.circleCenter.visible = tile.visible;
-        tile.circleText.visible = tile.visible;
-      },
-
-      setTileColor: function(tile, color, stackPointer) {
-        this.setTileVisible(tile, true);
-        tile.colorIndex = parseInt(color); 
-        tile.circleText.text = String(tile.colorIndex);
-
-        if (color > 0) {
-          color = ((color - 1) % (this.colorPairs.length -1)) + 1;
-        }
-        var colorStops = this.colorPairs[color];
-
-        tile.circle.setGradient("fill", {
-          y2: 2 * this.sizes.tile_radius,
-          colorStops: colorStops
-        });
-      },
-
-      _addLargeRectangleOverlay: function() {
-
-        this.overLay = new fabric.Rect({
-          width: 632,
-          height: 482,
-          left: 0,
-          top: 0,
-          opacity: 0.0,
-          originX: 'left',
-          originY: 'top',
-          lockMovementY: true,
-          lockMovementX: true,
-          selectable: false
-        });
-
-        this.mainFabricCanvas.add(this.overLay);
-      }
-    };
-  }
-})(jQuery, fabric);
-
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.createField = function() {
-    // It create those fields in the tab , there is 4 types of them.
-    return {
-
-      _createField: function(field) {
-        switch (field.data.type) {
-          case "text":
-            this._createTextField(field);
-            break;
-
-          case "numeric":
-            this._createNumericField(field);
-            break;
-
-          case "select":
-            this._createSelectField(field);
-            break;
-
-          case "multiselect":
-            this._createMultiSelectField(field);
-            break;
-
-          case "boolean":
-            this._createBooleanField(field);
-            break;
-
-          case "multiplex":
-            this._createMultiplexField(field);
-            break;
-        }
-      },
-
-      _createTextField: function(field) {
-        var id = field.id;
-        var that = this;
-        var input = this._createElement("<input>").attr("id", id)
-          .addClass("plate-setup-tab-input");
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        that.defaultWell[id] = null;
-
-        field.parseValue = function(v) {
-          if (v) {
-            v = String(v);
-          } else {
-            v = null;
-          }
-          return v;
-        };
-
-        field.getValue = function() {
-          var v = input.val().trim();
-          if (v == "") {
-            v = null;
-          }
-          return v;
-        };
-
-        field.setValue = function(v) {
-          input.val(v);
-        };
-
-        field.getText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          return v;
-        };
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-        };
-
-        field.parseText = field.parseValue;
-
-        input.on("input", function(e, generated) {
-          field.onChange();
-        });
-
-        field.input = input;
-      },
-
-      _createOpts: function(config) {
-        var opts = {
-          allowClear: true,
-          placeholder: "select",
-          minimumResultsForSearch: 10
-        };
-
-        if (config.options) {
-          opts.data = config.options;
-        } else if (config.query) {
-          var query = config.query;
-          if (config.delay) {
-            query = this._debounce(config.delay, query);
-          }
-          opts.query = query;
-        } else {
-          throw "Must specify data or query";
-        }
-        return opts;
-      },
-
-      _createSelectField: function(field) {
-        var id = field.id;
-        var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
-          .addClass("plate-setup-tab-select-field");
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        that.defaultWell[id] = null;
-
-        var opts = that._createOpts(field.data);
-        var optMap = {};
-        opts.data.forEach(function(opt) {
-          optMap[opt.id] = opt;
-        });
-
-        input.select2(opts);
-
-        field.parseValue = function(value) {
-          var v = value;
-
-          if (v == "") {
-            v = null;
-          }
-          if (v == null) {
-            return null;
-          }
-          if (v in optMap) {
-            return optMap[v].id;
-          } else {
-            throw "Invalid value " + value + " for select field " + id;
-          }
-        };
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-        };
-
-        field.getValue = function() {
-          var v = input.select2('data');
-          return v ? v.id : null;
-        };
-
-        field.setValue = function(v) {
-          if (v) {
-            v = optMap[v];
-          }
-          input.select2('data', v);
-        };
-
-        field.setOpts = function(v) {
-          input.select2('data', {});
-          opts.data = v || [];
-          input.select2(opts);
-        };
-
-        field.getText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          return optMap[v].text;
-        };
-
-        field.parseText = function(value) {
-          var v = value;
-
-          if (v == "") {
-            v = null;
-          }
-          if (v == null) {
-            return null;
-          }
-          if (v in optMap) {
-            return optMap[v].text;
-          } else {
-            throw "Invalid text value " + value + " for select field " + id;
-          }
-        };
-
-        input.on("change", function(e, generated) {
-          field.onChange();
-        });
-
-        field.input = input;
-      },
-
-      _createMultiSelectField: function(field) {
-        var id = field.id;
-        var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
-          .addClass("plate-setup-tab-multiselect-field");
-        input.attr("multiple", "multiple");
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        that.defaultWell[id] = null;
-
-        var separator = ",";
-        var opts = that._createOpts(field.data);
-        opts.multiple = true;
-        var optMap = {};
-        opts.data.forEach(function(opt) {
-          optMap[opt.id] = opt;
-        });
-        input.select2(opts);
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-        };
-
-        field.parseValue = function(value) {
-          var v = value;
-          if (v && v.length) {
-            v = v.map(function(opt) {
-              if (opt in optMap) {
-                return optMap[opt].id;
-              } else {
-                throw "Invalid value " + opt + " for multiselect field " + id;
-              }
-            });
-          } else {
-            v = null;
-          }
-          return v;
-        };
-
-        field.setOpts = function(v) {
-          var allOpts = field.data.options;
-          var selectedVal = [];
-          for (var id in allOpts) {
-            var curOpts = allOpts[id];
-            if (v.indexOf(curOpts["id"]) >= 0) {
-              selectedVal.push(curOpts);
-            }
-          }
-
-          opts.data = selectedVal;
-          input.select2(opts);
-        };
-
-        field.getValue = function() {
-          var v = input.select2('data');
-          if (v.length) {
-            return v.map(function(i) {
-              return i.id;
-            });
-          }
-          return null;
-        };
-
-        field.setValue = function(v) {
-          v = v || [];
-          v = v.map(function(i) {
-            return optMap[i];
-          });
-          input.select2('data', v);
-        };
-
-        field.getText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          if (v.length > 0) {
-            return v.map(function(v) {
-              return optMap[v].text
-            }).join("; ");
-          }
-          return "";
-        };
-
-        field.multiOnChange = function (added, removed) {
-          if (added) {
-            added = added.id.toString();
-          }
-          if (removed) {
-            removed = removed.id.toString();
-          }
-          var data = {
-          };
-          data[field.id] = {
-            multi: true,
-            added: added,
-            removed: removed
-          };
-
-          that._addAllData(data);
-        };
-
-        field.parseText = function(value){
-          var v = value;
-          if (v && v.length) {
-            v = v.map(function(opt) {
-              if (opt in optMap) {
-                return optMap[opt].text;
-              } else {
-                throw "Invalid text value " + opt + " for multiselect field " + id;
-              }
-            });
-          } else {
-            v = null;
-          }
-          return v;
-        };
-
-        input.on("change", function(e, generated) {
-          var added = e.added;
-          var removed = e.removed;
-          //field.onChange();
-          field.multiOnChange(added, removed);
-        });
-
-        field.input = input;
-
-        that._createDeleteButton(field);
-      },
-
-      _createNumericField: function(field) {
-        var id = field.id;
-        var data = field.data;
-        var that = this;
-        var input = this._createElement("<input>").addClass("plate-setup-tab-input")
-          .attr("placeholder", data.placeholder || "").attr("id", id);
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        that.defaultWell[id] = null;
-
-        // Adding unit
-        var units = data.units || [];
-        var defaultUnit = data.defaultUnit || null;
-        var unitInput = null;
-        if (defaultUnit) {
-          if (units.length) {
-            if (units.indexOf(defaultUnit) < 0) {
-              defaultUnit = units[0];
-            }
-          } else {
-            units = [defaultUnit];
-          }
-        } else {
-          if (units.length) {
-            defaultUnit = units[0];
-          }
-        }
-
-        if (units.length) {
-          field.units = units;
-          field.hasUnits = true;
-          field.defaultUnit = defaultUnit;
-          if (units.length == 1) {
-            var unitText = $("<div></div>").addClass("plate-setup-tab-unit");
-            unitText.text(defaultUnit);
-            field.root.find(".plate-setup-tab-field-container").append(unitText);
-          } else {
-            unitInput = this._createElement("<input/>").attr("id", id)
-              .addClass("plate-setup-tab-label-select-field");
-
-            field.root.find(".plate-setup-tab-field-container").append(unitInput);
-
-            var selected = null;
-            var unitData = units.map(function(unit) {
-              var o = {
-                id: unit,
-                text: unit
-              };
-              if (unit == defaultUnit) {
-                selected = o;
-              }
-              return o;
-            });
-
-            var opts = {
-              data: unitData,
-              allowClear: false,
-              minimumResultsForSearch: 10
-            };
-
-            unitInput.select2(opts);
-            unitInput.select2("data", selected);
-          }
-        }
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-          if (unitInput) {
-            unitInput.prop("disabled", bool);
-          }
-        };
-
-        field.setUnitOpts = function(opts) {
-          field.units = opts || null;
-          field.defaultUnit = null;
-
-          var newUnits = [];
-          var selected = null;
-          if (field.units && field.units.length) {
-            field.defaultUnit = field.units[0];
-            newUnits = field.units.map(function(curUnit) {
-              var cleanUnit = {
-                id: curUnit,
-                text: curUnit
-              };
-              if (curUnit == field.defaultUnit) {
-                selected = cleanUnit;
-              }
-              return cleanUnit;
-            });
-          }
-
-          var newOpts = {
-            data: newUnits,
-            allowClear: false,
-            minimumResultsForSearch: 10
-          };
-          unitInput.select2(newOpts);
-          unitInput.select2("data", selected);
-        };
-
-        field.parseValue = function(value) {
-          var v;
-          if ($.isPlainObject(value)) {
-            if (field.hasUnits) {
-              v = field.parseRegularValue(value.value);
-              if (v === null) {
-                return null;
-              }
-              return {
-                value: v,
-                unit: field.parseUnit(value.unit)
-              };
-            } else {
-              throw "Value must be plain numeric for numeric field " + id;
-            }
-          } else {
-            if (field.hasUnits) {
-              v = field.parseRegularValue(value);
-              if (v === null) {
-                return null;
-              }
-              return {
-                value: v,
-                unit: field.defaultUnit
-              };
-            } else {
-              return field.parseRegularValue(value);
-            }
-          }
-        };
-
-        field.getValue = function() {
-          var v = field.getRegularValue();
-
-          if ((v === null) || isNaN(v)) {
-            return null;
-          } else if (field.hasUnits) {
-            var returnVal = {
-              value: v,
-              unit: field.getUnit()
-            };
-
-            if (field.data.hasMultiplexUnit) {
-              // include unitTypeId and UnitId to returnVal
-              for (var unitTypeKey in field.data.unitMap) {
-                var unitTypeUnits = field.data.unitMap[unitTypeKey];
-                unitTypeUnits.forEach(function(unit) {
-                  if (unit.text === returnVal.unit) {
-                    returnVal['unitTypeId'] = unitTypeKey;
-                    returnVal['unitId'] = unit.id;
-                  }
-                })
-              }
-            }
-            return returnVal;
-          } else {
-            return v;
-          }
-        };
-
-        field.setValue = function(value) {
-          if (field.hasUnits) {
-            if ($.isPlainObject(value)) {
-              field.setUnit(value.unit || field.defaultUnit);
-              field.setRegularValue(value.value);
-
-            } else {
-              field.setRegularValue(value);
-              field.setUnit(field.defaultUnit)
-            }
-          } else {
-            field.setRegularValue(value);
-          }
-        };
-
-        field.parseRegularValue = function(value) {
-          if (value == null) {
-            return null;
-          }
-          var v = String(value).trim();
-          if (v === "") {
-            return null;
-          }
-          v = Number(value);
-          if (isNaN(v)) {
-            throw "Invalid value " + value + " for numeric field " + id;
-          }
-          return v;
-        };
-
-        field.getRegularValue = function() {
-          var v = input.val().trim();
-          if (v == "") {
-            v = null;
-          } else {
-            v = Number(v);
-          }
-          return v;
-        };
-
-        field.setRegularValue = function(value) {
-          input.val(value);
-        };
-
-        field.parseUnit = function(unit) {
-          if (unit == null || unit === "") {
-            return field.defaultUnit;
-          }
-          for (var i = 0; i < units.length; i++) {
-            if (unit.toLowerCase() == units[i].toLowerCase()) {
-              return units[i];
-            }
-          }
-          throw "Invalid unit " + unit + " for field " + id;
-        };
-
-        field.getUnit = function() {
-          if (unitInput) {
-            return unitInput.val();
-          } else {
-            return field.defaultUnit;
-          }
-        };
-
-        field.setUnit = function(unit) {
-          if (unitInput) {
-            unit = unit || field.defaultUnit;
-            if (unit != null) {
-              unit = {
-                id: unit,
-                text: unit
-              };
-            }
-            unitInput.select2("data", unit);
-          }
-        };
-
-        // val now contains unit
-        field.getText = function(val) {
-          if (typeof(val) === 'object' && val) {
-            var v = val.value;
-            var u = val.unit;
-            if (v == null) {
-              return "";
-            }
-            v = v.toString();
-            if (!u) {
-              u = defaultUnit;
-            }
-            if (u) {
-              v = v + " " + u;
-            }
-            return v;
-          } else {
-            return field.getRegularText(val);
-          }
-        };
-
-        field.getRegularText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          v = v.toString();
-          return v;
-        };
-
-        field.parseText = function(v){
-          var textVal = field.parseValue(v);
-          if (textVal && typeof(textVal) === "object"){
-            return textVal.value + textVal.unit;
-          } else if (textVal) {
-            return textVal
-          } else {
-            return null;
-          }
-        };
-
-        input.on("input", function() {
-          var v = field.getRegularValue();
-          if (isNaN(v)) {
-            //flag field as invalid
-            input.addClass("invalid");
-          } else {
-            input.removeClass("invalid");
-          }
-          field.onChange();
-        });
-        if (unitInput) {
-          unitInput.on("change", function() {
-            field.onChange();
-          });
-        }
-
-        field.input = input;
-        field.unitInput = unitInput;
-      },
-
-      _createBooleanField: function(field) {
-        var id = field.id;
-        var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
-          .addClass("plate-setup-tab-select-field");
-        that.defaultWell[id] = null;
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        var tval = {
-          id: "true",
-          text: "true"
-        };
-        var fval = {
-          id: "false",
-          text: "false"
-        };
-        var opts = {
-          data: [tval, fval],
-          placeholder: "select",
-          allowClear: true,
-          minimumResultsForSearch: -1,
-          initSelection: function(element, callback) {
-            var v = element.val();
-            callback({
-              id: v,
-              text: v
-            });
-          }
-        };
-
-        input.select2(opts);
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-        };
-
-        field.parseValue = function(value) {
-          if (value == null) {
-            return null;
-          }
-          var v = String(value).trim().toLowerCase();
-          if (v == "true") {
-            v = true;
-          } else if (v == "false") {
-            v = false;
-          } else if (v == "") {
-            v = null;
-          } else {
-            throw "Invalid value " + value + " for boolean field " + id;
-          }
-          return v;
-        };
-
-        field.getValue = function() {
-          var v = input.val();
-          switch (v) {
-            case "true":
-              return true;
-            case "false":
-              return false;
-            default:
-              return null;
-          }
-        };
-
-        field.setValue = function(v) {
-          if (v == true || v == "true") {
-            v = tval;
-          } else if (v == false || v == "false") {
-            v = fval;
-          } else {
-            v = null;
-          }
-          input.select2('data', v);
-        };
-
-        field.getText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          return v.toString();
-        };
-
-        field.parseText = field.parseValue;
-
-        input.on("change", function(e) {
-          field.onChange();
-        });
-
-        field.input = input;
-      },
-
-      _createMultiplexField: function(field) {
-        var that = this;
-        // make correct multiplex data
-        this._createMultiSelectField(field);
-        // overwrite default well for multiplex field
-        that.defaultWell[field.id] = [];
-
-        // single select
-        var nameContainer1 = that._createElement("<div></div>").addClass("plate-setup-tab-name-singleSelect").text("Select to edit");
-        var fieldContainer1 = that._createElement("<div></div>").addClass("plate-setup-tab-field-container-singleSelect");
-        field.root.find(".plate-setup-tab-field-right-side").append(nameContainer1, fieldContainer1);
-
-        field.singleSelect = this._createElement("<input/>").attr("id", field.id + "SingleSelect")
-          .addClass("plate-setup-tab-multiplex-single-select-field");
-
-        field.singleSelect.appendTo(fieldContainer1);
-
-        field.singleSelectValue = function () {
-          var v = field.singleSelect.select2("data");
-          if (v != null) {
-            v = v.id;
-          }
-          return v;
-        };
-
-        var setSingleSelectOptions = function (v, selected_v) {
-          var opts = {
-            allowClear: false,
-            placeholder: "select",
-            minimumResultsForSearch: 10,
-            data: v || []
-          }
-          if (!selected_v) {
-            if (opts.data.length) {
-              selected_v = opts.data[0];
-            } else {
-              selected_v = null;
-            }
-          }
-          field.singleSelect.select2('data', []);
-          field.singleSelect.select2(opts);
-          field.singleSelect.select2('data', selected_v);
-          field.singleSelect.prop("disabled", opts.data.length == 0);
-        };
-
-        var singleSelectChange = function () {
-          var v = field.singleSelectValue();
-
-          field.updateSubFieldUnitOpts(v);
-
-          var curData = field.detailData || [];
-          var curSubField = null;
-          curData.forEach(function(val) {
-            if (val[field.id] === v) {
-              curSubField = val;
-            }
-          });
-
-          if (curSubField) {
-            // setvalue for subfield
-            field.subFieldList.forEach(function(subField) {
-              subField.disabled(false);
-              subField.setValue(curSubField[subField.id]);
-            });
-          } else {
-            field.subFieldList.forEach(function(subField) {
-              subField.disabled(true);
-              subField.setValue(null);
-            });
-          }
-          that.readOnlyHandler();
-        };
-
-        setSingleSelectOptions([]);
-
-        field.singleSelect.on("change", singleSelectChange);
-
-        field._changeMultiFieldValue = function(added, removed) {
-          var newSubFieldValue = {};
-          for (var subFieldName in field.data.multiplexFields) {
-            var subFieldId = field.data.multiplexFields[subFieldName].id;
-            newSubFieldValue[subFieldId] = null;
-          }
-
-          var val;
-          if (added) {
-            if (added.value) {
-              val = added.value;
-            } else {
-              newSubFieldValue[field.id] = added.id;
-              val = newSubFieldValue;
-            }
-            added = {
-              id: added.id,
-              value: val
-            };
-          }
-
-          if (removed) {
-            if (removed.value){
-              val = removed.value;
-            } else {
-              newSubFieldValue[field.id] = removed.id;
-              val = newSubFieldValue;
-            }
-            removed = {
-              id: removed.id,
-              value: val
-            };
-          }
-
-          var data = {};
-          data[field.id] = {
-            multi: true,
-            added: added,
-            removed: removed
-          };
-          that._addAllData(data);
-        };
-
-        var multiselectSetValue = field.setValue;
-
-        // overwrite multiplex set value
-        field.setValue = function(v) {
-          // used to keep track of initially loaded multiplex data
-          field.detailData = v;
-          var multiselectValues = null;
-          if (v && v.length) {
-            multiselectValues = v.map(function(val) {
-              return val[field.id]
-            });
-          }
-
-          multiselectSetValue(multiselectValues);
-          var newOptions = field.input.select2('data') || [];
-          setSingleSelectOptions(newOptions);
-          singleSelectChange();
-        };
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-          field.subFieldList.forEach(function(subField) {
-            subField.disabled(bool);
-          });
-          if (bool) {
-            nameContainer1.text("Select to inspect");
-          } else {
-            nameContainer1.text("Select to edit");
-          }
-        };
-
-        field.parseValue = function(value) {
-          var v = value;
-          if (v && v.length) {
-            v = v.map(function(opt) {
-              var valMap = {};
-              valMap[field.id] = opt[field.id];
-              for (var subFieldId in opt) {
-                field.subFieldList.forEach(function(subField) {
-                  if (subField.id === subFieldId) {
-                    valMap[subField.id] = subField.parseValue(opt[subFieldId]);
-                  }
-                });
-              }
-              return valMap;
-            });
-          } else {
-            v = null;
-          }
-          return v;
-        };
-
-        field.updateSubFieldUnitOpts = function(val) {
-          var curOpts;
-          field.data.options.forEach(function(opt) {
-            if (opt.id === val) {
-              curOpts = opt;
-            }
-          });
-          field.subFieldList.forEach(function(subField) {
-            if (subField.data.hasMultiplexUnit) {
-              if (curOpts && curOpts.hasOwnProperty("unitOptions")) {
-								subField.setUnitOpts(curOpts.unitOptions[subField.id]);
-              } else {
-                subField.setUnitOpts(null);
-              }
-            }
-          })
-        };
-
-        field.multiOnChange = function(added, removed) {
-          field._changeMultiFieldValue(added, removed);
-          var v = field.getValue();
-          var curData = field.detailData;
-          var curIds = [];
-          var curOpt = null;
-          //reshape data for saveback
-          if (curData) {
-            curIds = curData.map(function(val) {
-              return val[field.id]
-            });
-          }
-
-          var newMultiplexVal = [];
-          var selectList = [];
-          if (v) {
-            v.forEach(function(selectedVal) {
-              if (curData) {
-                curData.forEach(function(val) {
-                  if (val[field.id] === selectedVal) {
-                    newMultiplexVal.push(val)
-                  }
-                });
-              }
-              // cases when adding new data
-              if (curIds.indexOf(selectedVal) < 0) {
-                var newVal = {};
-                newVal[field.id] = selectedVal;
-
-                field.updateSubFieldUnitOpts(selectedVal);
-                field.subFieldList.forEach(function(subfield) {
-                  // special handling for subfield which has multiplexUnit
-                  if (subfield.hasUnits) {
-                    if (subfield.data.hasMultiplexUnit) {
-                      subfield.disabled(false);
-                      field.data.options.forEach(function(opt) {
-                        if (opt.id === selectedVal) {
-                          var val = {
-                            value: null,
-                            unit: subfield.units[0]
-                          };
-                          newVal[subfield.id] = subfield.parseValue(val);
-                        }
-                      });
-                    } else {
-                      if (subfield.data.units) {
-                        if (subfield.data.units.length > 1){
-                          subfield.disabled(false);
-                        }
-                      }
-                      var val = {
-                        value: null,
-                        unit: subfield.defaultUnit
-                      };
-                      newVal[subfield.id] = subfield.parseValue(val);
-                    }
-                  }
-                   else {
-                    newVal[subfield.id] = subfield.parseValue(null);
-                  }
-                });
-                newMultiplexVal.push(newVal);
-              }
-            });
-
-            // make data for single select options
-            v.forEach(function(selectId) {
-              field.data.options.forEach(function(opt) {
-                if (opt.id === selectId) {
-                  selectList.push(opt);
-                }
-              });
-            });
-            // set the newest selected to be the current obj
-            curOpt = selectList[v.length - 1];
-          }
-
-          field.detailData = newMultiplexVal;
-          setSingleSelectOptions(selectList, curOpt);
-          singleSelectChange();
-        };
-
-        field.getText = function(v) {
-          if (v === null) {
-            return "";
-          }
-          // get subfields that is selected from the checkbox
-          if (field.id in that.globalSelectedMultiplexSubfield) {
-            var checkedSubfields = that.globalSelectedMultiplexSubfield[field.id];
-            var returnVal = [];
-            for (var valIdx in v) {
-              var subV = v[valIdx];
-              var subText = [];
-              for (var optId in field.data.options) {
-                var opt = field.data.options[optId];
-                if (opt.id === subV[field.id]) {
-                  subText.push(opt.text);
-                }
-              }
-              field.subFieldList.forEach(function(subField) {
-                if (checkedSubfields.indexOf(subField.id) >= 0) {
-                  var x = subField.getText(subV[subField.id]);
-                  subText.push(subField.name + ": " + x);
-                }
-              });
-              returnVal.push("{" + subText.join(", ") + "}");
-            }
-            return returnVal.join(";");
-          }
-        };
-
-        field.parseText = function(v) {
-          if (v === null) {
-            return "";
-          } else {
-            var returnVal = [];
-            for (var valIdx in v) {
-              var subV = v[valIdx];
-              var subText = [];
-              for (var optId in field.data.options) {
-                var opt = field.data.options[optId];
-                if (opt.id === subV[field.id]) {
-                  subText.push(opt.text);
-                }
-              }
-              field.subFieldList.forEach(function(subField) {
-                var x = subField.getText(subV[subField.id]);
-                if (x) {
-                  subText.push(x);
-                }
-              });
-              returnVal.push(subText);
-            }
-            return returnVal;
-          }
-        };
-
-        field.checkMultiplexCompletion = function(valList) {
-          var valCount = 0;
-          var completionPct = 0;
-          var include = false;
-          function getSubfieldStatus (vals) {
-            var req = 0;
-            var fill = 0;
-            for (var subFieldId in field.subFieldList) {
-              var subField = field.subFieldList[subFieldId];
-              var curVal = vals[subField.id];
-              if (subField.required) {
-                include = true;
-                req++;
-                if (typeof(curVal) === 'object' && curVal) {
-                  if (curVal.value) {
-                    fill++;
-                  }
-                } else if (curVal) {
-                  fill++;
-                }
-              }
-            }
-            return fill/req;
-          }
-
-          // for cases has value in multiplex field
-          if (valList) {
-            if (valList.length > 0){
-              for (var idx in valList) {
-                valCount++;
-                var vals = valList[idx];
-                completionPct += getSubfieldStatus(vals);
-              }
-            } else if (field.required) {
-              include = true;
-              valCount = 1;
-            }
-          }  else if (field.required) {
-            include = true;
-            valCount = 1;
-          }
-
-          return {
-            include: include,
-            completionPct: completionPct/valCount
-          };
-        };
-
-        // valList contains all of the vals for selected val
-        field.applyMultiplexSubFieldColor = function(valList){
-          function updateSubFieldWarningMap (vals) {
-            for (var subFieldId in field.subFieldList) {
-              var subField = field.subFieldList[subFieldId];
-              // loop through each well's multiplexval list
-              if (vals === null){
-                if (field.required && subField.required){
-                  subFieldWarningMap[subField.id].warningStatus.push(true);
-                }
-              } else if (typeof(vals) === "object") {
-                if (vals.length === 0) {
-                  if (field.required && subField.required){
-                    subFieldWarningMap[subField.id].warningStatus.push(true);
-                  }
-                } else {
-                  for (var multiplexIdx in vals) {
-                    var curVal = vals[multiplexIdx][subField.id];
-                    if (subField.required) {
-                      if (typeof(curVal) === 'object' && curVal) {
-                        if (!curVal.value) {
-                          subFieldWarningMap[subField.id].warningStatus.push(true);
-                        } else {
-                          subFieldWarningMap[subField.id].warningStatus.push(false);
-                        }
-                      } else if (!curVal) {
-                        subFieldWarningMap[subField.id].warningStatus.push(true);
-                      } else {
-                        subFieldWarningMap[subField.id].warningStatus.push(false);
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-
-          var subFieldWarningMap = {};
-          field.subFieldList.forEach(function(subField){
-            if (subField.required) {
-              subFieldWarningMap[subField.id] = {
-                field: subField,
-                warningStatus: []
-              };
-            }
-          });
-
-          valList.forEach(function(multiplexVals) {
-            updateSubFieldWarningMap(multiplexVals);
-          });
-          // turn off main field when all subfield are filled
-
-          var requiredSubField = [];
-          var mainFieldStatus = [];
-          for (var subFieldId in subFieldWarningMap){
-            var subField = subFieldWarningMap[subFieldId].field;
-            if (subFieldWarningMap[subFieldId].warningStatus.indexOf(true) >= 0) {
-              var text =  subField.name + " is a required subfield for " + field.name + ", please make sure all " + field.name + " have " + subField.name;
-              if (field.required){
-                that.fieldWarningMsg(subField, text, true);
-                mainFieldStatus.push(true);
-              } else {
-                that.fieldWarningMsg(subField, text, true);
-                mainFieldStatus.push(true);
-              }
-            } else {
-              that.fieldWarningMsg(subField, "none", false);
-              mainFieldStatus.push(false);
-            }
-          }
-          var mainFieldWarning = false;
-          if (mainFieldStatus.indexOf(true) < 0) {
-            mainFieldWarning = false;
-          } else {
-            mainFieldWarning = true;
-          }
-          var warningText;
-          if (field.required) {
-            warningText = field.name + " is a required field, please also fix missing required subfield(s) below";
-          } else {
-            warningText = field.name + " is not a required field, please fix missing required subfield(s) below or remove selected " + field.name;
-          }
-          that.fieldWarningMsg(field, warningText, mainFieldWarning);
-        };
-
-        field.parseMainFieldVal = function(val) {
-          var optMap = field.data.options;
-          for (var idx = 0; idx < optMap.length; idx++){
-            var curOpt = optMap[idx];
-            if (curOpt.id === val){
-              return curOpt.text
-            }
-          }
-        };
-      },
-
-      _deleteDialog: function (field) {
-        var that = this;
-
-        var valMap = field.allSelectedMultipleVal;
-        var valToRemove;
-        if (valMap) {
-          valToRemove = Object.keys(valMap);
-        } else {
-          valToRemove = [];
-        }
-
-
-        var dialogDiv = $("<div/>").addClass("delete-dialog modal");
-        $('body').append(dialogDiv);
-
-        function killDialog() {
-          dialogDiv.hide();
-          dialogDiv.remove();
-        }
-
-        var dialogContent = $("<div/>").addClass("modal-content").appendTo(dialogDiv);
-        var tableArea = $("<div/>").appendTo(dialogContent);
-        var buttonRow = $("<div/>").addClass("dialog-buttons").css("justify-content", "flex-end").appendTo(dialogContent);
-
-        if (valToRemove.length > 0){
-          // apply CSS property for table
-          $("<p/>").text(field.name + " in selected wells: choose items to delete and click the delete button below").appendTo(tableArea);
-
-          var table = that._deleteDialogTable(field, valMap);
-          table.appendTo(tableArea);
-          table.addClass("plate-popout-table");
-          table.find('td').addClass("plate-popout-td");
-          table.find('th').addClass("plate-popout-th");
-          table.find('tr').addClass("plate-popout-tr");
-          if (!that.readOnly) {
-            var deleteCheckedButton = $("<button class='multiple-field-manage-delete-button'>Delete Checked Items</button>");
-            buttonRow.append(deleteCheckedButton);
-            deleteCheckedButton.click(function() {
-              table.find("input:checked").each(function () {
-                var val = this.value;
-                field.multiOnChange(null, {id: val});
-              });
-              // refresh selected fields after updating the multiplex field value
-              that.decideSelectedFields();
-              killDialog();
-            });
-          }
-
-        } else {
-          $("<p/>").text("No " + field.name + " in the selected wells").appendTo(tableArea);
-        }
-
-        var cancelButton = $("<button>Cancel</button>");
-        buttonRow.append(cancelButton);
-        cancelButton.click(killDialog);
-
-        dialogDiv.show();
-
-        window.onclick = function(event) {
-          if (event.target == dialogDiv[0]) {
-            killDialog();
-          }
-        }
-      },
-
-      _deleteDialogTable: function (field, valMap) {
-        var that = this;
-        var colName = [field.name, "Counts"]; //Added because it was missing... no idea what the original should have been
-        if (!that.readOnly) {
-          colName.push("Delete");
-        }
-        var table = $('<table/>');
-        var thead = $('<thead/>').appendTo(table);
-        var tr = $('<tr/>').appendTo(thead);
-
-        tr.append(colName.map(function (text) {
-          return $('<th/>').text(text);
-        }));
-
-        var tbody = $("<tbody/>").appendTo(table);
-
-        field.data.options.forEach(function (opt) {
-          if (opt.id in valMap) {
-            var tr = $('<tr/>').appendTo(tbody);
-            var checkbox = $("<input type='checkbox'>").prop("value", opt.id);
-            $("<td/>").text(opt.text).appendTo(tr);
-            $("<td/>").text(valMap[opt.id]).appendTo(tr);
-            if (!that.readOnly) {
-              $("<td/>").append(checkbox).appendTo(tr);
-            }
-          }
-        });
-
-        return table;
-      },
-
-      _createDeleteButton: function (field) {
-        var that = this;
-        var deleteButton = $("<button/>").addClass("plate-setup-remove-all-button");
-        deleteButton.id = field.id + "Delete";
-        deleteButton.text("Manage " + field.name + "...");
-        var buttonContainer = that._createElement("<div></div>").addClass("plate-setup-remove-all-button-container");
-        buttonContainer.append(deleteButton);
-
-        field.deleteButton = deleteButton;
-        field.root.find(".plate-setup-tab-field-right-side").append(buttonContainer);
-
-        deleteButton.click(function () {
-          that._deleteDialog(field);
-        });
-      }
-
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.engine = function(THIS) {
-    // Methods which look after data changes and stack up accordingly
-    // Remember THIS points to plateLayOutWidget and 'this' points to engine
-    // Use THIS to refer parent this.
-    return {
-      engine: {
-
-        derivative: {},
-        stackUpWithColor: {},
-        stackPointer: 2,
-
-        wellEmpty: function (well) {
-          for (var prop in well) {
-            var curVal = well[prop];
-            if (curVal !== null && curVal !== undefined) {
-              if (Array.isArray(curVal)) {
-                if (curVal.length > 0) {
-                  return false;
-                }
-              } else {
-                return false;
-              }
-            }
-          }
-          return true;
-        },
-
-        searchAndStack: function() {
-          // This method search and stack the change we made.
-          this.stackUpWithColor = {};
-          this.stackPointer = 1;
-          var derivativeJson = {};
-          for (var idx in this.derivative) {
-            var data = this.derivative[idx];
-            var wellData = {};
-            for (var i = 0; i < THIS.globalSelectedAttributes.length; i++) {
-              var attr = THIS.globalSelectedAttributes[i]; 
-
-              if (attr in THIS.globalSelectedMultiplexSubfield){
-                var selectedSubFields = THIS.globalSelectedMultiplexSubfield[attr];
-                var newMultiplexVal = [];
-                for (var multiplexIdx in data[attr]){
-                  var curMultiplexVals = data[attr][multiplexIdx];
-                  var newVal = {};
-                  newVal[attr] = curMultiplexVals[attr];
-                  selectedSubFields.forEach(function (subFieldId) {
-                    newVal[subFieldId] = curMultiplexVals[subFieldId];
-                  });
-                  newMultiplexVal.push(newVal);
-                }
-                wellData[attr] = newMultiplexVal;
-              } else {
-                if (data[attr] != null) {
-                  wellData[attr] = data[attr];
-                }
-              }
-            }
-            if ($.isEmptyObject(wellData)) {
-              derivativeJson[idx] = null; 
-            } else {
-              derivativeJson[idx] = JSON.stringify(wellData);
-            }
-          }
-
-          while (!$.isEmptyObject(derivativeJson)) {
-            var keys = Object.keys(derivativeJson).map(function (k) {return parseFloat(k, 10);});
-            keys.sort(function (a, b) {return a-b;}); 
-
-            var refDerivativeIndex = keys[0];
-            var referenceDerivative = derivativeJson[refDerivativeIndex];
-            var arr = [];
-
-            if (!referenceDerivative) {
-              // if no checked box has value, push it to first spot
-              if (this.stackUpWithColor[0]) {
-                this.stackUpWithColor[0].push(refDerivativeIndex);
-              } else {
-                this.stackUpWithColor[0] = [refDerivativeIndex];
-              }
-
-              delete derivativeJson[refDerivativeIndex];
-            } else {
-              // if checked boxes have values
-              for (var i = 0; i < keys.length; i++) {
-                var idx = keys[i]; 
-                if (referenceDerivative == derivativeJson[idx]) {
-                  arr.push(idx);
-                  this.stackUpWithColor[this.stackPointer] = arr;
-                  delete derivativeJson[idx];
-                }
-              }
-              if (arr.length > 0)
-                this.stackPointer++;
-            }
-          }
-        },
-
-        applyColors: function() {
-
-          var wholeNoTiles = 0;
-          var wholePercentage = 0;
-
-          THIS.addBottomTableHeadings();
-
-          for (var i = 0; i < THIS.allTiles.length; i++) {
-            var tile = THIS.allTiles[i];
-            THIS.setTileVisible(tile, false);
-          }
-
-          for (var color = 0; color < this.stackPointer; color++) {
-            var arr = this.stackUpWithColor[color];
-            if (arr) {
-              THIS.addBottomTableRow(color, arr);
-
-              for (var tileIndex in arr) {
-                wholeNoTiles++;
-                var index = this.stackUpWithColor[color][tileIndex]; 
-                var tile = THIS.allTiles[index];
-                var well = this.derivative[index];
-                THIS.setTileColor(tile, color, this.stackPointer); 
-                // Checks if all the required fields are filled
-                var completion = this.checkCompletion(well, tile);
-                THIS.setTileComplete(tile, completion == 1); 
-                wholePercentage = wholePercentage + completion;
-              }
-            }
-          }
-
-          wholePercentage = Math.floor(100 * wholePercentage / wholeNoTiles);
-
-          if (isNaN(wholePercentage)) {
-            THIS.overLayTextContainer.text("Completion Percentage: 0%");
-          } else {
-            THIS.overLayTextContainer.text("Completion Percentage: " + wholePercentage + "%");
-          }
-        },
-
-        checkCompletion: function(wellData, tile) {
-          var req = 0; 
-          var fill = 0;
-          for (var i = 0; i < THIS.fieldList.length; i++) {
-            var field = THIS.fieldList[i];
-            if (field.checkMultiplexCompletion){
-              // also apply color
-              var multiplexStatus = field.checkMultiplexCompletion(wellData[field.id]);
-              if (multiplexStatus.include) {
-                fill += multiplexStatus.completionPct;
-                req++;
-              }
-            } else {
-              if (field.required) {
-                req++;
-                if (wellData[field.id] !== null) {
-                  fill++;
-                }
-              }
-            }
-          }
-          if (req === fill) {
-            return 1; 
-          }
-          return fill / req;
-        },
-      }
-    }
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.fabricEvents = function() {
-    // This object contains Menu items and how it works;
-    return {
-      colorToIndex: {},
-      startCoords: {
-        x: 0,
-        y: 0
-      },
-      focalWell: {
-        row: 0,
-        col: 0
-      },
-      selectedAreas: [],
-
-      _clickCoords: function(evt) {
-        //Get XY Coords for a given event. 
-        var rect = evt.e.target.getBoundingClientRect();
-        return {
-          x: evt.e.clientX - rect.left,
-          y: evt.e.clientY - rect.top
-        };
-      },
-
-      _fabricEvents: function() {
-        // Set up event handling. 
-        var that = this;
-
-        $(that.target).on("getPlates", function(evt, data) {
-          // This method should be compatable to redo/undo.
-          that.getPlates(JSON.parse(data));
-        });
-
-        that.mainFabricCanvas.on("mouse:down", function(evt) {
-          // Start selecting new area
-          that.selecting = true;
-          var coords = that._clickCoords(evt);
-
-          var areas = that.selectedAreas.slice();
-          var focalWell = that.focalWell;
-          var startCoords = that._wellToCoords(focalWell, true);
-          var rect = that._coordsToRect(startCoords, coords);
-
-          if (evt.e.ctrlKey) {
-            //adding new area
-            startCoords = coords;
-            rect = that._coordsToRect(startCoords, coords);
-            focalWell = that._coordsToWell(startCoords);
-            if (evt.e.shiftKey) {
-              //replacing existing areas
-              areas = [that._rectToArea(rect)];
-            } else {
-              areas.push(that._rectToArea(rect));
-            }
-          } else {
-            if (evt.e.shiftKey) {
-              //Altering last area
-              areas[areas.length - 1] = that._rectToArea(rect);
-            } else {
-              //Creating new area
-              startCoords = coords;
-              rect = that._coordsToRect(startCoords, coords);
-              focalWell = that._coordsToWell(startCoords);
-              areas = [that._rectToArea(rect)];
-            }
-          }
-
-          that.startCoords = startCoords;
-          that.setSelection(areas, focalWell);
-          that.mainFabricCanvas.renderAll();
-        });
-
-        that.mainFabricCanvas.on("mouse:move", function(evt) {
-          if (that.selecting) {
-            // continue selecting new area
-            var areas = that.selectedAreas.slice();
-            var endCoords = that._clickCoords(evt);
-            var rect = that._coordsToRect(that.startCoords, endCoords);
-            var area = that._rectToArea(rect);
-            if (area) {
-              areas[areas.length - 1] = area;
-            }
-
-            that.setSelection(areas, that.focalWell);
-            that.mainFabricCanvas.renderAll();
-          }
-
-        });
-
-        that.mainFabricCanvas.on("mouse:up", function(evt) {
-          // finish selecting new area
-          that.selecting = false;
-          var areas = that.selectedAreas.slice();
-          var endCoords = that._clickCoords(evt);
-          var rect = that._coordsToRect(that.startCoords, endCoords);
-          var area = that._rectToArea(rect);
-          if (area) {
-            areas[areas.length - 1] = area;
-          }
-
-          that.setSelection(areas, that.focalWell);
-          that.decideSelectedFields();
-          that.mainFabricCanvas.renderAll();
-          that._trigger("selectedWells", null, {selectedAddress: that.getSelectedAddress()});
-        });
-      },
-
-      setSelection: function(areas, focalWell) {
-        this.selectedAreas = areas;
-        this.focalWell = focalWell;
-        this.allSelectedObjects = this._areasToTiles(areas);
-        this._setSelectedTiles();
-        this._setFocalWellRect(this.focalWell);
-        document.activeElement.blur();
-      },
-
-      _setFocalWellRect: function(well) {
-        var flag;
-        // check if not allow to add or delete existing wells
-        if (this.disableAddDeleteWell) {
-          var address = this.locToAddress({
-            r: well.row,
-            c: well.col
-          });
-          if  (this.addressAllowToEdit.indexOf(address) < 0) {
-            flag = false;
-            this.setFieldsDisabled(true);
-          } else {
-            flag = true;
-            this.setFieldsDisabled(false);
-          }
-        } else if (well) {
-          flag = true;
-        }
-
-        if (flag) {
-          var rect = this._areaToRect(this._wellToArea(well));
-          var strokeWidth = 2;
-          if (this.focalWellRect) {
-            //update focalWellRect
-            this.focalWellRect.top = rect.top;
-            this.focalWellRect.left = rect.left;
-            this.focalWellRect.width = rect.width - strokeWidth;
-            this.focalWellRect.height = rect.height - strokeWidth;
-          } else {
-            //create focalWellRect
-            this.focalWellRect = new fabric.Rect({
-              width: rect.width - strokeWidth,
-              height: rect.height - strokeWidth,
-              left: rect.left,
-              top: rect.top,
-              fill: null,
-              strokeWidth: strokeWidth,
-              stroke: "black",
-              selectable: false
-            });
-            this.mainFabricCanvas.add(this.focalWellRect);
-          }
-        } else {
-          //clear focalWellRect
-          this.mainFabricCanvas.remove(this.focalWellRect);
-          this.focalWellRect = null;
-        }
-      },
-
-      _setSelectedTiles: function() {
-        // Update selected tile display only
-        var selectedTiles = this.allSelectedObjects;
-        this.allTiles.forEach(function(tile) {
-          var selected = selectedTiles.indexOf(tile) >= 0;
-          tile.highlight.visible = selected;
-        })
-      },
-
-      _getSelectedWells: function () {
-        var that = this; 
-        return this.allSelectedObjects.map(function (tile) {
-          var well = that.engine.derivative[tile.index];
-          if (!well) {
-            well = that.defaultWell; 
-          }
-          return well; 
-        }); 
-      },
-
-      _getCommonFields: function (wells) {
-        if (wells.length) {
-          var referenceWell = wells[0];
-          var referenceFields = $.extend(true, {}, referenceWell);
-          for (var i = 1; i < wells.length; i++) {
-            var fields = wells[i];
-            for (var field in referenceFields) {
-              if (Array.isArray(referenceFields[field])) {
-                var refArr = referenceFields[field]; 
-                var agrArr = []; 
-                for (var j = 0; j < refArr.length; j++) {
-                  var v = refArr[j];
-                  if (v && typeof(v) === "object") {
-                    if (this.containsObject(v, fields[field])) {
-                      agrArr.push(v);
-                    }
-                  } else {
-                    if ($.inArray(v, fields[field]) >= 0) {
-                      agrArr.push(v);
-                    }
-                  }
-                }
-                referenceFields[field] = agrArr; 
-              } else {
-                if (fields[field] && typeof(fields[field]) ==="object" && referenceFields[field] && typeof(referenceFields[field]) ==="object"){
-                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){
-                    delete referenceFields[field];
-                  }
-                } else if (referenceFields[field] != fields[field]) {
-                  delete referenceFields[field];
-                }
-              }
-            }
-          }
-          return referenceFields
-        } else {
-          return {};
-        }
-      },
-
-      containsObject: function(obj, list) {
-        var equality = [];
-        if (list) {
-          list.forEach(function(val) {
-            //evaluate val and obj
-            var evaluate = [];
-            Object.keys(val).forEach(function(listKey){
-              if (Object.keys(obj).indexOf(listKey) >= 0){
-                var curVal = val[listKey];
-                if (typeof(curVal) === 'object' && curVal) {
-                  if (obj[listKey]){
-                    evaluate.push((curVal.unit === obj[listKey].unit) && (curVal.value === obj[listKey].value));
-                  } else {
-                    // when obj[listKey] is null but curVal is not
-                    evaluate.push(false);
-                  }
-                } else {
-                  evaluate.push(curVal === obj[listKey]);
-                }
-              }
-            });
-            equality.push(evaluate.indexOf(false) < 0);
-          });
-          return equality.indexOf(true) >= 0;
-        } else {
-          return false;
-        }
-      },
-
-      _getCommonWell: function (wells) {
-        if (wells.length) {
-          var referenceWell = wells[0];
-          var referenceFields = $.extend(true, {}, referenceWell);
-          for (var i = 1; i < wells.length; i++) {
-            var well = wells[i];
-            var fields = well;
-            for (var field in referenceFields) {
-              if (Array.isArray(referenceFields[field])) {
-                var refArr = referenceFields[field]; 
-                var agrArr = []; 
-                for (var j = 0; j < refArr.length; j++) {
-                  var v = refArr[j];
-                  // for multiplex field
-                  if (typeof(refArr[j]) ==="object"){
-                    if (this.containsObject(v, fields[field])) {
-                      agrArr.push(v);
-                    }
-                  } else {
-                    if ($.inArray(v, fields[field]) >= 0) {
-                      agrArr.push(v);
-                    }
-                  }
-                }
-                referenceFields[field] = agrArr; 
-              } else {
-                if (fields[field] && typeof(fields[field]) ==="object" && referenceFields[field] && typeof(referenceFields[field]) ==="object"){
-                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){
-                    referenceFields[field] = null;
-                  }
-                } else if (referenceFields[field] != fields[field]) {
-                  referenceFields[field] = null;
-                }
-
-              }
-            }
-          }
-          return referenceFields;
-        } else {
-          return this.defaultWell; 
-        }
-      }, 
-
-      _getAllMultipleVal: function (wells) {
-        var multipleFieldList = this.multipleFieldList;
-
-        multipleFieldList.forEach(function(multiplexField) {
-          if(wells.length) {
-            var curMultipleVal = {};
-            wells.forEach(function (wellData) {
-              var id = multiplexField.id;
-              if (wellData[id]){
-                if (wellData[id].length > 0) {
-                  wellData[id].forEach(function (multipleVal) {
-                    if (typeof(multipleVal) === 'object') {
-                      if (multipleVal[id] in curMultipleVal) {
-                        curMultipleVal[multipleVal[id]] ++;
-                      } else {
-                        curMultipleVal[multipleVal[id]] = 1;
-                      }
-                    } else {
-                      if (multipleVal in curMultipleVal) {
-                        curMultipleVal[multipleVal] ++;
-
-                      } else {
-                        curMultipleVal[multipleVal] = 1;
-                      }
-                    }
-                  })
-                }
-              }
-            });
-            multiplexField.allSelectedMultipleVal = curMultipleVal;
-          } else {
-            multiplexField.allSelectedMultipleVal = null
-          }
-        });
-      },
-
-      decideSelectedFields: function() {
-        var wells = this._getSelectedWells();
-        this._getAllMultipleVal(wells);
-        this.applyFieldWarning(wells);
-        var well = this._getCommonWell(wells); 
-        this._addDataToTabFields(well);
-      },
-
-      // get well value differences for each well in wellsHash
-      getDifferentWellsVals: function(wellsHash) {
-        var wells = [];
-        for (var wellId in wellsHash){
-          wells.push(wellsHash[wellId]);
-        }
-        var differentWellsVals = {};
-        if (wells.length > 1){
-          var commonWell = this._getCommonWell(wells);
-          var allFieldVal = {};
-          for (var fieldIdx in wellsHash[0]) {
-            allFieldVal[fieldIdx] = [];
-          }
-          for (var wellIdx in wells){
-            var diffWellVal = {};
-            var curWellData = wells[wellIdx];
-            for (var fieldId in curWellData) {
-              var commonVal = commonWell[fieldId];
-              var curVal = curWellData[fieldId];
-              var newVal = null;
-              if (Array.isArray(curVal)) {
-                // get uncommonVal
-                newVal = [];
-                for (var idx = 0; idx < curVal.length; idx ++){
-                  var curMultiVal = curVal[idx];
-                  // multiplex field
-                  if (curMultiVal && typeof(curMultiVal === "object")){
-                    if (!this.containsObject(curMultiVal, commonVal)) {
-                      newVal.push(curMultiVal);
-                      if (!this.containsObject(curMultiVal, allFieldVal[fieldId])) {
-                        allFieldVal[fieldId].push(curMultiVal);
-                      }
-                    }
-                  } else {
-                    if (commonVal.indexOf(curMultiVal) >= 0) {
-                      newVal.push(curMultiVal);
-                      if (!allFieldVal[fieldId].indexOf(curMultiVal) >= 0) {
-                        allFieldVal[fieldId].push(curMultiVal);
-                      }
-                    }
-                  }
-                }
-              } else if (curVal && typeof(curVal) === "object"){
-                if (commonVal && typeof(commonVal) ==="object"){
-                  if (!((curVal.value === commonVal.value) || (curVal.unit === commonVal.unit))){
-                    newVal = curVal;
-                    if (!this.containsObject(curVal, allFieldVal[fieldId])) {
-                      allFieldVal[fieldId].push(curVal);
-                    }
-                  }
-                } else {
-                  newVal = curVal;
-                  if (!this.containsObject(curVal, allFieldVal[fieldId])) {
-                    allFieldVal[fieldId].push(curVal);
-                  }
-                }
-              } else if (curVal !== commonVal) {
-                newVal = curVal;
-                if (!allFieldVal[fieldId].indexOf(curVal) >= 0) {
-                  allFieldVal[fieldId].push(curVal);
-                }
-              }
-              diffWellVal[fieldId] = newVal;
-            }
-
-
-            differentWellsVals[wellIdx] = diffWellVal;
-          }
-
-          // clean up step for fields that are empty
-          for (var fieldId in allFieldVal) {
-            if (allFieldVal[fieldId].length === 0) {
-              for (var wellIdx in differentWellsVals){
-                delete differentWellsVals[wellIdx][fieldId];
-              }
-            }
-          }
-
-          return differentWellsVals;
-        } else if (wellsHash[0]) {
-          var well = {};
-          for (var fieldId in wellsHash[0]) {
-            var curVal = wellsHash[0][fieldId];
-            if (Array.isArray(curVal)){
-              if (curVal.length > 0) {
-                well[fieldId] = curVal
-              }
-            } else if (curVal){
-              well[fieldId] = curVal;
-            }
-          }
-          return {
-            0: well
-          };
-        }
-      },
-
-      // get all wells that has data
-      getWellSetAddressWithData: function(){
-        var address = [];
-        var derivative = this.engine.derivative;
-        for (var id in derivative){
-          address.push(this.indexToAddress(id));
-        }
-        return address;
-      }
-
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-plateLayOutWidget.assets = function () {
-    return {
-        _assets: {
-            doImg: '&#10003;',
-            dontImg: '',
-            warningImg: '&#9888;'
-        }
-    };
-};
-
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.interface = function() {
-    // interface holds all the methods to put the interface in place
-    return {
-
-      _createInterface: function() {
-
-        var divIdentifier = '<div></div>';
-        this.container = this._createElement(divIdentifier).addClass("plate-setup-wrapper");
-        this.topSection = this._createElement(divIdentifier).addClass("plate-setup-top-section");
-
-        this.topLeft = this._createElement(divIdentifier).addClass("plate-setup-top-left");
-        this.topRight = this._createElement(divIdentifier).addClass("plate-setup-top-right");
-
-        this.overLayContainer = this._createElement(divIdentifier).addClass("plate-setup-overlay-container");
-        this.canvasContainer = this._createElement(divIdentifier).addClass("plate-setup-canvas-container");
-
-        this._createOverLay();
-        $(this.topLeft).append(this.overLayContainer);
-
-        this._createCanvas();
-        $(this.topLeft).append(this.canvasContainer);
-
-
-        $(this.topSection).append(this.topLeft);
-        $(this.topSection).append(this.topRight);
-
-        $(this.container).append(this.topSection);
-        $(this.element).append(this.container);
-
-        this._initiateFabricCanvas();
-
-        this._createTabAtRight();
-        this._createTabs();
-
-        this._placePresetTabs();
-        // Bottom of the screen
-        this._bottomScreen();
-        // Canvas
-        this._canvas();
-
-        this.bottomForFirstTime();
-
-        var that = this;
-        this._setShortcuts();
-        $(document.body).keyup(function(e) {
-          that._handleShortcuts(e);
-        });
-
-        this._configureUndoRedoArray();
-      },
-
-      _createElement: function(element) {
-        return $(element);
-      },
-
-      _setShortcuts: function () {
-        var that = this; 
-        window.addEventListener("cut", function (e) {
-          if (document.activeElement == document.body) {
-            that.copyCriteria();
-            that.clearCriteria();
-            e.preventDefault();
-          }
-        });
-        window.addEventListener("copy", function (e) {
-          if (document.activeElement == document.body) {
-            that.copyCriteria();
-            e.preventDefault();
-          }
-        });
-        window.addEventListener("paste", function (e) {
-          if (document.activeElement == document.body) {
-            that.pasteCriteria();
-            e.preventDefault();
-          }
-        });
-      },
-
-      _handleShortcuts: function(e) {
-        if (document.activeElement === document.body) {
-          if (e.keyCode == 46) {
-            this.clearCriteria();
-            e.preventDefault();
-          } else if (e.ctrlKey || e.metaKey) {
-            if (e.keyCode == 90) {
-              if (e.shiftKey) {
-                this.redo();
-              } else {
-                this.undo();
-              }
-              e.preventDefault();
-            } else if (e.keyCode == 89) {
-              this.redo();
-              e.preventDefault();
-            }
-          }
-        }
-      },
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.loadPlate = function(THIS) {
-    // Methods which look after data changes and stack up accordingly
-    // Remember THIS points to plateLayOutWidget and 'this' points to engine
-    return {
-
-      getPlates: function (data) {
-        //sanitize input
-        var derivative = {}; 
-        for (var index in data.derivative) {
-          var well = data.derivative[index]; 
-          derivative[index] = this.sanitizeWell(well); 
-        }
-
-        var checkboxes = data.checkboxes || []; 
-        var selection = this.sanitizeAreas(data.selectedAreas, data.focalWell); 
-
-        var sanitized = {
-          "derivative": derivative,
-          "checkboxes": checkboxes,
-          "selectedAreas": selection.selectedAreas,
-          "focalWell": selection.focalWell
-        }; 
-
-        this.setData(sanitized);
-      }, 
-
-      sanitizeAreas: function (selectedAreas, focalWell) {
-        var that = this; 
-        var rows = this.dimensions.rows;
-        var cols = this.dimensions.cols;
-
-        if (!selectedAreas) {
-          selectedAreas = [];
-        }
-        if (selectedAreas.length) {
-          selectedAreas = selectedAreas.map(function (area) {
-            return {
-              minCol: that._coordIndex(Math.min(area.minCol, area.maxCol), cols), 
-              minRow: that._coordIndex(Math.min(area.minRow, area.maxRow), rows), 
-              maxCol: that._coordIndex(Math.max(area.minCol, area.maxCol), cols), 
-              maxRow: that._coordIndex(Math.max(area.minRow, area.maxRow), rows)
-            }; 
-          }); 
-          var area = selectedAreas[selectedAreas.length - 1];
-          if (focalWell && !this._wellInArea(focalWell, area)) {
-            focalWell = null;
-          }
-          if (!focalWell) {
-            focalWell = {
-              row: area.minRow,
-              col: area.minCol
-            };
-          }
-        } else {
-          if (!focalWell) {
-            focalWell = {
-              row: 0,
-              col: 0
-            };
-          }
-          selectedAreas = [this._wellToArea(focalWell)];
-        }
-        return {
-          selectedAreas: selectedAreas, 
-          focalWell: focalWell
-        };
-      }, 
-
-      sanitizeWell: function (well) {
-        var newWell = {};
-        for (var i = 0; i < this.fieldList.length; i++) {
-          var field = this.fieldList[i];
-          newWell[field.id] = field.parseValue(well[field.id]);
-        }
-        return newWell; 
-      }, 
-
-      setData: function(data) {
-        this.engine.derivative = $.extend(true, {}, data.derivative);
-        this.setCheckboxes(data.checkboxes);
-        this.setSelection(data.selectedAreas, data.focalWell);
-        this._colorMixer();
-        this.decideSelectedFields();
-        this.mainFabricCanvas.renderAll();
-      },
-
-    }
-  }
-})(jQuery, fabric);
-var GET_PLATES = 'getPlates';
-var IS_READ_ONLY = 'isReadOnly';
-var IS_DISABLE_ADD_DELETE_WELL = 'isDisableAddDeleteWell';
-var GET_SELECTED_OBJECT = 'getSelectedObject';
-var SETSELECTEDWELL = 'setSelectedWell';
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.overlay = function() {
-    // overlay holds all the methods to put the part just above the canvas which contains all those
-    // 'completion percentage' annd 'copy Criteria' button etc ...
-    return {
-
-      _createOverLay: function() {
-
-        var that = this;
-        this.overLayTextContainer = this._createElement("<div></div>").addClass("plate-setup-overlay-text-container");
-        this.overLayTextContainer.text("Completion Percentage:");
-        this.overLayContainer.append(this.overLayTextContainer);
-        this.overLayButtonContainer = this._createElement("<div></div>").addClass("plate-setup-overlay-button-container");
-        this.overLayContainer.append(this.overLayButtonContainer);
-
-        this.clearCriteriaButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.clearCriteriaButton.text("Clear");
-        this.overLayButtonContainer.append(this.clearCriteriaButton);
-
-        this.clearCriteriaButton.click(function(evt) {
-          that.clearCriteria();
-        });
-
-        this.copyCriteriaButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.copyCriteriaButton.text("Copy");
-        this.overLayButtonContainer.append(this.copyCriteriaButton);
-
-        this.copyCriteriaButton.click(function(evt) {
-          that.copyCriteria();
-        });
-
-        this.pasteCriteriaButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.pasteCriteriaButton.text("Paste");
-        this.overLayButtonContainer.append(this.pasteCriteriaButton);
-
-        this.pasteCriteriaButton.click(function(evt) {
-          that.pasteCriteria();
-        });
-
-        this.undoButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.undoButton.text("Undo");
-        this.overLayButtonContainer.append(this.undoButton);
-
-        this.undoButton.click(function(evt) {
-          that.undo();
-        });
-
-        this.redoButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.redoButton.text("Redo");
-        this.overLayButtonContainer.append(this.redoButton);
-
-        this.redoButton.click(function(evt) {
-          that.redo();
-        });
-
-      },
-
-      clearCriteria: function() {
-        if (this.allSelectedObjects) {
-          var noOfSelectedObjects = this.allSelectedObjects.length;
-          var hasWellUpdate = false;
-          for (var objectIndex = 0; objectIndex < noOfSelectedObjects; objectIndex++) {
-            var tile = this.allSelectedObjects[objectIndex];
-            if (tile.index in this.engine.derivative) {
-              // handling for clearing well when not allowed to add or delete wells
-              if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {
-                var well = JSON.parse(JSON.stringify(this.defaultWell));
-                var defaultValue = this.emptyWellWithDefaultVal;
-                for (var key in defaultValue){
-                  if (key in well) {
-                    well[key] = defaultValue[key];
-                    this._applyFieldData(key, defaultValue[key]);
-                  } else {
-                    console.log("Well does not contain key: " + key + ", please contact support");
-                  }
-                }
-                this.engine.derivative[tile.index] = well;
-              } else {
-                delete this.engine.derivative[tile.index];
-              }
-              hasWellUpdate = true;
-            }
-          }
-          if (hasWellUpdate){
-            this.derivativeChange();
-          }
-
-          this._colorMixer();
-          this.decideSelectedFields();
-        } else {
-          alert("Please select any well");
-        }
-      },
-
-      copyCriteria: function() {
-        if (this.allSelectedObjects) {
-          var wells = this._getSelectedWells(); 
-          this.commonWell = this._getCommonFields(wells); 
-        } else {
-          alert("Please select any well.");
-        }
-      },
-
-      pasteCriteria: function() {
-        if (this.commonWell) {
-          this._addAllData(this.commonWell);
-          this.decideSelectedFields();
-          this.mainFabricCanvas.renderAll();
-        }
-      }
-    };
-  }
-})(jQuery, fabric);
-$.widget("DNA.plateLayOut", {
-
-  plateLayOutWidget: {},
-
-  options: {
-    value: 0
-  },
-
-  allTiles: [], // All tiles containes all thise circles in the canvas
-
-  addressToLoc: function (layoutAddress) {
-    var m = /^([A-Z]+)(\d+)$/.exec(layoutAddress.trim().toUpperCase())
-    if (m) {
-      var row_v = m[1]; 
-      var col = parseInt(m[2])-1;
-      var row; 
-      for (var i = 0; i < row_v.length; i++) {
-        var c = row_v.charCodeAt(i) - 65; 
-        if (i) {
-            row += 1;
-            row *= 26; 
-            row += c ; 
-        } else {
-            row = c;
-        }
-      }
-      return {
-        r: row, 
-        c: col
-      };
-    } else {
-      throw layoutAddress + " not a proper layout address"; 
-    }
-  },
-
-  locToIndex: function (loc, dimensions) {
-    if (!dimensions) {
-      dimensions = this.dimensions;
-    }
-    if (loc.r < 0) {
-      t
-    }
-    if (!(loc.r >= 0 && loc.r < dimensions.rows)) {
-      throw "Row index " + (loc.r + 1) + " invalid"; 
-    }
-    if (!(loc.c >= 0 && loc.c < dimensions.cols)) {
-      throw "Column index " + (loc.c + 1) + " invalid"; 
-    }
-    return loc.r*dimensions.cols + loc.c; 
-  },
-
-  addressToIndex: function (layoutAddress, dimensions) {
-    var loc = this.addressToLoc(layoutAddress); 
-    return this.locToIndex(loc, dimensions); 
-  }, 
-
-  _rowKey: function (i) {
-    var c1 = i % 26;
-    var c2 = (i - c1) / 26;
-    var code = String.fromCharCode(65 + c1);
-    if (c2 > 0) {
-      code = String.fromCharCode(64 + c2) + code;
-    }
-    return code;
-  }, 
-
-  indexToLoc: function (index, dimensions) {
-    if (!dimensions) {
-      dimensions = this.dimensions;
-    }
-
-    if (index >= dimensions.rows * dimensions.cols) {
-      throw "Index too high: " + index.toString(10); 
-    }
-    var loc = {}; 
-    loc.c = index % dimensions.cols;
-    loc.r = (index - loc.c) / dimensions.cols;
-
-    return loc; 
-  },
-
-  locToAddress: function (loc) {
-    return this._rowKey(loc.r) + (loc.c + 1).toString(10);
-  },
-
-  indexToAddress: function (index, dimensions) {
-    var loc = this.indexToLoc(index, dimensions); 
-    return this.locToAddress(loc); 
-  },
-
-  getDimensions: function () {
-    return $.extend(true, {}, this.dimensions);
-  },
-
-  _create: function() {
-    var rows = parseInt(this.options.numRows || 8);
-    var cols = parseInt(this.options.numCols || 12);
-    this.dimensions = {
-      rows: rows,
-      cols: cols
-    };
-    this.rowIndex = [];
-    for (var i = 0; i < rows; i++) {
-      this.rowIndex.push(this._rowKey(i));
-    }
-
-    this.target = (this.element[0].id) ? "#" + this.element[0].id : "." + this.element[0].className;
-
-    // Import classes from other files.. Here we import it using extend and add it to this
-    // object. internally we add to widget.DNA.getPlates.prototype.
-    // Helpers are methods which return other methods and objects.
-    // add Objects to plateLayOutWidget and it will be added to this object.
-    // set read only well
-    if (this.options.readOnly){
-      this.isReadOnly(true);
-    }
-
-    for (var component in plateLayOutWidget) {
-      // Incase some properties has to initialize with data from options hash,
-      // we provide it sending this object.
-      $.extend(this, new plateLayOutWidget[component](this));
-    }
-
-    this.imgSrc = this.options.imgSrc || "assets";
-
-    this._createInterface();
-
-    this._trigger("created", null, this);
-
-    return this;
-  },
-
-  _init: function() {
-    // This is invoked when the user use the plugin after _create is called.
-    // The point is _create is invoked for the very first time and for all other
-    // times _init is used.
-  },
-
-  addData: function() {
-    alert("wow this is good");
-  },
-
-  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
-  getTextDerivative: function(wellsData) {
-    var textDerivative = {};
-    var fieldMap = this.fieldMap;
-    for (var idx in wellsData){
-      var textValWell = {};
-      var textFieldIdWell = {};
-      var curWellData = wellsData[idx];
-      for (var fieldId in curWellData){
-        if (fieldId in this.fieldMap){
-          var field = this.fieldMap[fieldId];
-          var textVal = field.parseText(curWellData[fieldId]);
-          textFieldIdWell[field.name] = textVal;
-          textValWell[fieldId] = textVal;
-        } else {
-          // do not convert if not a field (ex: layout_address)
-          textFieldIdWell[fieldId] = curWellData[fieldId];
-          textValWell[fieldId] = curWellData[fieldId];
-        }
-      }
-      textDerivative[idx] = {
-        textVal: textValWell,
-        textFieldVal: textFieldIdWell
-      };
-    }
-
-    return textDerivative;
-  },
-
-  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
-  getWellsDifferences: function(wellsData) {
-    return this.getDifferentWellsVals(wellsData);
-  },
-
-  setFieldsDisabled: function(flag){
-    this.fieldList.forEach(function(field){
-      field.disabled(flag);
-    });
-  },
-
-  isReadOnly: function(flag){
-    if (flag){
-      this.readOnly = true;
-    } else {
-      this.readOnly = false;
-    }
-    this.readOnlyHandler();
-  },
-
-  readOnlyHandler: function(){
-    if (this.readOnly){
-      this.overLayButtonContainer.css("display", "none");
-      $('.multiple-field-manage-delete-button').css("display", "none");
-      this.setFieldsDisabled(true);
-    } else {
-      this.overLayButtonContainer.css("display", "flex");
-      $('.multiple-field-manage-delete-button').css("display", "none");
-      if (!this.disableAddDeleteWell) {
-        this.setFieldsDisabled(false);
-      }
-    }
-  },
-
-  disableAddDeleteWell: null,
-  // column_with_default_val will be used to determine empty wells, format: {field_name: default_val}
-  isDisableAddDeleteWell: function(flag, column_with_default_val){
-    if (flag){
-      this.disableAddDeleteWell = true;
-      this.addressAllowToEdit = this.getWellSetAddressWithData();
-      // configure undo redo action
-      this.actionPointer = 0;
-      this.undoRedoArray = [];
-      this.undoRedoArray.push(this.createObject());
-      if (column_with_default_val) {
-        this.emptyWellWithDefaultVal = column_with_default_val;
-      }
-    } else {
-      this.disableAddDeleteWell = false;
-      this.setFieldsDisabled(false);
-      this.emptyWellWithDefaultVal = null;
-    }
-    this._fabricEvents();
-  },
-
-  getSelectedObject: function() {
-    var selectedAddress = [];
-    for (var i = 0; i < this.allSelectedObjects.length; i++){
-      selectedAddress.push(this.allSelectedObjects[i].address);
-    }
-    var selectedObjects = {};
-    var derivative = this.engine.derivative;
-    for (var loc in derivative){
-      var address = this.indexToAddress(loc);
-      if (selectedAddress.indexOf(address) >= 0) {
-        selectedObjects[address] = derivative[loc];
-      }
-    }
-    return selectedObjects;
-  },
-
-  getSelectedIndex: function() {
-    return this.allSelectedObjects.map(function(selectedObj){
-        return that.addressToIndex(selectedObj.address)
-    });
-  },
-
-  getSelectedAddress: function() {
-    return this.allSelectedObjects.map(function(selectedObj){
-      return selectedObj.address;
-    });
-  },
-
-  setSelectedWell: function(addressList) {
-    var areas = [];
-    var minRow = 999;
-    var locMap = {};
-    for (var id = 0; id < addressList.length; id++){
-      var wellIdx = this.addressToIndex(addressList[id]);
-      var loc = this.indexToLoc(wellIdx);
-      areas.push({
-        minCol: loc.c,
-        minRow: loc.r,
-        maxCol: loc.c,
-        maxRow: loc.r
-      });
-      if (loc.r <= minRow) {
-        minRow = loc.r;
-        if (loc.r in locMap) {
-          locMap[loc.r].push(loc.c);
-        } else {
-          locMap[loc.r] = [loc.c];
-        }
-      }
-    }
-    var focalWell = {
-      row: minRow,
-      col: Math.min.apply(null, locMap[minRow])
-    };
-
-    this.setSelection(areas, focalWell);
-    this.decideSelectedFields();
-    this.mainFabricCanvas.renderAll();
-  }
-
-});
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.preset = function(me) {
-    // All the preset action goes here
-    return {
-
-      presets: [],
-
-      _placePresetTabs: function() {
-        var presets = this.options.attributes.presets;
-
-        if (presets && presets.length) {
-          this.wellAttrContainer = this._createElement("<div></div>").addClass("plate-setup-well-attr-container")
-            .text("Checkbox presets");
-          this.tabContainer.append(this.wellAttrContainer);
-
-          this.presetTabContainer = this._createElement("<div></div>").addClass("plate-setup-preset-container");
-          this.tabContainer.append(this.presetTabContainer);
-
-          for (var i = 0; i < presets.length; i++) {
-            var preset = presets[i];
-            var divText = this._createElement("<div></div>").addClass("plate-setup-prest-tab-div")
-              .text(preset.title);
-
-            var presetButton = this._createElement("<div></div>").addClass("plate-setup-prest-tab")
-              .data("preset", preset.fields).append(divText);
-            this.presetTabContainer.append(presetButton);
-
-            var that = this;
-            presetButton.click(function() {
-              var preset = $(this);
-              that._selectPreset(preset);
-            });
-            this.presets.push(presetButton);
-          }
-        }
-      },
-
-      _clearPresetSelection: function() {
-        for (var j = 0; j < this.presets.length; j++) {
-          var p = this.presets[j]; 
-          p.removeClass("plate-setup-prest-tab-selected")
-            .addClass("plate-setup-prest-tab"); 
-        }
-      },
-
-      _selectPreset: function (preset) {
-        this.setCheckboxes(preset.data("preset")); 
-        preset.removeClass("plate-setup-prest-tab")
-          .addClass("plate-setup-prest-tab-selected");
-      },
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.tabs = function() {
-    // Tabs crete and manage tabs at the right side of the canvas.
-    return {
-
-      allTabs: [],
-
-      defaultWell: {},
-
-      allDataTabs: [], // To hold all the tab contents. this contains all the tabs and its elements and elements
-      // Settings as a whole. its very usefull, when we have units for a specific field.
-      // it goes like tabs-> individual field-> units and checkbox
-
-      _createTabAtRight: function() {
-        this.tabContainer = this._createElement("<div></div>").addClass("plate-setup-tab-container");
-        $(this.topRight).append(this.tabContainer);
-      },
-
-      _createTabs: function() {
-        // this could be done using z-index. just imagine few cards stacked up.
-        // Check if options has tab data.
-        // Originally we will be pulling tab data from developer.
-        // Now we are building upon dummy data.
-        this.tabHead = this._createElement("<div></div>").addClass("plate-setup-tab-head");
-        $(this.tabContainer).append(this.tabHead);
-
-        var tabData = this.options.attributes.tabs;
-        var that = this;
-
-        tabData.forEach(function (tab, tabIndex) {
-          that.allTabs[tabIndex] = that._createElement("<div></div>").addClass("plate-setup-tab");
-          $(that.allTabs[tabIndex]).data("index", tabIndex)
-            .text(tab.name);
-
-          $(that.allTabs[tabIndex]).click(function() {
-            that._tabClickHandler(this);
-          });
-
-          $(that.tabHead).append(that.allTabs[tabIndex]);
-        }); 
-
-        this.tabDataContainer = this._createElement("<div></div>").addClass("plate-setup-tab-data-container");
-        $(this.tabContainer).append(this.tabDataContainer);
-
-        this._addDataTabs(tabData);
-
-        $(this.allTabs[0]).click();
-
-        this._addTabData();
-      },
-
-      _tabClickHandler: function(clickedTab) {
-
-        if (this.selectedTab) {
-          $(this.selectedTab).removeClass("plate-setup-tab-selected")
-            .addClass("plate-setup-tab");
-
-          var previouslyClickedTabIndex = $(this.selectedTab).data("index");
-          $(this.allDataTabs[previouslyClickedTabIndex]).css("z-index", 0);
-          this.readOnlyHandler();
-        }
-
-        $(clickedTab).addClass("plate-setup-tab-selected");
-
-        this.selectedTab = clickedTab;
-
-        var clickedTabIndex = $(clickedTab).data("index");
-        $(this.allDataTabs[clickedTabIndex]).css("z-index", 1000);
-      },
-
-      _addDataTabs: function(tabs) {
-
-        var tabIndex = 0;
-
-        for (var tabData in tabs) {
-          this.allDataTabs[tabIndex++] = this._createElement("<div></div>").addClass("plate-setup-data-div")
-            .css("z-index", 0);
-          $(this.tabDataContainer).append(this.allDataTabs[tabIndex - 1]);
-        }
-      }
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.undoRedoManager = function(THIS) {
-
-    return {
-
-      undoRedoArray: [],
-
-      actionPointer: null,
-
-      addToUndoRedo: function(data) {
-
-        if (this.actionPointer != null) {
-          var i = this.actionPointer + 1; 
-          if (i < this.undoRedoArray.length) {
-            this.undoRedoArray.splice(i, this.undoRedoArray.length - i);
-          }
-        }
-        this.actionPointer = null;
-        this.undoRedoArray.push($.extend(true, {}, data));
-      },
-
-      _configureUndoRedoArray: function() {
-
-        var data = {
-          checkboxes: [],
-          derivative: {},
-          selectedAreas: [{
-            minRow: 0,
-            minCol: 0,
-            maxRow: 0,
-            maxCol: 0
-          }],
-          focalWell: {
-            row: 0,
-            col: 0
-          }
-        };
-
-        this.undoRedoArray = []; 
-        this.actionPointer = null; 
-        this.undoRedoArray.push($.extend({}, data));
-      },
-
-      undo: function() {
-        console.log("undo");
-        return this.shiftUndoRedo(-1); 
-      },
-
-      redo: function() {
-        console.log("redo");
-        return this.shiftUndoRedo(1); 
-      }, 
-
-      shiftUndoRedo: function (pointerDiff) {
-        var pointer = this.actionPointer;
-        if (pointer == null) {
-          pointer = this.undoRedoArray.length - 1; 
-        }
-        pointer += pointerDiff; 
-        return this.setUndoRedo(pointer); 
-      }, 
-
-      setUndoRedo: function (pointer) {
-        if (pointer < 0) {
-          return false; 
-        }
-        if (pointer >= this.undoRedoArray.length) {
-          return false; 
-        }
-        this.undoRedoActive = true; 
-        this.setData(this.undoRedoArray[pointer]);
-        this.actionPointer = pointer; 
-        this.undoRedoActive = false;
-        this.derivativeChange();
-        return true;
-      }
-    }
-  };
-
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.wellArea = function(fabric) {
-
-    return {
-
-      _areasToTiles: function(areas) {
-        //Convert areas to tiles
-        var cols = this.dimensions.cols;
-        var that = this;
-        return areas.reduce(function(tiles, area) {
-          if (area) {
-            for (var r = area.minRow; r <= area.maxRow; r++) {
-              for (var c = area.minCol; c <= area.maxCol; c++) {
-                var tile = that.allTiles[c + cols * r];
-                if (tiles.indexOf(tile) < 0) {
-                  if (that.disableAddDeleteWell){
-                    if(that.addressAllowToEdit.indexOf(tile.address) >= 0){
-                      tiles.push(tile);
-                    }
-                  } else {
-                    tiles.push(tile);
-                  }
-                }
-              }
-            }
-          }
-          return tiles;
-        }, []);
-      },
-
-      _encodeArea: function(area) {
-        //Encode area as string
-        if ((area.minRow == area.maxRow) && (area.minCol == area.maxCol)) {
-          return this.rowIndex[area.minRow] + area.minCol.toString(10);
-        } else {
-          return this.rowIndex[area.minRow] + area.minCol.toString(10) + ":" + this.rowIndex[area.maxRow] + area.maxCol.toString(10);
-        }
-      },
-
-      _encodeAreas: function(areas) {
-        //Encode an array of areas as a string
-        var that = this;
-        return areas.map(function(area) {
-          return that._encodeArea(area);
-        }).join(",");
-      },
-
-      _decodeWell: function(wellAddress) {
-        var that = this;
-        var adRx = new RegExp("^\\s*(" + that.rowIndex.join("|") + ")(\\d+)\\s*$")
-        var rcRx = /^\s*R(\d+)C(\d+)\s*$/i;
-
-        var match;
-        match = wellAddress.match(adRx);
-        if (match) {
-          var row = that.rowIndex.indexOf(match[1]);
-          if (row >= 0) {
-            return {
-              row: row,
-              col: parseInt(match[2]) - 1
-            };
-          }
-        }
-        match = wellAddress.match(rcRx);
-        if (match) {
-          return {
-            row: parseInt(match[1]) - 1,
-            col: parseInt(match[2]) - 1
-          };
-        }
-
-        throw "Invalid well address: " + wellAddress;
-      },
-
-      _decodeArea: function(areaAddress) {
-        //Decode single area as string
-        var that = this;
-        var wells = areaAddress.split(":").map(function(wellAddress) {
-          return that._decodeWell(wellAddress);
-        })
-        if (wells.length == 1) {
-          return {
-            minRow: wells[0].row,
-            minCol: wells[0].col,
-            maxRow: wells[0].row,
-            maxCol: wells[0].col
-          }
-        } else if (wells.length == 2) {
-          var minRow = Math.min(wells[0].row, wells[1].row)
-          return {
-            minRow: Math.min(wells[0].row, wells[1].row),
-            minCol: Math.min(wells[0].col, wells[1].col),
-            maxRow: Math.max(wells[0].row, wells[1].row),
-            maxCol: Math.max(wells[0].col, wells[1].col)
-          }
-        } else {
-          throw "Invalid address: " + areaAddress;
-        }
-      },
-
-      _decodeAreas: function(areasAddress) {
-        //Decode single area as string
-        var that = this;
-        return areasAddress.split(",").map(function(areaAddress) {
-          return that._decodeArea(areaAddress);
-        });
-      },
-
-      _wellToArea: function(well) {
-        //Convert a well to an area
-        return {
-          minCol: well.col,
-          minRow: well.row,
-          maxCol: well.col,
-          maxRow: well.row
-        }
-      },
-
-      _wellInArea: function(well, area) {
-        //Determine if a well lies within an area
-        return well.row >= area.minRow && well.row <= area.maxRow && well.col >= area.minCol && well.col <= area.maxCol;
-      },
-
-      _coordsToRect: function(startCoords, endCoords) {
-        //Convert two XY coords to a bounding box
-        var left = Math.min(startCoords.x, endCoords.x);
-        var top = Math.min(startCoords.y, endCoords.y);
-        var height = Math.abs(endCoords.y - startCoords.y);
-        var width = Math.abs(endCoords.x - startCoords.x);
-        return {
-          top: top,
-          left: left,
-          height: height,
-          width: width
-        };
-      },
-
-      _coordIndex: function(v, count) {
-        var i;
-        if (v < 0) {
-          i = 0;
-        } else if (v >= count) {
-          i = count - 1;
-        } else {
-          i = Math.floor(v);
-        }
-        return i;
-      },
-
-      _coordsToWell: function(coord) {
-        //Convert a coordinate to a well
-        var cols = this.dimensions.cols;
-        var rows = this.dimensions.rows;
-
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
-
-        var x = (coord.x - m) / w;
-        var y = (coord.y - m) / w;
-
-        var row = this._coordIndex(y, rows);
-        var col = this._coordIndex(x, cols);
-
-        return {
-          row: row,
-          col: col,
-        };
-      },
-
-      _wellToCoords: function(well, center) {
-        //Convert a well to a coordinate
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
-        var x = well.col * w + m;
-        var y = well.row * w + m;
-        if (center) {
-          var hw = w/2;
-          x = x + hw;
-          y = y + hw;
-        }
-
-        return {
-          x: x,
-          y: y
-        };
-      },
-
-      _areaToRect: function(area) {
-        //Convert area to rectangle
-        var rows = area.maxRow - area.minRow + 1;
-        var cols = area.maxCol - area.minCol + 1;
-
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
-
-        return {
-          top: area.minRow * w + m,
-          left: area.minCol * w + m,
-          height: rows * w,
-          width: cols * w
-        }
-      },
-
-      _rectToArea: function(rect) {
-        //Convert a rectangular region to an area
-        var rows = this.dimensions.rows;
-        var cols = this.dimensions.cols;
-
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
-
-        var left = (rect.left - m) / w;
-        var top = (rect.top - m) / w;
-        var height = rect.height / w;
-        var width = rect.width / w;
-        var right = left + width;
-        var bottom = top + height;
-
-        //select whole row
-        if (right < 0) {
-          right = cols;
-        }
-        if (left >= cols) {
-          left = 0;
-        }
-        //select whole col
-        if (bottom < 0) {
-          bottom = rows;
-        }
-        if (top <= 0) {
-          top = 0;
-        }
-
-        return {
-          minCol: this._coordIndex(left, cols),
-          minRow: this._coordIndex(top, rows),
-          maxCol: this._coordIndex(right, cols),
-          maxRow: this._coordIndex(bottom, rows)
-        };
-      }
-
-    }
-  }
-})(jQuery, fabric);
\ No newline at end of file
diff --git a/dist/js/plate-map.min.js b/dist/js/plate-map.min.js
deleted file mode 100755
index e20d70f..0000000
--- a/dist/js/plate-map.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-var plateLayOutWidget=plateLayOutWidget||{};!function(u,e){plateLayOutWidget.addDataOnChange=function(){return{_addAllData:function(e){if(this.allSelectedObjects)for(var t=this.allSelectedObjects.length,i=[],a=0;a<t;a++){var n,l=this.allSelectedObjects[a];l.index in this.engine.derivative?n=this.engine.derivative[l.index]:(n=u.extend(!0,{},this.defaultWell),this.engine.derivative[l.index]=n);var s=this.processWellData(e,n,t,i);if(i=s.wells,n=s.well,this.engine.wellEmpty(n))if(this.emptyWellWithDefaultVal&&this.disableAddDeleteWell){var r=JSON.parse(JSON.stringify(n)),o=this.emptyWellWithDefaultVal;for(var d in o)d in r&&(r[d]=o[d],this._applyFieldData(d,o[d]));this.engine.derivative[l.index]=r}else delete this.engine.derivative[l.index]}this._getAllMultipleVal(i),this.applyFieldWarning(i),this._colorMixer(),this.derivativeChange()},processWellData:function(e,t,i,a){for(var n in a||(a=[]),e){var l;if(void 0!==e[n]&&null!==e[n])if(e[n].multi){var s=e[n],r=t[n],o=this._getMultiData(r,s,n,i);l=JSON.parse(JSON.stringify(o))}else l=JSON.parse(JSON.stringify(e[n]));else l=JSON.parse(JSON.stringify(e[n]));t[n]=l,a.push(t)}return{well:t,wells:a}},_getMultiData:function(e,t,i,a){var n=t.added,l=t.removed;if(n)if(e)if(n.value){var s=!0;for(var r in e){e[r][i].toString()===n.id.toString()&&(s=!1,e=e.map(function(e){if(e[i].toString()===n.id.toString())for(var t in e)t in n.value&&t!==i&&(1===a?e[t]=n.value[t]:n.value[t]&&(e[t]=n.value[t]));return e}))}s&&e.push(n.value)}else e.indexOf(n)<0&&e.push(n);else e=[],n.value?e.push(n.value):n&&e.push(n);var o,d=function(e,t){var i=[];for(var a in e)parseInt(a)!==parseInt(t)&&i.push(e[a]);return i};if(l)if(l.value){for(var r in e){e[r][i].toString()===l.id.toString()&&(o=r)}e=d(e,o)}else e&&0<=(o=e.indexOf(l))&&(e=d(e,o));return e&&0==e.length&&(e=null),e},_colorMixer:function(){if(!this.undoRedoActive){var e=this.createObject();this.addToUndoRedo(e)}this.engine.searchAndStack(),this.engine.applyColors(),this.mainFabricCanvas.renderAll()},derivativeChange:function(){this._trigger("updateWells",null,this.createObject())},createObject:function(){return{derivative:u.extend(!0,{},this.engine.derivative),checkboxes:this.globalSelectedAttributes.slice(),selectedAreas:this.selectedAreas.slice(),focalWell:this.focalWell,requiredField:this.requiredField}}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};jQuery,fabric,plateLayOutWidget.addDataToFields=function(){return{_addDataToTabFields:function(e){for(var t in e)this._applyFieldData(t,e[t])},_applyFieldData:function(e,t){this.fieldMap[e].setValue(t)}}};plateLayOutWidget=plateLayOutWidget||{};!function(u,e){plateLayOutWidget.addTabData=function(){return{fieldList:[],fieldMap:{},autoId:1,_addTabData:function(){var e=this.options.attributes.tabs,r=this;this.requiredField=[];var o=[];e.forEach(function(e,t){if(e.fields){var i=e.fields,a=[];for(var n in i){var l,s=i[n];s.id||(s.id="Auto"+r.autoId++,console.log("Field autoassigned id "+s.id)),s.type||(s.type="text",console.log("Field "+s.id+" autoassigned type "+s.type)),"multiplex"===s.type?(l=r._makeMultiplexField(s,t,a),o.push(l)):(l=r._makeRegularField(s,t,a,!0),"multiselect"===s.type&&o.push(l))}r.allDataTabs[t].fields=a}else console.log("unknown format in field initialization")}),r.multipleFieldList=o},_makeSubField:function(e,t,i){var a=this;e.id||(e.id="Auto"+a.autoId++,console.log("Field autoassigned id "+e.id)),e.type||(e.type="text",console.log("Field "+e.id+" autoassigned type "+e.type));var n=a._createElement("<div></div>").addClass("plate-setup-tab-default-field"),l=a._createElement("<div></div>").addClass("plate-setup-tab-field-left-side"),s=a._createElement("<div></div>").addClass("plate-setup-tab-field-right-side"),r=a._createElement("<div></div>").addClass("plate-setup-tab-name").text(e.name),o=a._createElement("<div></div>").addClass("plate-setup-tab-field-container");u(s).append(r),u(s).append(o),u(n).append(l),u(n).append(s),u(a.allDataTabs[t]).append(n);var d={id:e.id,name:e.name,root:n,data:e,required:e.required||!1};return i.push(d),a.fieldMap[e.id]=d},_makeRegularField:function(e,t,i,a){var n=this,l=n._createElement("<div></div>").addClass("plate-setup-tab-default-field"),s=n._createElement("<div></div>").addClass("plate-setup-tab-field-left-side"),r=n._createElement("<div></div>").addClass("plate-setup-tab-field-right-side "),o=n._createElement("<div></div>").addClass("plate-setup-tab-name").text(e.name),d=n._createElement("<div></div>").addClass("plate-setup-tab-field-container");r.append(o),r.append(d),l.append(s),l.append(r),n.allDataTabs[t].append(l);var u={id:e.id,name:e.name,root:l,data:e,required:e.required};return u.required&&n.requiredField.push(u.id),i.push(u),n.fieldList.push(u),n.fieldMap[u.id]=u,a&&n._addCheckBox(u),n._createField(u),u.onChange=function(){var e=u.getValue(),t={};t[u.id]=e,n._addAllData(t)},u},_makeMultiplexField:function(e,t,i){var a=this,n=a._createElement("<div></div>").addClass("plate-setup-tab-default-field"),l=a._createElement("<div></div>").addClass("plate-setup-tab-field-left-side"),s=a._createElement("<div></div>").addClass("plate-setup-tab-field-right-side "),r=a._createElement("<div></div>").addClass("plate-setup-tab-name").text(e.name),o=a._createElement("<div></div>").addClass("plate-setup-tab-field-container");s.append(r),s.append(o),n.append(l),n.append(s),a.allDataTabs[t].append(n);var d={id:e.id,name:e.name,root:n,data:e,required:e.required};i.push(d),a.fieldList.push(d),a.fieldMap[e.id]=d;var u=[],c=[];for(var f in e.multiplexFields){var h=e.multiplexFields[f],p=a._makeSubField(h,t,i);u.push(p),h.required&&c.push(p.id)}return(d.required||c.length)&&this.requiredField.push({multiplexId:d.id,subFields:c}),d.subFieldList=u,a._createField(d),a._addCheckBox(d),u.forEach(function(s){s.mainMultiplexField=d,i.push(s),a._createField(s),a._addCheckBox(s),delete a.defaultWell[s.id],s.onChange=function(){var t=s.getValue(),i=s.mainMultiplexField,a=i.singleSelectValue(),e={};e[i.id]=a,e[s.id]=t;var n={id:a,value:e};d._changeMultiFieldValue(n,null);var l=i.detailData;null!==l&&(a=i.singleSelectValue(),l=l.map(function(e){return e[i.id]===a&&(e[s.id]=t),e})),i.detailData=l}}),d.getValue=function(){var e=d.input.select2("data");return e.length?e.map(function(e){return e.id}):null},d}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(s,e){plateLayOutWidget.addWarningMsg=function(){return{fieldWarningMsg:function(e,t,i){var a="fieldWarning"+e.id,n=s("<span>").html(this._assets.warningImg).attr("id",a).addClass("plate-field-warning-image");if(i){if(e.root.find("#"+a).length<=0){e.root.find(".plate-setup-tab-name").text(" "+e.name),e.root.find(".plate-setup-tab-name").prepend(n);var l=s("<div/>").addClass("pop-out-text");l.text(t),e.root.find(".plate-setup-tab-name").append(l),s("#"+a).hover(function(e){l[0].style.display="flex"},function(){l.hide()})}}else 0<e.root.find("#"+a).length&&(e.root.find(".plate-setup-tab-name").text(e.name),s("#"+a).remove())},removeWarningMsg:function(e,t,i){var a="fieldWarning"+e.id,n=s("<span>").html(this._assets.warningImg).attr("id",a).addClass("plate-field-warning-image");if(i){e.root.find(".plate-setup-tab-name").append(n);var l=s("<div/>").addClass("pop-out-text");l.text(t),e.root.find(".plate-setup-tab-name").append(l),s("#"+a).hover(function(e){l[0].style.display="inline-block"},function(){l.hide()})}else s("#"+a).remove(),0<e.root.find("#"+a).length&&s("#"+a).remove()},applyFieldWarning:function(e){var i=this,a={};i.fieldList.forEach(function(e){a[e.id]=[]}),e.forEach(function(e){if(!i.engine.wellEmpty(e))for(var t in a)t in e?a[t].push(e[t]):a[t].push(null)});for(var t=0;t<i.fieldList.length;t++){var n=i.fieldList[t];if(n.applyMultiplexSubFieldColor)n.applyMultiplexSubFieldColor(a[n.id]);else if(n.required){var l=!1;a[n.id].forEach(function(e){e instanceof Array?0===e.length&&(l=!0):null===e&&(l=!0)}),i.fieldWarningMsg(n,"required field",l)}}}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(d,e){plateLayOutWidget.bottomTable=function(){return{_bottomScreen:function(){this.bottomContainer=this._createElement("<div></div>").addClass("plate-setup-bottom-container"),this.bottomTableContainer=this._createElement("<div></div>").addClass("plate-setup-bottom-table-container"),this.bottomTable=this._createElement("<table></table>").addClass("plate-setup-bottom-table"),this.bottomTableContainer.append(this.bottomTable),this.bottomContainer.append(this.bottomTableContainer),this.container.append(this.bottomContainer)},addBottomTableHeadings:function(){this.bottomRow=this._createElement("<tr></tr>");var e=this._createElement("<th></th>").text("Group");this.bottomRow.prepend(e),this.bottomTable.empty(),this.bottomTable.append(this.bottomRow),this.rowCounter=1;for(var t=0;t<this.globalSelectedAttributes.length;t++){var i=this.globalSelectedAttributes[t],a=this.fieldMap[i];e=this._createElement("<th></th>").text(a.name);this.bottomRow.append(e),this.rowCounter=this.rowCounter+1}this.adjustFieldWidth(this.bottomRow)},tileAttrText:function(e,t){var i=this.engine.derivative[e.index];return this.fieldMap[t].getText(i[t])},addBottomTableRow:function(e,i){var a=this,t=this.allTiles[i[0]],n=this._createElement("<tr></tr>"),l=this._createElement("<td></td>").addClass("plate-setup-bottom-id"),s=this._createElement("<button/>");s.addClass("plate-setup-color-text"),s.text(e),l.append(s),s.click(function(e){var t=i.map(function(e){return a.indexToAddress(e)});e.ctrlKey&&a.getSelectedAddress().forEach(function(e){t.indexOf(e)<0&&t.push(e)}),a.setSelectedWell(t),a._trigger("selectedWells",null,{selectedAddress:a.getSelectedAddress()})}),0<e&&(e=(e-1)%(this.colorPairs.length-1)+1);var r=this.colorPairs[e];l.css("background","linear-gradient(to right, "+r[0]+" , "+r[1]+")"),n.append(l);for(var o=0;o<this.globalSelectedAttributes.length;o++){var d=this.globalSelectedAttributes[o],u=this.tileAttrText(t,d),c=this._createElement("<td></td>").text(u);n.append(c)}this.bottomTable.append(n),this.adjustFieldWidth(n)},bottomForFirstTime:function(){this.addBottomTableHeadings();var e=this._createElement("<tr></tr>"),t=this.colorPairs[0],i=this._createElement("<td></td>");i.css("background","-webkit-linear-gradient(left, "+t[0]+" , "+t[1]+")"),e.append(i),this.bottomTable.append(e),this.createExportButton()},adjustFieldWidth:function(e){var t=this.rowCounter;1024<150*t&&e.css("width",152*t+"px")},downloadCSV:function(e,t){var i,a;i=new Blob([e],{type:"text/csv"}),(a=document.createElement("a")).download=t,a.href=window.URL.createObjectURL(i),a.style.display="none",document.body.appendChild(a),a.click()},exportData:function(e){var t=[],i=document.querySelectorAll("table tr"),a={},n=this.engine.stackUpWithColor,l=this.getDimensions(),s=this;for(var r in n)a[r]=n[r].map(function(e){return s.indexToAddress(e,l)});for(var o=0;o<i.length;o++){for(var d=[],u=i[o].querySelectorAll("td, th"),c=0;c<u.length;c++){var f="";if(u[c].innerText&&(f="csv"===e?'"'+u[c].innerText.replace(/"/g,'""')+'"':u[c].innerText),d.push(f),0===o&&0===c&&("csv"===e?d.push('"Location"'):"clipboard"===e&&d.push("Location")),0!==o&&0===c){var h="";a[parseInt(u[c].innerText)]&&("csv"===e?h='"'+a[parseInt(u[c].innerText)].join(",")+'"':"clipboard"===e&&(h=a[parseInt(u[c].innerText)].join(","))),d.push(h)}}"csv"===e?t.push(d.join(",")):"clipboard"===e&&t.push(d.join("\t"))}if("csv"===e)this.downloadCSV(t.join("\n"),"table.csv");else if("clipboard"===e)return t.join("\n")},createExportButton:function(){var e=this,t=d("<div>").addClass("plate-setup-bottom-control-container"),i=d("<div>").addClass("plate-setup-overlay-text-container");i.text("Color groups"),t.append(i);var a=d("<div>").addClass("plate-setup-overlay-bottom-button-container"),n=d("<button/>").addClass("plate-setup-button");function l(){n.text("Export CSV"),n[0].classList.remove("plate-setup-clicked-button"),n.addClass("plate-setup-button")}n.text("Export CSV"),a.append(n),n.click(function(){e.exportData("csv"),n.text("Exported"),n[0].classList.remove("plate-setup-button"),n.addClass("plate-setup-clicked-button"),setTimeout(l,3e3)});var s=d("<button/>").addClass("plate-setup-button");s.text("Copy To Clipboard"),a.append(s);var r=new ClipboardJS(s.get(0),{text:function(){return e.exportData("clipboard")}});function o(){s.text("Copy To Clipboard"),s[0].classList.remove("plate-setup-clicked-button"),s.addClass("plate-setup-button")}r.on("success",function(e){s.text("Copied as tab-delimited format"),s[0].classList.remove("plate-setup-button"),s.addClass("plate-setup-clicked-button"),setTimeout(o,3e3)}),r.on("error",function(e){s.text("Failed to copy table to clipboard: browser may be incompatible"),setTimeout(o,3e3)}),t.append(a),d(".plate-setup-bottom-container").prepend(t)}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(e,i){plateLayOutWidget.canvas=function(){return{allSelectedObjects:null,allPreviouslySelectedObjects:null,colorPointer:0,goldenRatio:.618033988749895,_createCanvas:function(){this.normalCanvas=this._createElement("<canvas>").attr("id","DNAcanvas"),e(this.canvasContainer).append(this.normalCanvas)},_initiateFabricCanvas:function(){var e=this.canvasContainer.width(),t=this.canvasContainer.height();this._setCanvasArea(e,t),this.mainFabricCanvas=new i.Canvas("DNAcanvas",{backgroundColor:"#f5f5f5",selection:!1,stateful:!1,hoverCursor:"pointer",renderOnAddRemove:!1}).setWidth(e).setHeight(t)}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(l,e){plateLayOutWidget.checkBox=function(){return{globalSelectedAttributes:[],_addCheckBox:function(e){var t=l("<span>").html(this._assets.dontImg).addClass("plate-setup-tab-check-box bg-light").data("clicked",!1);t.data("linkedFieldId",e.id),e.root.find(".plate-setup-tab-field-left-side").empty().append(t),this._applyCheckboxHandler(t),e.checkbox=t},_applyCheckboxHandler:function(e){var n=this;e.click(function(e,t){var i=l(this),a={};a[i.data("linkedFieldId")]=!i.data("clicked"),n.changeCheckboxes(a)})},changeSubFieldsCheckboxes:function(e,n){var l=this,s=[];return e.subFieldList.forEach(function(e){var t=e.checkbox,i=t.data("linkedFieldId"),a=t.data("clicked");i in n&&(a=Boolean(n[i])),t.data("clicked",a),a?(t.html(l._assets.doImg),s.push(e.id)):t.html(l._assets.dontImg)}),s},changeCheckboxes:function(e){for(var t=[],i={},a=0;a<this.fieldList.length;a++){var n=this.fieldList[a];if(n.checkbox){n.subFieldList&&(i[n.id]=this.changeSubFieldsCheckboxes(n,e));var l=n.checkbox,s=l.data("linkedFieldId"),r=l.data("clicked");s in e&&(r=Boolean(e[s])),l.data("clicked",r),r?(t.push(s),l.html(this._assets.doImg)):l.html(this._assets.dontImg)}}this.globalSelectedMultiplexSubfield=i,this.globalSelectedAttributes=t,this._clearPresetSelection(),this._colorMixer()},setSubFieldCheckboxes:function(e,n){var l=this,s=[];return e.subFieldList.forEach(function(e){var t=e.checkbox,i=t.data("linkedFieldId"),a=0<=n.indexOf(i);t.data("clicked",a),a?(t.html(l._assets.doImg),s.push(e.id)):t.html(l._assets.dontImg)}),s},setCheckboxes:function(e){e=e||[];for(var t=[],i={},a=0;a<this.fieldList.length;a++){var n=this.fieldList[a];if(n.checkbox){n.subFieldList&&(i[n.id]=this.setSubFieldCheckboxes(n,e));var l=n.checkbox,s=l.data("linkedFieldId"),r=0<=e.indexOf(s);l.data("clicked",r),r?(t.push(s),l.html(this._assets.doImg)):l.html(this._assets.dontImg)}}this.globalSelectedMultiplexSubfield=i,this.globalSelectedAttributes=t,this._clearPresetSelection(),this._colorMixer()}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};jQuery,fabric,plateLayOutWidget.colorManager=function(){return{colorPairs:[["#e6e6e6","#808080"],["#66e8ff","#0082c8"],["#ff7fb1","#e6194b"],["#a2ffb1","#3cb44b"],["#f784ff","#911eb4"],["#ffe897","#f58231"],["#6666ff","#0000FF"],["#ffff7f","#ffe119"],["#acffff","#46f0f0"],["#ff98ff","#f032e6"],["#ffffa2","#d2f53c"],["#ffffff","#fabebe"],["#66e6e6","#008080"],["#ffffff","#e6beff"],["#ffd48e","#aa6e28"],["#e66666","#800000"],["#ffffff","#aaffc3"],["#e6e666","#808000"],["#ffffff","#ffd8b1"],["#66a9ef","#004389"],["#ff6672","#a7000c"],["#66db72","#00750c"],["#b866db","#520075"],["#ffa966","#b64300"],["#ffff66","#c0a200"],["#6dffff","#07b1b1"],["#ff66ff","#b100a7"],["#f9ff66","#93b600"],["#ffe5e5","#bb7f7f"],["#66a7a7","#004141"],["#ffe5ff","#a77fc0"],["#d19566","#6b2f00"],["#ffffef","#c0bb89"],["#d1ffea","#6bc084"],["#a7a766","#414100"],["#ffffd8","#c09972"],["#a5ffff","#3fc1ff"],["#ffbef0","#ff588a"],["#e1fff0","#7bf38a"],["#ffc3ff","#d05df3"],["#ffffd6","#ffc170"],["#a5a5ff","#3f3fff"],["#ffffbe","#ffff58"],["#ebffff","#85ffff"],["#ffd7ff","#ff71ff"],["#a5ffff","#3fbfbf"],["#ffffcd","#e9ad67"],["#ffa5a5","#bf3f3f"],["#ffffa5","#bfbf3f"]]}};plateLayOutWidget=plateLayOutWidget||{};!function(e,u){plateLayOutWidget.createCanvasElements=function(){return{scaleFactor:1,baseSizes:{spacing:48,tile_radius:22,center_radius_complete:10,center_radius_incomplete:14,label_size:14,label_spacing:24,text_size:13,stroke:.5,gap:2},_setCanvasArea:function(e,t){this.scaleFactor=Math.min(t/(this.dimensions.rows*this.baseSizes.spacing+this.baseSizes.label_spacing),e/(this.dimensions.cols*this.baseSizes.spacing+this.baseSizes.label_spacing));var i={};for(var a in this.baseSizes)i[a]=this.baseSizes[a]*this.scaleFactor;this.sizes=i},_canvas:function(){this._fixRowAndColumn(),this._putCircles()},_fixRowAndColumn:function(){for(var e=this.dimensions.cols,t=this.dimensions.rows,i=this.sizes.spacing,a=this.sizes.label_spacing/2,n=this.sizes.label_spacing+this.sizes.spacing/2,l=this.sizes.label_size,s=a,r=n,o=1;o<=e;o++){var d=new u.IText(o.toString(),{fill:"black",originX:"center",originY:"center",fontSize:l,top:s,left:r,fontFamily:'"Roboto", Arial, sans-serif',selectable:!1,fontWeight:"400"});r+=i,this.mainFabricCanvas.add(d)}s=n,r=a;for(o=1;o<=t;o++){d=new u.IText(this.rowIndex[o-1],{fill:"black",originX:"center",originY:"center",fontSize:l,top:s,left:r,fontFamily:'"Roboto", Arial, sans-serif',selectable:!1,fontWeight:"400"});s+=i,this.mainFabricCanvas.add(d)}},_putCircles:function(){for(var e=this.dimensions.cols,t=this.dimensions.rows,i=0,a=0;a<t;a++)for(var n=0;n<e;n++){this.allTiles.length;var l=this._createTile(a,n);l.index=i++,this.allTiles.push(l),this.mainFabricCanvas.add(l.background),this.mainFabricCanvas.add(l.highlight),this.mainFabricCanvas.add(l.circle),this.mainFabricCanvas.add(l.circleCenter),this.mainFabricCanvas.add(l.circleText)}this._addLargeRectangleOverlay(),this._fabricEvents()},_createTile:function(e,t){var i={visible:!1,colorIndex:null};i.row=e,i.col=t,i.address=this.rowIndex[e]+(t+1);var a=(e+1)*this.sizes.spacing,n=(t+1)*this.sizes.spacing;return i.background=new u.Circle({top:a,left:n,radius:this.sizes.tile_radius,originX:"center",originY:"center",hasControls:!1,hasBorders:!1,lockMovementX:!0,lockMovementY:!0,evented:!1}),i.background.setGradient("fill",{type:"radial",x1:this.sizes.tile_radius,x2:this.sizes.tile_radius,y1:this.sizes.tile_radius+this.sizes.gap,y2:this.sizes.tile_radius+this.sizes.gap,r1:this.sizes.tile_radius-this.sizes.gap,r2:this.sizes.tile_radius,colorStops:{0:"rgba(0,0,0,0.1)",1:"rgba(0,0,0,0.2)"}}),i.highlight=new u.Rect({originX:"center",originY:"center",top:a,left:n,width:this.sizes.spacing,height:this.sizes.spacing,fill:"rgba(0,0,0,0.4)",evented:!1,visible:!1}),i.circle=new u.Circle({originX:"center",originY:"center",top:a,left:n,radius:this.sizes.tile_radius,stroke:"gray",strokeWidth:this.sizes.stroke,evented:!1,visible:!1}),i.circleCenter=new u.Circle({originX:"center",originY:"center",top:a,left:n,radius:this.sizes.center_radius_incomplete,fill:"white",stroke:"gray",strokeWidth:this.sizes.stroke,evented:!1,visible:!1}),i.circleText=new u.IText("",{originX:"center",originY:"center",top:a,left:n,fill:"black",fontFamily:'"Roboto", Arial, sans-serif',fontSize:this.sizes.text_size,lockScalingX:!0,lockScalingY:!0,evented:!1,visible:!1}),i},setTileComplete:function(e,t){e.circleText.fontWeight=t?(e.circleCenter.radius=this.sizes.center_radius_complete,e.circleText.fill="black","normal"):(e.circleCenter.radius=this.sizes.center_radius_incomplete,e.circleText.fill="red","bold")},setTileVisible:function(e,t){e.visible=t,e.circle.visible=e.visible,e.circleCenter.visible=e.visible,e.circleText.visible=e.visible},setTileColor:function(e,t,i){this.setTileVisible(e,!0),e.colorIndex=parseInt(t),e.circleText.text=String(e.colorIndex),0<t&&(t=(t-1)%(this.colorPairs.length-1)+1);var a=this.colorPairs[t];e.circle.setGradient("fill",{y2:2*this.sizes.tile_radius,colorStops:a})},_addLargeRectangleOverlay:function(){this.overLay=new u.Rect({width:632,height:482,left:0,top:0,opacity:0,originX:"left",originY:"top",lockMovementY:!0,lockMovementX:!0,selectable:!1}),this.mainFabricCanvas.add(this.overLay)}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(f,e){plateLayOutWidget.createField=function(){return{_createField:function(e){switch(e.data.type){case"text":this._createTextField(e);break;case"numeric":this._createNumericField(e);break;case"select":this._createSelectField(e);break;case"multiselect":this._createMultiSelectField(e);break;case"boolean":this._createBooleanField(e);break;case"multiplex":this._createMultiplexField(e)}},_createTextField:function(i){var e=i.id,t=this._createElement("<input>").attr("id",e).addClass("plate-setup-tab-input");i.root.find(".plate-setup-tab-field-container").append(t),this.defaultWell[e]=null,i.parseValue=function(e){return e=e?String(e):null},i.getValue=function(){var e=t.val().trim();return""==e&&(e=null),e},i.setValue=function(e){t.val(e)},i.getText=function(e){return null==e?"":e},i.disabled=function(e){i.input.prop("disabled",e)},i.parseText=i.parseValue,t.on("input",function(e,t){i.onChange()}),i.input=t},_createOpts:function(e){var t={allowClear:!0,placeholder:"select",minimumResultsForSearch:10};if(e.options)t.data=e.options;else{if(!e.query)throw"Must specify data or query";var i=e.query;e.delay&&(i=this._debounce(e.delay,i)),t.query=i}return t},_createSelectField:function(i){var a=i.id,t=this._createElement("<input/>").attr("id",a).addClass("plate-setup-tab-select-field");i.root.find(".plate-setup-tab-field-container").append(t),this.defaultWell[a]=null;var n=this._createOpts(i.data),l={};n.data.forEach(function(e){l[e.id]=e}),t.select2(n),i.parseValue=function(e){var t=e;if(""==t&&(t=null),null==t)return null;if(t in l)return l[t].id;throw"Invalid value "+e+" for select field "+a},i.disabled=function(e){i.input.prop("disabled",e)},i.getValue=function(){var e=t.select2("data");return e?e.id:null},i.setValue=function(e){e&&(e=l[e]),t.select2("data",e)},i.setOpts=function(e){t.select2("data",{}),n.data=e||[],t.select2(n)},i.getText=function(e){return null==e?"":l[e].text},i.parseText=function(e){var t=e;if(""==t&&(t=null),null==t)return null;if(t in l)return l[t].text;throw"Invalid text value "+e+" for select field "+a},t.on("change",function(e,t){i.onChange()}),i.input=t},_createMultiSelectField:function(l){var i=l.id,a=this,s=this._createElement("<input/>").attr("id",i).addClass("plate-setup-tab-multiselect-field");s.attr("multiple","multiple"),l.root.find(".plate-setup-tab-field-container").append(s),a.defaultWell[i]=null;var r=a._createOpts(l.data);r.multiple=!0;var n={};r.data.forEach(function(e){n[e.id]=e}),s.select2(r),l.disabled=function(e){l.input.prop("disabled",e)},l.parseValue=function(e){var t=e;return t=t&&t.length?t.map(function(e){if(e in n)return n[e].id;throw"Invalid value "+e+" for multiselect field "+i}):null},l.setOpts=function(e){var t=l.data.options,i=[];for(var a in t){var n=t[a];0<=e.indexOf(n.id)&&i.push(n)}r.data=i,s.select2(r)},l.getValue=function(){var e=s.select2("data");return e.length?e.map(function(e){return e.id}):null},l.setValue=function(e){e=(e=e||[]).map(function(e){return n[e]}),s.select2("data",e)},l.getText=function(e){return null==e?"":0<e.length?e.map(function(e){return n[e].text}).join("; "):""},l.multiOnChange=function(e,t){e&&(e=e.id.toString()),t&&(t=t.id.toString());var i={};i[l.id]={multi:!0,added:e,removed:t},a._addAllData(i)},l.parseText=function(e){var t=e;return t=t&&t.length?t.map(function(e){if(e in n)return n[e].text;throw"Invalid text value "+e+" for multiselect field "+i}):null},s.on("change",function(e,t){var i=e.added,a=e.removed;l.multiOnChange(i,a)}),l.input=s,a._createDeleteButton(l)},_createNumericField:function(n){var i=n.id,e=n.data,t=this._createElement("<input>").addClass("plate-setup-tab-input").attr("placeholder",e.placeholder||"").attr("id",i);n.root.find(".plate-setup-tab-field-container").append(t),this.defaultWell[i]=null;var a=e.units||[],l=e.defaultUnit||null,s=null;if(l?a.length?a.indexOf(l)<0&&(l=a[0]):a=[l]:a.length&&(l=a[0]),a.length)if(n.units=a,n.hasUnits=!0,n.defaultUnit=l,1==a.length){var r=f("<div></div>").addClass("plate-setup-tab-unit");r.text(l),n.root.find(".plate-setup-tab-field-container").append(r)}else{s=this._createElement("<input/>").attr("id",i).addClass("plate-setup-tab-label-select-field"),n.root.find(".plate-setup-tab-field-container").append(s);var o=null,d={data:a.map(function(e){var t={id:e,text:e};return e==l&&(o=t),t}),allowClear:!1,minimumResultsForSearch:10};s.select2(d),s.select2("data",o)}n.disabled=function(e){n.input.prop("disabled",e),s&&s.prop("disabled",e)},n.setUnitOpts=function(e){n.units=e||null;var t=[],i=n.defaultUnit=null;n.units&&n.units.length&&(n.defaultUnit=n.units[0],t=n.units.map(function(e){var t={id:e,text:e};return e==n.defaultUnit&&(i=t),t}));var a={data:t,allowClear:!1,minimumResultsForSearch:10};s.select2(a),s.select2("data",i)},n.parseValue=function(e){var t;if(f.isPlainObject(e)){if(n.hasUnits)return null===(t=n.parseRegularValue(e.value))?null:{value:t,unit:n.parseUnit(e.unit)};throw"Value must be plain numeric for numeric field "+i}return n.hasUnits?null===(t=n.parseRegularValue(e))?null:{value:t,unit:n.defaultUnit}:n.parseRegularValue(e)},n.getValue=function(){var e=n.getRegularValue();if(null===e||isNaN(e))return null;if(n.hasUnits){var t={value:e,unit:n.getUnit()};if(n.data.hasMultiplexUnit)for(var i in n.data.unitMap){n.data.unitMap[i].forEach(function(e){e.text===t.unit&&(t.unitTypeId=i,t.unitId=e.id)})}return t}return e},n.setValue=function(e){n.hasUnits?f.isPlainObject(e)?(n.setUnit(e.unit||n.defaultUnit),n.setRegularValue(e.value)):(n.setRegularValue(e),n.setUnit(n.defaultUnit)):n.setRegularValue(e)},n.parseRegularValue=function(e){if(null==e)return null;var t=String(e).trim();if(""===t)return null;if(t=Number(e),isNaN(t))throw"Invalid value "+e+" for numeric field "+i;return t},n.getRegularValue=function(){var e=t.val().trim();return e=""==e?null:Number(e)},n.setRegularValue=function(e){t.val(e)},n.parseUnit=function(e){if(null==e||""===e)return n.defaultUnit;for(var t=0;t<a.length;t++)if(e.toLowerCase()==a[t].toLowerCase())return a[t];throw"Invalid unit "+e+" for field "+i},n.getUnit=function(){return s?s.val():n.defaultUnit},n.setUnit=function(e){s&&(null!=(e=e||n.defaultUnit)&&(e={id:e,text:e}),s.select2("data",e))},n.getText=function(e){if("object"==typeof e&&e){var t=e.value,i=e.unit;return null==t?"":(t=t.toString(),i||(i=l),i&&(t=t+" "+i),t)}return n.getRegularText(e)},n.getRegularText=function(e){return null==e?"":e=e.toString()},n.parseText=function(e){var t=n.parseValue(e);return t&&"object"==typeof t?t.value+t.unit:t||null},t.on("input",function(){var e=n.getRegularValue();isNaN(e)?t.addClass("invalid"):t.removeClass("invalid"),n.onChange()}),s&&s.on("change",function(){n.onChange()}),n.input=t,n.unitInput=s},_createBooleanField:function(t){var i=t.id,a=this._createElement("<input/>").attr("id",i).addClass("plate-setup-tab-select-field");this.defaultWell[i]=null,t.root.find(".plate-setup-tab-field-container").append(a);var n={id:"true",text:"true"},l={id:"false",text:"false"},e={data:[n,l],placeholder:"select",allowClear:!0,minimumResultsForSearch:-1,initSelection:function(e,t){var i=e.val();t({id:i,text:i})}};a.select2(e),t.disabled=function(e){t.input.prop("disabled",e)},t.parseValue=function(e){if(null==e)return null;var t=String(e).trim().toLowerCase();if("true"==t)t=!0;else if("false"==t)t=!1;else{if(""!=t)throw"Invalid value "+e+" for boolean field "+i;t=null}return t},t.getValue=function(){switch(a.val()){case"true":return!0;case"false":return!1;default:return null}},t.setValue=function(e){e=1==e||"true"==e?n:0==e||"false"==e?l:null,a.select2("data",e)},t.getText=function(e){return null==e?"":e.toString()},t.parseText=t.parseValue,a.on("change",function(e){t.onChange()}),t.input=a},_createMultiplexField:function(o){var d=this;this._createMultiSelectField(o),d.defaultWell[o.id]=[];var e=d._createElement("<div></div>").addClass("plate-setup-tab-name-singleSelect").text("Select to edit"),t=d._createElement("<div></div>").addClass("plate-setup-tab-field-container-singleSelect");o.root.find(".plate-setup-tab-field-right-side").append(e,t),o.singleSelect=this._createElement("<input/>").attr("id",o.id+"SingleSelect").addClass("plate-setup-tab-multiplex-single-select-field"),o.singleSelect.appendTo(t),o.singleSelectValue=function(){var e=o.singleSelect.select2("data");return null!=e&&(e=e.id),e};var u=function(e,t){var i={allowClear:!1,placeholder:"select",minimumResultsForSearch:10,data:e||[]};t||(t=i.data.length?i.data[0]:null),o.singleSelect.select2("data",[]),o.singleSelect.select2(i),o.singleSelect.select2("data",t),o.singleSelect.prop("disabled",0==i.data.length)},c=function(){var t=o.singleSelectValue();o.updateSubFieldUnitOpts(t);var e=o.detailData||[],i=null;e.forEach(function(e){e[o.id]===t&&(i=e)}),i?o.subFieldList.forEach(function(e){e.disabled(!1),e.setValue(i[e.id])}):o.subFieldList.forEach(function(e){e.disabled(!0),e.setValue(null)}),d.readOnlyHandler()};u([]),o.singleSelect.on("change",c),o._changeMultiFieldValue=function(e,t){var i,a={};for(var n in o.data.multiplexFields){a[o.data.multiplexFields[n].id]=null}e&&(i=e.value?e.value:(a[o.id]=e.id,a),e={id:e.id,value:i}),t&&(i=t.value?t.value:(a[o.id]=t.id,a),t={id:t.id,value:i});var l={};l[o.id]={multi:!0,added:e,removed:t},d._addAllData(l)};var a=o.setValue;o.setValue=function(e){var t=null;(o.detailData=e)&&e.length&&(t=e.map(function(e){return e[o.id]})),a(t);var i=o.input.select2("data")||[];u(i),c()},o.disabled=function(t){o.input.prop("disabled",t),o.subFieldList.forEach(function(e){e.disabled(t)}),t?e.text("Select to inspect"):e.text("Select to edit")},o.parseValue=function(e){var t=e;return t=t&&t.length?t.map(function(t){var i={};for(var a in i[o.id]=t[o.id],t)o.subFieldList.forEach(function(e){e.id===a&&(i[e.id]=e.parseValue(t[a]))});return i}):null},o.updateSubFieldUnitOpts=function(t){var i;o.data.options.forEach(function(e){e.id===t&&(i=e)}),o.subFieldList.forEach(function(e){e.data.hasMultiplexUnit&&(i&&i.hasOwnProperty("unitOptions")?e.setUnitOpts(i.unitOptions[e.id]):e.setUnitOpts(null))})},o.multiOnChange=function(e,t){o._changeMultiFieldValue(e,t);var i=o.getValue(),l=o.detailData,s=[],a=null;l&&(s=l.map(function(e){return e[o.id]}));var r=[],n=[];i&&(i.forEach(function(a){if(l&&l.forEach(function(e){e[o.id]===a&&r.push(e)}),s.indexOf(a)<0){var n={};n[o.id]=a,o.updateSubFieldUnitOpts(a),o.subFieldList.forEach(function(i){if(i.hasUnits)if(i.data.hasMultiplexUnit)i.disabled(!1),o.data.options.forEach(function(e){if(e.id===a){var t={value:null,unit:i.units[0]};n[i.id]=i.parseValue(t)}});else{i.data.units&&1<i.data.units.length&&i.disabled(!1);var e={value:null,unit:i.defaultUnit};n[i.id]=i.parseValue(e)}else n[i.id]=i.parseValue(null)}),r.push(n)}}),i.forEach(function(t){o.data.options.forEach(function(e){e.id===t&&n.push(e)})}),a=n[i.length-1]),o.detailData=r,u(n,a),c()},o.getText=function(e){if(null===e)return"";if(o.id in d.globalSelectedMultiplexSubfield){var i=d.globalSelectedMultiplexSubfield[o.id],t=[];for(var a in e){var n=e[a],l=[];for(var s in o.data.options){var r=o.data.options[s];r.id===n[o.id]&&l.push(r.text)}o.subFieldList.forEach(function(e){if(0<=i.indexOf(e.id)){var t=e.getText(n[e.id]);l.push(e.name+": "+t)}}),t.push("{"+l.join(", ")+"}")}return t.join(";")}},o.parseText=function(e){if(null===e)return"";var t=[];for(var i in e){var a=e[i],n=[];for(var l in o.data.options){var s=o.data.options[l];s.id===a[o.id]&&n.push(s.text)}o.subFieldList.forEach(function(e){var t=e.getText(a[e.id]);t&&n.push(t)}),t.push(n)}return t},o.checkMultiplexCompletion=function(e){var t=0,i=0,s=!1;function a(e){var t=0,i=0;for(var a in o.subFieldList){var n=o.subFieldList[a],l=e[n.id];n.required&&(s=!0,t++,"object"==typeof l&&l?l.value&&i++:l&&i++)}return i/t}if(e)if(0<e.length)for(var n in e){t++,i+=a(e[n])}else o.required&&(s=!0,t=1);else o.required&&(s=!0,t=1);return{include:s,completionPct:i/t}},o.applyMultiplexSubFieldColor=function(e){var l={};o.subFieldList.forEach(function(e){e.required&&(l[e.id]={field:e,warningStatus:[]})}),e.forEach(function(e){!function(e){for(var t in o.subFieldList){var i=o.subFieldList[t];if(null===e)o.required&&i.required&&l[i.id].warningStatus.push(!0);else if("object"==typeof e)if(0===e.length)o.required&&i.required&&l[i.id].warningStatus.push(!0);else for(var a in e){var n=e[a][i.id];i.required&&("object"==typeof n&&n?n.value?l[i.id].warningStatus.push(!1):l[i.id].warningStatus.push(!0):n?l[i.id].warningStatus.push(!1):l[i.id].warningStatus.push(!0))}}}(e)});var t=[];for(var i in l){var a=l[i].field;if(0<=l[i].warningStatus.indexOf(!0)){var n=a.name+" is a required subfield for "+o.name+", please make sure all "+o.name+" have "+a.name;o.required,d.fieldWarningMsg(a,n,!0),t.push(!0)}else d.fieldWarningMsg(a,"none",!1),t.push(!1)}var s,r=!1;r=!(t.indexOf(!0)<0),s=o.required?o.name+" is a required field, please also fix missing required subfield(s) below":o.name+" is not a required field, please fix missing required subfield(s) below or remove selected "+o.name,d.fieldWarningMsg(o,s,r)},o.parseMainFieldVal=function(e){for(var t=o.data.options,i=0;i<t.length;i++){var a=t[i];if(a.id===e)return a.text}}},_deleteDialog:function(t){var e,i=this,a=t.allSelectedMultipleVal;e=a?Object.keys(a):[];var n=f("<div/>").addClass("delete-dialog modal");function l(){n.hide(),n.remove()}f("body").append(n);var s=f("<div/>").addClass("modal-content").appendTo(n),r=f("<div/>").appendTo(s),o=f("<div/>").addClass("dialog-buttons").css("justify-content","flex-end").appendTo(s);if(0<e.length){f("<p/>").text(t.name+" in selected wells: choose items to delete and click the delete button below").appendTo(r);var d=i._deleteDialogTable(t,a);if(d.appendTo(r),d.addClass("plate-popout-table"),d.find("td").addClass("plate-popout-td"),d.find("th").addClass("plate-popout-th"),d.find("tr").addClass("plate-popout-tr"),!i.readOnly){var u=f("<button class='multiple-field-manage-delete-button'>Delete Checked Items</button>");o.append(u),u.click(function(){d.find("input:checked").each(function(){var e=this.value;t.multiOnChange(null,{id:e})}),i.decideSelectedFields(),l()})}}else f("<p/>").text("No "+t.name+" in the selected wells").appendTo(r);var c=f("<button>Cancel</button>");o.append(c),c.click(l),n.show(),window.onclick=function(e){e.target==n[0]&&l()}},_deleteDialogTable:function(e,a){var n=this,t=[e.name,"Counts"];n.readOnly||t.push("Delete");var i=f("<table/>"),l=f("<thead/>").appendTo(i);f("<tr/>").appendTo(l).append(t.map(function(e){return f("<th/>").text(e)}));var s=f("<tbody/>").appendTo(i);return e.data.options.forEach(function(e){if(e.id in a){var t=f("<tr/>").appendTo(s),i=f("<input type='checkbox'>").prop("value",e.id);f("<td/>").text(e.text).appendTo(t),f("<td/>").text(a[e.id]).appendTo(t),n.readOnly||f("<td/>").append(i).appendTo(t)}}),i},_createDeleteButton:function(e){var t=this,i=f("<button/>").addClass("plate-setup-remove-all-button");i.id=e.id+"Delete",i.text("Manage "+e.name+"...");var a=t._createElement("<div></div>").addClass("plate-setup-remove-all-button-container");a.append(i),e.deleteButton=i,e.root.find(".plate-setup-tab-field-right-side").append(a),i.click(function(){t._deleteDialog(e)})}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(b,e){plateLayOutWidget.engine=function(v){return{engine:{derivative:{},stackUpWithColor:{},stackPointer:2,wellEmpty:function(e){for(var t in e){var i=e[t];if(null!=i){if(!Array.isArray(i))return!1;if(0<i.length)return!1}}return!0},searchAndStack:function(){this.stackUpWithColor={},this.stackPointer=1;var e={};for(var t in this.derivative){for(var i=this.derivative[t],a={},n=0;n<v.globalSelectedAttributes.length;n++){var l=v.globalSelectedAttributes[n];if(l in v.globalSelectedMultiplexSubfield){var s=v.globalSelectedMultiplexSubfield[l],r=[];for(var o in i[l]){var d=i[l][o],u={};u[l]=d[l],s.forEach(function(e){u[e]=d[e]}),r.push(u)}a[l]=r}else null!=i[l]&&(a[l]=i[l])}b.isEmptyObject(a)?e[t]=null:e[t]=JSON.stringify(a)}for(;!b.isEmptyObject(e);){var c=Object.keys(e).map(function(e){return parseFloat(e,10)});c.sort(function(e,t){return e-t});var f=c[0],h=e[f],p=[];if(h){for(n=0;n<c.length;n++){h==e[t=c[n]]&&(p.push(t),this.stackUpWithColor[this.stackPointer]=p,delete e[t])}0<p.length&&this.stackPointer++}else this.stackUpWithColor[0]?this.stackUpWithColor[0].push(f):this.stackUpWithColor[0]=[f],delete e[f]}},applyColors:function(){var e=0,t=0;v.addBottomTableHeadings();for(var i=0;i<v.allTiles.length;i++){var a=v.allTiles[i];v.setTileVisible(a,!1)}for(var n=0;n<this.stackPointer;n++){var l=this.stackUpWithColor[n];if(l)for(var s in v.addBottomTableRow(n,l),l){e++;var r=this.stackUpWithColor[n][s],o=(a=v.allTiles[r],this.derivative[r]);v.setTileColor(a,n,this.stackPointer);var d=this.checkCompletion(o,a);v.setTileComplete(a,1==d),t+=d}}t=Math.floor(100*t/e),isNaN(t)?v.overLayTextContainer.text("Completion Percentage: 0%"):v.overLayTextContainer.text("Completion Percentage: "+t+"%")},checkCompletion:function(e,t){for(var i=0,a=0,n=0;n<v.fieldList.length;n++){var l=v.fieldList[n];if(l.checkMultiplexCompletion){var s=l.checkMultiplexCompletion(e[l.id]);s.include&&(a+=s.completionPct,i++)}else l.required&&(i++,null!==e[l.id]&&a++)}return i===a?1:a/i}}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(u,n){plateLayOutWidget.fabricEvents=function(){return{colorToIndex:{},startCoords:{x:0,y:0},focalWell:{row:0,col:0},selectedAreas:[],_clickCoords:function(e){var t=e.e.target.getBoundingClientRect();return{x:e.e.clientX-t.left,y:e.e.clientY-t.top}},_fabricEvents:function(){var s=this;u(s.target).on("getPlates",function(e,t){s.getPlates(JSON.parse(t))}),s.mainFabricCanvas.on("mouse:down",function(e){s.selecting=!0;var t=s._clickCoords(e),i=s.selectedAreas.slice(),a=s.focalWell,n=s._wellToCoords(a,!0),l=s._coordsToRect(n,t);e.e.ctrlKey?(n=t,l=s._coordsToRect(n,t),a=s._coordsToWell(n),e.e.shiftKey?i=[s._rectToArea(l)]:i.push(s._rectToArea(l))):e.e.shiftKey?i[i.length-1]=s._rectToArea(l):(n=t,l=s._coordsToRect(n,t),a=s._coordsToWell(n),i=[s._rectToArea(l)]),s.startCoords=n,s.setSelection(i,a),s.mainFabricCanvas.renderAll()}),s.mainFabricCanvas.on("mouse:move",function(e){if(s.selecting){var t=s.selectedAreas.slice(),i=s._clickCoords(e),a=s._coordsToRect(s.startCoords,i),n=s._rectToArea(a);n&&(t[t.length-1]=n),s.setSelection(t,s.focalWell),s.mainFabricCanvas.renderAll()}}),s.mainFabricCanvas.on("mouse:up",function(e){s.selecting=!1;var t=s.selectedAreas.slice(),i=s._clickCoords(e),a=s._coordsToRect(s.startCoords,i),n=s._rectToArea(a);n&&(t[t.length-1]=n),s.setSelection(t,s.focalWell),s.decideSelectedFields(),s.mainFabricCanvas.renderAll(),s._trigger("selectedWells",null,{selectedAddress:s.getSelectedAddress()})})},setSelection:function(e,t){this.selectedAreas=e,this.focalWell=t,this.allSelectedObjects=this._areasToTiles(e),this._setSelectedTiles(),this._setFocalWellRect(this.focalWell),document.activeElement.blur()},_setFocalWellRect:function(e){var t;if(this.disableAddDeleteWell){var i=this.locToAddress({r:e.row,c:e.col});this.addressAllowToEdit.indexOf(i)<0?(t=!1,this.setFieldsDisabled(!0)):(t=!0,this.setFieldsDisabled(!1))}else e&&(t=!0);if(t){var a=this._areaToRect(this._wellToArea(e));this.focalWellRect?(this.focalWellRect.top=a.top,this.focalWellRect.left=a.left,this.focalWellRect.width=a.width-2,this.focalWellRect.height=a.height-2):(this.focalWellRect=new n.Rect({width:a.width-2,height:a.height-2,left:a.left,top:a.top,fill:null,strokeWidth:2,stroke:"black",selectable:!1}),this.mainFabricCanvas.add(this.focalWellRect))}else this.mainFabricCanvas.remove(this.focalWellRect),this.focalWellRect=null},_setSelectedTiles:function(){var i=this.allSelectedObjects;this.allTiles.forEach(function(e){var t=0<=i.indexOf(e);e.highlight.visible=t})},_getSelectedWells:function(){var i=this;return this.allSelectedObjects.map(function(e){var t=i.engine.derivative[e.index];return t||(t=i.defaultWell),t})},_getCommonFields:function(e){if(e.length){for(var t=e[0],i=u.extend(!0,{},t),a=1;a<e.length;a++){var n=e[a];for(var l in i)if(Array.isArray(i[l])){for(var s=i[l],r=[],o=0;o<s.length;o++){var d=s[o];d&&"object"==typeof d?this.containsObject(d,n[l])&&r.push(d):0<=u.inArray(d,n[l])&&r.push(d)}i[l]=r}else n[l]&&"object"==typeof n[l]&&i[l]&&"object"==typeof i[l]?n[l].value===i[l].value&&n[l].unit===i[l].unit||delete i[l]:i[l]!=n[l]&&delete i[l]}return i}return{}},containsObject:function(n,e){var t=[];return!!e&&(e.forEach(function(i){var a=[];Object.keys(i).forEach(function(e){if(0<=Object.keys(n).indexOf(e)){var t=i[e];"object"==typeof t&&t?n[e]?a.push(t.unit===n[e].unit&&t.value===n[e].value):a.push(!1):a.push(t===n[e])}}),t.push(a.indexOf(!1)<0)}),0<=t.indexOf(!0))},_getCommonWell:function(e){if(e.length){for(var t=e[0],i=u.extend(!0,{},t),a=1;a<e.length;a++){var n=e[a];for(var l in i)if(Array.isArray(i[l])){for(var s=i[l],r=[],o=0;o<s.length;o++){var d=s[o];"object"==typeof s[o]?this.containsObject(d,n[l])&&r.push(d):0<=u.inArray(d,n[l])&&r.push(d)}i[l]=r}else n[l]&&"object"==typeof n[l]&&i[l]&&"object"==typeof i[l]?n[l].value===i[l].value&&n[l].unit===i[l].unit||(i[l]=null):i[l]!=n[l]&&(i[l]=null)}return i}return this.defaultWell},_getAllMultipleVal:function(e){this.multipleFieldList.forEach(function(i){if(e.length){var a={};e.forEach(function(e){var t=i.id;e[t]&&0<e[t].length&&e[t].forEach(function(e){"object"==typeof e?e[t]in a?a[e[t]]++:a[e[t]]=1:e in a?a[e]++:a[e]=1})}),i.allSelectedMultipleVal=a}else i.allSelectedMultipleVal=null})},decideSelectedFields:function(){var e=this._getSelectedWells();this._getAllMultipleVal(e),this.applyFieldWarning(e);var t=this._getCommonWell(e);this._addDataToTabFields(t)},getDifferentWellsVals:function(e){var t=[];for(var i in e)t.push(e[i]);var a={};if(1<t.length){var n=this._getCommonWell(t),l={};for(var s in e[0])l[s]=[];for(var r in t){var o={},d=t[r];for(var u in d){var c=n[u],f=d[u],h=null;if(Array.isArray(f)){h=[];for(var p=0;p<f.length;p++){var v=f[p];v?this.containsObject(v,c)||(h.push(v),this.containsObject(v,l[u])||l[u].push(v)):0<=c.indexOf(v)&&(h.push(v),0<=!l[u].indexOf(v)&&l[u].push(v))}}else f&&"object"==typeof f?c&&"object"==typeof c?f.value!==c.value&&f.unit!==c.unit&&(h=f,this.containsObject(f,l[u])||l[u].push(f)):(h=f,this.containsObject(f,l[u])||l[u].push(f)):f!==c&&(h=f,0<=!l[u].indexOf(f)&&l[u].push(f));o[u]=h}a[r]=o}for(var u in l)if(0===l[u].length)for(var r in a)delete a[r][u];return a}if(e[0]){var b={};for(var u in e[0]){f=e[0][u];Array.isArray(f)?0<f.length&&(b[u]=f):f&&(b[u]=f)}return{0:b}}},getWellSetAddressWithData:function(){var e=[],t=this.engine.derivative;for(var i in t)e.push(this.indexToAddress(i));return e}}}}(jQuery,fabric),(plateLayOutWidget=plateLayOutWidget||{}).assets=function(){return{_assets:{doImg:"&#10003;",dontImg:"",warningImg:"&#9888;"}}};plateLayOutWidget=plateLayOutWidget||{};!function(i,e){plateLayOutWidget.interface=function(){return{_createInterface:function(){var e="<div></div>";this.container=this._createElement(e).addClass("plate-setup-wrapper"),this.topSection=this._createElement(e).addClass("plate-setup-top-section"),this.topLeft=this._createElement(e).addClass("plate-setup-top-left"),this.topRight=this._createElement(e).addClass("plate-setup-top-right"),this.overLayContainer=this._createElement(e).addClass("plate-setup-overlay-container"),this.canvasContainer=this._createElement(e).addClass("plate-setup-canvas-container"),this._createOverLay(),i(this.topLeft).append(this.overLayContainer),this._createCanvas(),i(this.topLeft).append(this.canvasContainer),i(this.topSection).append(this.topLeft),i(this.topSection).append(this.topRight),i(this.container).append(this.topSection),i(this.element).append(this.container),this._initiateFabricCanvas(),this._createTabAtRight(),this._createTabs(),this._placePresetTabs(),this._bottomScreen(),this._canvas(),this.bottomForFirstTime();var t=this;this._setShortcuts(),i(document.body).keyup(function(e){t._handleShortcuts(e)}),this._configureUndoRedoArray()},_createElement:function(e){return i(e)},_setShortcuts:function(){var t=this;window.addEventListener("cut",function(e){document.activeElement==document.body&&(t.copyCriteria(),t.clearCriteria(),e.preventDefault())}),window.addEventListener("copy",function(e){document.activeElement==document.body&&(t.copyCriteria(),e.preventDefault())}),window.addEventListener("paste",function(e){document.activeElement==document.body&&(t.pasteCriteria(),e.preventDefault())})},_handleShortcuts:function(e){document.activeElement===document.body&&(46==e.keyCode?(this.clearCriteria(),e.preventDefault()):(e.ctrlKey||e.metaKey)&&(90==e.keyCode?(e.shiftKey?this.redo():this.undo(),e.preventDefault()):89==e.keyCode&&(this.redo(),e.preventDefault())))}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(t,e){plateLayOutWidget.loadPlate=function(e){return{getPlates:function(e){var t={};for(var i in e.derivative){var a=e.derivative[i];t[i]=this.sanitizeWell(a)}var n=e.checkboxes||[],l=this.sanitizeAreas(e.selectedAreas,e.focalWell),s={derivative:t,checkboxes:n,selectedAreas:l.selectedAreas,focalWell:l.focalWell};this.setData(s)},sanitizeAreas:function(e,t){var i=this,a=this.dimensions.rows,n=this.dimensions.cols;if(e||(e=[]),e.length){var l=(e=e.map(function(e){return{minCol:i._coordIndex(Math.min(e.minCol,e.maxCol),n),minRow:i._coordIndex(Math.min(e.minRow,e.maxRow),a),maxCol:i._coordIndex(Math.max(e.minCol,e.maxCol),n),maxRow:i._coordIndex(Math.max(e.minRow,e.maxRow),a)}}))[e.length-1];t&&!this._wellInArea(t,l)&&(t=null),t||(t={row:l.minRow,col:l.minCol})}else t||(t={row:0,col:0}),e=[this._wellToArea(t)];return{selectedAreas:e,focalWell:t}},sanitizeWell:function(e){for(var t={},i=0;i<this.fieldList.length;i++){var a=this.fieldList[i];t[a.id]=a.parseValue(e[a.id])}return t},setData:function(e){this.engine.derivative=t.extend(!0,{},e.derivative),this.setCheckboxes(e.checkboxes),this.setSelection(e.selectedAreas,e.focalWell),this._colorMixer(),this.decideSelectedFields(),this.mainFabricCanvas.renderAll()}}}}(jQuery,fabric);var GET_PLATES="getPlates",IS_READ_ONLY="isReadOnly",IS_DISABLE_ADD_DELETE_WELL="isDisableAddDeleteWell",GET_SELECTED_OBJECT="getSelectedObject",SETSELECTEDWELL="setSelectedWell";plateLayOutWidget=plateLayOutWidget||{};jQuery,fabric,plateLayOutWidget.overlay=function(){return{_createOverLay:function(){var t=this;this.overLayTextContainer=this._createElement("<div></div>").addClass("plate-setup-overlay-text-container"),this.overLayTextContainer.text("Completion Percentage:"),this.overLayContainer.append(this.overLayTextContainer),this.overLayButtonContainer=this._createElement("<div></div>").addClass("plate-setup-overlay-button-container"),this.overLayContainer.append(this.overLayButtonContainer),this.clearCriteriaButton=this._createElement("<button />").addClass("plate-setup-button"),this.clearCriteriaButton.text("Clear"),this.overLayButtonContainer.append(this.clearCriteriaButton),this.clearCriteriaButton.click(function(e){t.clearCriteria()}),this.copyCriteriaButton=this._createElement("<button />").addClass("plate-setup-button"),this.copyCriteriaButton.text("Copy"),this.overLayButtonContainer.append(this.copyCriteriaButton),this.copyCriteriaButton.click(function(e){t.copyCriteria()}),this.pasteCriteriaButton=this._createElement("<button />").addClass("plate-setup-button"),this.pasteCriteriaButton.text("Paste"),this.overLayButtonContainer.append(this.pasteCriteriaButton),this.pasteCriteriaButton.click(function(e){t.pasteCriteria()}),this.undoButton=this._createElement("<button />").addClass("plate-setup-button"),this.undoButton.text("Undo"),this.overLayButtonContainer.append(this.undoButton),this.undoButton.click(function(e){t.undo()}),this.redoButton=this._createElement("<button />").addClass("plate-setup-button"),this.redoButton.text("Redo"),this.overLayButtonContainer.append(this.redoButton),this.redoButton.click(function(e){t.redo()})},clearCriteria:function(){if(this.allSelectedObjects){for(var e=this.allSelectedObjects.length,t=!1,i=0;i<e;i++){var a=this.allSelectedObjects[i];if(a.index in this.engine.derivative){if(this.emptyWellWithDefaultVal&&this.disableAddDeleteWell){var n=JSON.parse(JSON.stringify(this.defaultWell)),l=this.emptyWellWithDefaultVal;for(var s in l)s in n?(n[s]=l[s],this._applyFieldData(s,l[s])):console.log("Well does not contain key: "+s+", please contact support");this.engine.derivative[a.index]=n}else delete this.engine.derivative[a.index];t=!0}}t&&this.derivativeChange(),this._colorMixer(),this.decideSelectedFields()}else alert("Please select any well")},copyCriteria:function(){if(this.allSelectedObjects){var e=this._getSelectedWells();this.commonWell=this._getCommonFields(e)}else alert("Please select any well.")},pasteCriteria:function(){this.commonWell&&(this._addAllData(this.commonWell),this.decideSelectedFields(),this.mainFabricCanvas.renderAll())}}},$.widget("DNA.plateLayOut",{plateLayOutWidget:{},options:{value:0},allTiles:[],addressToLoc:function(e){var t=/^([A-Z]+)(\d+)$/.exec(e.trim().toUpperCase());if(t){for(var i,a=t[1],n=parseInt(t[2])-1,l=0;l<a.length;l++){var s=a.charCodeAt(l)-65;l?(i+=1,i*=26,i+=s):i=s}return{r:i,c:n}}throw e+" not a proper layout address"},locToIndex:function(e,i){if(i||(i=this.dimensions),e.r<0&&t,!(0<=e.r&&e.r<i.rows))throw"Row index "+(e.r+1)+" invalid";if(!(0<=e.c&&e.c<i.cols))throw"Column index "+(e.c+1)+" invalid";return e.r*i.cols+e.c},addressToIndex:function(e,t){var i=this.addressToLoc(e);return this.locToIndex(i,t)},_rowKey:function(e){var t=e%26,i=(e-t)/26,a=String.fromCharCode(65+t);return 0<i&&(a=String.fromCharCode(64+i)+a),a},indexToLoc:function(e,t){if(t||(t=this.dimensions),e>=t.rows*t.cols)throw"Index too high: "+e.toString(10);var i={};return i.c=e%t.cols,i.r=(e-i.c)/t.cols,i},locToAddress:function(e){return this._rowKey(e.r)+(e.c+1).toString(10)},indexToAddress:function(e,t){var i=this.indexToLoc(e,t);return this.locToAddress(i)},getDimensions:function(){return $.extend(!0,{},this.dimensions)},_create:function(){var e=parseInt(this.options.numRows||8),t=parseInt(this.options.numCols||12);this.dimensions={rows:e,cols:t},this.rowIndex=[];for(var i=0;i<e;i++)this.rowIndex.push(this._rowKey(i));for(var a in this.target=this.element[0].id?"#"+this.element[0].id:"."+this.element[0].className,this.options.readOnly&&this.isReadOnly(!0),plateLayOutWidget)$.extend(this,new plateLayOutWidget[a](this));return this.imgSrc=this.options.imgSrc||"assets",this._createInterface(),this._trigger("created",null,this),this},_init:function(){},addData:function(){alert("wow this is good")},getTextDerivative:function(e){var t={};this.fieldMap;for(var i in e){var a={},n={},l=e[i];for(var s in l)if(s in this.fieldMap){var r=this.fieldMap[s],o=r.parseText(l[s]);n[r.name]=o,a[s]=o}else n[s]=l[s],a[s]=l[s];t[i]={textVal:a,textFieldVal:n}}return t},getWellsDifferences:function(e){return this.getDifferentWellsVals(e)},setFieldsDisabled:function(t){this.fieldList.forEach(function(e){e.disabled(t)})},isReadOnly:function(e){this.readOnly=!!e,this.readOnlyHandler()},readOnlyHandler:function(){this.readOnly?(this.overLayButtonContainer.css("display","none"),$(".multiple-field-manage-delete-button").css("display","none"),this.setFieldsDisabled(!0)):(this.overLayButtonContainer.css("display","flex"),$(".multiple-field-manage-delete-button").css("display","none"),this.disableAddDeleteWell||this.setFieldsDisabled(!1))},disableAddDeleteWell:null,isDisableAddDeleteWell:function(e,t){e?(this.disableAddDeleteWell=!0,this.addressAllowToEdit=this.getWellSetAddressWithData(),this.actionPointer=0,this.undoRedoArray=[],this.undoRedoArray.push(this.createObject()),t&&(this.emptyWellWithDefaultVal=t)):(this.disableAddDeleteWell=!1,this.setFieldsDisabled(!1),this.emptyWellWithDefaultVal=null),this._fabricEvents()},getSelectedObject:function(){for(var e=[],t=0;t<this.allSelectedObjects.length;t++)e.push(this.allSelectedObjects[t].address);var i={},a=this.engine.derivative;for(var n in a){var l=this.indexToAddress(n);0<=e.indexOf(l)&&(i[l]=a[n])}return i},getSelectedIndex:function(){return this.allSelectedObjects.map(function(e){return that.addressToIndex(e.address)})},getSelectedAddress:function(){return this.allSelectedObjects.map(function(e){return e.address})},setSelectedWell:function(e){for(var t=[],i=999,a={},n=0;n<e.length;n++){var l=this.addressToIndex(e[n]),s=this.indexToLoc(l);t.push({minCol:s.c,minRow:s.r,maxCol:s.c,maxRow:s.r}),s.r<=i&&(i=s.r,s.r in a?a[s.r].push(s.c):a[s.r]=[s.c])}var r={row:i,col:Math.min.apply(null,a[i])};this.setSelection(t,r),this.decideSelectedFields(),this.mainFabricCanvas.renderAll()}});plateLayOutWidget=plateLayOutWidget||{};!function(s,e){plateLayOutWidget.preset=function(e){return{presets:[],_placePresetTabs:function(){var e=this.options.attributes.presets;if(e&&e.length){this.wellAttrContainer=this._createElement("<div></div>").addClass("plate-setup-well-attr-container").text("Checkbox presets"),this.tabContainer.append(this.wellAttrContainer),this.presetTabContainer=this._createElement("<div></div>").addClass("plate-setup-preset-container"),this.tabContainer.append(this.presetTabContainer);for(var t=0;t<e.length;t++){var i=e[t],a=this._createElement("<div></div>").addClass("plate-setup-prest-tab-div").text(i.title),n=this._createElement("<div></div>").addClass("plate-setup-prest-tab").data("preset",i.fields).append(a);this.presetTabContainer.append(n);var l=this;n.click(function(){var e=s(this);l._selectPreset(e)}),this.presets.push(n)}}},_clearPresetSelection:function(){for(var e=0;e<this.presets.length;e++){this.presets[e].removeClass("plate-setup-prest-tab-selected").addClass("plate-setup-prest-tab")}},_selectPreset:function(e){this.setCheckboxes(e.data("preset")),e.removeClass("plate-setup-prest-tab").addClass("plate-setup-prest-tab-selected")}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(a,e){plateLayOutWidget.tabs=function(){return{allTabs:[],defaultWell:{},allDataTabs:[],_createTabAtRight:function(){this.tabContainer=this._createElement("<div></div>").addClass("plate-setup-tab-container"),a(this.topRight).append(this.tabContainer)},_createTabs:function(){this.tabHead=this._createElement("<div></div>").addClass("plate-setup-tab-head"),a(this.tabContainer).append(this.tabHead);var e=this.options.attributes.tabs,i=this;e.forEach(function(e,t){i.allTabs[t]=i._createElement("<div></div>").addClass("plate-setup-tab"),a(i.allTabs[t]).data("index",t).text(e.name),a(i.allTabs[t]).click(function(){i._tabClickHandler(this)}),a(i.tabHead).append(i.allTabs[t])}),this.tabDataContainer=this._createElement("<div></div>").addClass("plate-setup-tab-data-container"),a(this.tabContainer).append(this.tabDataContainer),this._addDataTabs(e),a(this.allTabs[0]).click(),this._addTabData()},_tabClickHandler:function(e){if(this.selectedTab){a(this.selectedTab).removeClass("plate-setup-tab-selected").addClass("plate-setup-tab");var t=a(this.selectedTab).data("index");a(this.allDataTabs[t]).css("z-index",0),this.readOnlyHandler()}a(e).addClass("plate-setup-tab-selected"),this.selectedTab=e;var i=a(e).data("index");a(this.allDataTabs[i]).css("z-index",1e3)},_addDataTabs:function(e){var t=0;for(var i in e)this.allDataTabs[t++]=this._createElement("<div></div>").addClass("plate-setup-data-div").css("z-index",0),a(this.tabDataContainer).append(this.allDataTabs[t-1])}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(i,e){plateLayOutWidget.undoRedoManager=function(e){return{undoRedoArray:[],actionPointer:null,addToUndoRedo:function(e){if(null!=this.actionPointer){var t=this.actionPointer+1;t<this.undoRedoArray.length&&this.undoRedoArray.splice(t,this.undoRedoArray.length-t)}this.actionPointer=null,this.undoRedoArray.push(i.extend(!0,{},e))},_configureUndoRedoArray:function(){this.undoRedoArray=[],this.actionPointer=null,this.undoRedoArray.push(i.extend({},{checkboxes:[],derivative:{},selectedAreas:[{minRow:0,minCol:0,maxRow:0,maxCol:0}],focalWell:{row:0,col:0}}))},undo:function(){return console.log("undo"),this.shiftUndoRedo(-1)},redo:function(){return console.log("redo"),this.shiftUndoRedo(1)},shiftUndoRedo:function(e){var t=this.actionPointer;return null==t&&(t=this.undoRedoArray.length-1),t+=e,this.setUndoRedo(t)},setUndoRedo:function(e){return!(e<0)&&(!(e>=this.undoRedoArray.length)&&(this.undoRedoActive=!0,this.setData(this.undoRedoArray[e]),this.actionPointer=e,this.undoRedoActive=!1,this.derivativeChange(),!0))}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};jQuery,fabric,plateLayOutWidget.wellArea=function(e){return{_areasToTiles:function(e){var l=this.dimensions.cols,s=this;return e.reduce(function(e,t){if(t)for(var i=t.minRow;i<=t.maxRow;i++)for(var a=t.minCol;a<=t.maxCol;a++){var n=s.allTiles[a+l*i];e.indexOf(n)<0&&(s.disableAddDeleteWell?0<=s.addressAllowToEdit.indexOf(n.address)&&e.push(n):e.push(n))}return e},[])},_encodeArea:function(e){return e.minRow==e.maxRow&&e.minCol==e.maxCol?this.rowIndex[e.minRow]+e.minCol.toString(10):this.rowIndex[e.minRow]+e.minCol.toString(10)+":"+this.rowIndex[e.maxRow]+e.maxCol.toString(10)},_encodeAreas:function(e){var t=this;return e.map(function(e){return t._encodeArea(e)}).join(",")},_decodeWell:function(e){var t,i=new RegExp("^\\s*("+this.rowIndex.join("|")+")(\\d+)\\s*$");if(t=e.match(i)){var a=this.rowIndex.indexOf(t[1]);if(0<=a)return{row:a,col:parseInt(t[2])-1}}if(t=e.match(/^\s*R(\d+)C(\d+)\s*$/i))return{row:parseInt(t[1])-1,col:parseInt(t[2])-1};throw"Invalid well address: "+e},_decodeArea:function(e){var t=this,i=e.split(":").map(function(e){return t._decodeWell(e)});if(1==i.length)return{minRow:i[0].row,minCol:i[0].col,maxRow:i[0].row,maxCol:i[0].col};if(2!=i.length)throw"Invalid address: "+e;return Math.min(i[0].row,i[1].row),{minRow:Math.min(i[0].row,i[1].row),minCol:Math.min(i[0].col,i[1].col),maxRow:Math.max(i[0].row,i[1].row),maxCol:Math.max(i[0].col,i[1].col)}},_decodeAreas:function(e){var t=this;return e.split(",").map(function(e){return t._decodeArea(e)})},_wellToArea:function(e){return{minCol:e.col,minRow:e.row,maxCol:e.col,maxRow:e.row}},_wellInArea:function(e,t){return e.row>=t.minRow&&e.row<=t.maxRow&&e.col>=t.minCol&&e.col<=t.maxCol},_coordsToRect:function(e,t){var i=Math.min(e.x,t.x);return{top:Math.min(e.y,t.y),left:i,height:Math.abs(t.y-e.y),width:Math.abs(t.x-e.x)}},_coordIndex:function(e,t){return e<0?0:t<=e?t-1:Math.floor(e)},_coordsToWell:function(e){var t=this.dimensions.cols,i=this.dimensions.rows,a=this.sizes.spacing,n=this.sizes.label_spacing,l=(e.x-n)/a,s=(e.y-n)/a;return{row:this._coordIndex(s,i),col:this._coordIndex(l,t)}},_wellToCoords:function(e,t){var i=this.sizes.spacing,a=this.sizes.label_spacing,n=e.col*i+a,l=e.row*i+a;if(t){var s=i/2;n+=s,l+=s}return{x:n,y:l}},_areaToRect:function(e){var t=e.maxRow-e.minRow+1,i=e.maxCol-e.minCol+1,a=this.sizes.spacing,n=this.sizes.label_spacing;return{top:e.minRow*a+n,left:e.minCol*a+n,height:t*a,width:i*a}},_rectToArea:function(e){var t=this.dimensions.rows,i=this.dimensions.cols,a=this.sizes.spacing,n=this.sizes.label_spacing,l=(e.left-n)/a,s=(e.top-n)/a,r=e.height/a,o=l+e.width/a,d=s+r;return o<0&&(o=i),i<=l&&(l=0),d<0&&(d=t),s<=0&&(s=0),{minCol:this._coordIndex(l,i),minRow:this._coordIndex(s,t),maxCol:this._coordIndex(o,i),maxRow:this._coordIndex(d,t)}}}};
-//# sourceMappingURL=plate-map.min.js.map
\ No newline at end of file
diff --git a/dist/js/plate-map.min.js.map b/dist/js/plate-map.min.js.map
deleted file mode 100644
index da1b0dd..0000000
--- a/dist/js/plate-map.min.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["add-data-on-change.js","add-data-to-tabs.js","add-tab-data.js","add-warning-msg.js","bottom-table.js","canvas.js","check-box.js","color-manager.js","create-canvas-elements.js","create-field.js","engine.js","fabric-events.js","image_assets.js","interface.js","load-plate.js","main.js","overlay.js","plate-layout.js","preset.js","tabs.js","undo-redo-manager.js","well-area.js"],"names":["plateLayOutWidget","$","fabric","addDataOnChange","_addAllData","data","this","allSelectedObjects","noOfSelectedObjects","length","wells","objectIndex","well","tile","index","engine","derivative","extend","defaultWell","processedData","processWellData","wellEmpty","emptyWellWithDefaultVal","disableAddDeleteWell","wellCopy","JSON","parse","stringify","defaultValue","key","_applyFieldData","_getAllMultipleVal","applyFieldWarning","_colorMixer","derivativeChange","newData","curWell","wellList","id","v","undefined","multi","curData","preData","newDt","_getMultiData","push","fieldId","addNew","added","removed","value","add","listIdx","toString","map","val","subFieldId","indexOf","removeIndex","removeListIndex","newPreData","idx","parseInt","undoRedoActive","createObject","addToUndoRedo","searchAndStack","applyColors","mainFabricCanvas","renderAll","_trigger","checkboxes","globalSelectedAttributes","slice","selectedAreas","focalWell","requiredField","jQuery","addDataToFields","_addDataToTabFields","values","fieldMap","setValue","addTabData","fieldList","autoId","_addTabData","tabData","options","attributes","tabs","that","multiplexFieldArray","forEach","tab","tabPointer","tabFields","fieldArray","field","field_val","console","log","type","_makeMultiplexField","_makeRegularField","allDataTabs","multipleFieldList","_makeSubField","wrapperDiv","_createElement","addClass","wrapperDivLeftSide","wrapperDivRightSide","nameContainer","text","name","fieldContainer","append","root","required","checkbox","_addCheckBox","_createField","onChange","getValue","subFieldList","requiredSubField","subFieldKey","multiplexFields","subFieldData","subField","multiplexId","subFields","subfield","mainMultiplexField","mainRefField","curId","singleSelectValue","curVal","returnVal","_changeMultiFieldValue","curDataLs","detailData","input","select2","i","addWarningMsg","fieldWarningMsg","include","imgId","img","html","_assets","warningImg","attr","find","prepend","popText","hover","e","style","display","hide","remove","removeWarningMsg","fieldData","applyMultiplexSubFieldColor","Array","bottomTable","_bottomScreen","bottomContainer","bottomTableContainer","container","addBottomTableHeadings","bottomRow","singleField","empty","rowCounter","adjustFieldWidth","tileAttrText","getText","addBottomTableRow","color","singleStack","modelTile","allTiles","row","plateIdDiv","numberText","click","evt","addressToSelect","addressIdx","indexToAddress","ctrlKey","getSelectedAddress","setSelectedWell","selectedAddress","colorPairs","colorStops","css","dataDiv","bottomForFirstTime","createExportButton","downloadCSV","csv","filename","csvFile","downloadLink","Blob","document","createElement","download","href","window","URL","createObjectURL","body","appendChild","exportData","format","rows","querySelectorAll","colorLocMap","colorLocIdxMap","stackUpWithColor","dim","getDimensions","colorIdx","locIdx","cols","j","innerText","replace","loc","join","overlayContainer","descriptionDiv","buttonContainer","exportButton","resetExportText","classList","setTimeout","clipboardButton","clipboard","ClipboardJS","get","resetClipboardText","on","canvas","allPreviouslySelectedObjects","colorPointer","goldenRatio","_createCanvas","normalCanvas","canvasContainer","_initiateFabricCanvas","w","width","h","height","_setCanvasArea","Canvas","backgroundColor","selection","stateful","hoverCursor","renderOnAddRemove","setWidth","setHeight","checkBox","checkImage","dontImg","_applyCheckboxHandler","checkBoxImage","machineClick","changes","changeCheckboxes","changeSubFieldsCheckboxes","subFieldToInclude","clicked","Boolean","doImg","gsa","multiplexCheckedSubField","globalSelectedMultiplexSubfield","_clearPresetSelection","setSubFieldCheckboxes","fieldIds","setCheckboxes","colorManager","createCanvasElements","scaleFactor","baseSizes","spacing","tile_radius","center_radius_complete","center_radius_incomplete","label_size","label_spacing","text_size","stroke","gap","Math","min","dimensions","sizes","prop","_canvas","_fixRowAndColumn","_putCircles","d1","d2","fontSize","top","left","tempFabricText","IText","fill","originX","originY","fontFamily","selectable","fontWeight","rowIndex","tileCounter","col","_createTile","background","highlight","circle","circleCenter","circleText","_addLargeRectangleOverlay","_fabricEvents","visible","colorIndex","address","Circle","radius","hasControls","hasBorders","lockMovementX","lockMovementY","evented","setGradient","x1","x2","y1","y2","r1","r2","0","1","Rect","strokeWidth","lockScalingX","lockScalingY","setTileComplete","complete","setTileVisible","setTileColor","stackPointer","String","overLay","opacity","createField","_createTextField","_createNumericField","_createSelectField","_createMultiSelectField","_createBooleanField","_createMultiplexField","parseValue","trim","disabled","bool","parseText","generated","_createOpts","config","opts","allowClear","placeholder","minimumResultsForSearch","query","delay","_debounce","optMap","opt","setOpts","multiple","allOpts","selectedVal","curOpts","multiOnChange","_createDeleteButton","units","defaultUnit","unitInput","hasUnits","unitText","selected","unit","o","setUnitOpts","newUnits","curUnit","cleanUnit","newOpts","isPlainObject","parseRegularValue","parseUnit","getRegularValue","isNaN","getUnit","hasMultiplexUnit","unitTypeKey","unitMap","setUnit","setRegularValue","Number","toLowerCase","u","getRegularText","textVal","removeClass","tval","fval","initSelection","element","callback","nameContainer1","fieldContainer1","singleSelect","appendTo","setSingleSelectOptions","selected_v","singleSelectChange","updateSubFieldUnitOpts","curSubField","readOnlyHandler","newSubFieldValue","subFieldName","multiselectSetValue","multiselectValues","newOptions","valMap","hasOwnProperty","unitOptions","curIds","curOpt","newMultiplexVal","selectList","newVal","selectId","checkedSubfields","valIdx","subV","subText","optId","x","checkMultiplexCompletion","valList","valCount","completionPct","getSubfieldStatus","vals","req","subFieldWarningMap","warningStatus","multiplexVals","multiplexIdx","updateSubFieldWarningMap","mainFieldStatus","warningText","mainFieldWarning","parseMainFieldVal","_deleteDialog","valToRemove","allSelectedMultipleVal","Object","keys","dialogDiv","killDialog","dialogContent","tableArea","buttonRow","table","_deleteDialogTable","readOnly","deleteCheckedButton","each","decideSelectedFields","cancelButton","show","onclick","event","target","colName","thead","tbody","tr","deleteButton","THIS","isArray","derivativeJson","wellData","selectedSubFields","curMultiplexVals","isEmptyObject","k","parseFloat","sort","a","b","refDerivativeIndex","referenceDerivative","arr","wholeNoTiles","wholePercentage","tileIndex","completion","checkCompletion","floor","overLayTextContainer","multiplexStatus","fabricEvents","colorToIndex","startCoords","y","_clickCoords","rect","getBoundingClientRect","clientX","clientY","getPlates","selecting","coords","areas","_wellToCoords","_coordsToRect","_coordsToWell","shiftKey","_rectToArea","setSelection","endCoords","area","_areasToTiles","_setSelectedTiles","_setFocalWellRect","activeElement","blur","flag","locToAddress","r","c","addressAllowToEdit","setFieldsDisabled","_areaToRect","_wellToArea","focalWellRect","selectedTiles","_getSelectedWells","_getCommonFields","referenceWell","referenceFields","fields","refArr","agrArr","containsObject","inArray","obj","list","equality","evaluate","listKey","_getCommonWell","multiplexField","curMultipleVal","multipleVal","getDifferentWellsVals","wellsHash","wellId","differentWellsVals","commonWell","allFieldVal","fieldIdx","wellIdx","diffWellVal","curWellData","commonVal","curMultiVal","getWellSetAddressWithData","assets","interface","_createInterface","divIdentifier","topSection","topLeft","topRight","overLayContainer","_createOverLay","_createTabAtRight","_createTabs","_placePresetTabs","_setShortcuts","keyup","_handleShortcuts","_configureUndoRedoArray","addEventListener","copyCriteria","clearCriteria","preventDefault","pasteCriteria","keyCode","metaKey","redo","undo","loadPlate","sanitizeWell","sanitizeAreas","sanitized","setData","minCol","_coordIndex","maxCol","minRow","maxRow","max","_wellInArea","newWell","GET_PLATES","IS_READ_ONLY","IS_DISABLE_ADD_DELETE_WELL","GET_SELECTED_OBJECT","SETSELECTEDWELL","overlay","overLayButtonContainer","clearCriteriaButton","copyCriteriaButton","pasteCriteriaButton","undoButton","redoButton","hasWellUpdate","alert","widget","addressToLoc","layoutAddress","m","exec","toUpperCase","row_v","charCodeAt","locToIndex","t","addressToIndex","_rowKey","c1","c2","code","fromCharCode","indexToLoc","_create","numRows","numCols","component","className","isReadOnly","imgSrc","_init","addData","getTextDerivative","wellsData","textDerivative","textValWell","textFieldIdWell","textFieldVal","getWellsDifferences","isDisableAddDeleteWell","column_with_default_val","actionPointer","undoRedoArray","getSelectedObject","selectedObjects","getSelectedIndex","selectedObj","addressList","locMap","apply","preset","me","presets","wellAttrContainer","tabContainer","presetTabContainer","divText","title","presetButton","_selectPreset","allTabs","tabHead","tabIndex","_tabClickHandler","tabDataContainer","_addDataTabs","clickedTab","selectedTab","previouslyClickedTabIndex","clickedTabIndex","undoRedoManager","splice","shiftUndoRedo","pointerDiff","pointer","setUndoRedo","wellArea","reduce","tiles","_encodeArea","_encodeAreas","_decodeWell","wellAddress","match","adRx","RegExp","_decodeArea","areaAddress","split","_decodeAreas","areasAddress","abs","count","coord","center","hw","right","bottom"],"mappings":"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","file":"plate-map.min.js","sourcesContent":["var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.addDataOnChange = function() {\n    // This object is invoked when something in the tab fields change\n    return {\n\n      _addAllData: function(data) {\n        // Method to add data when something changes in the tabs. Its going to be tricky , just starting.\n        if (this.allSelectedObjects) {\n          var noOfSelectedObjects = this.allSelectedObjects.length;\n          var wells = [];\n          for (var objectIndex = 0; objectIndex < noOfSelectedObjects; objectIndex++) {\n            var tile = this.allSelectedObjects[objectIndex];\n            var well;\n            if (tile.index in this.engine.derivative) {\n              well = this.engine.derivative[tile.index];\n            } else {\n              well = $.extend(true, {}, this.defaultWell); \n              this.engine.derivative[tile.index] = well; \n            }\n            var processedData = this.processWellData(data, well, noOfSelectedObjects, wells);\n            wells = processedData.wells;\n            well = processedData.well;\n            var empty = this.engine.wellEmpty(well);\n            if (empty) {\n              if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {\n                var wellCopy = JSON.parse(JSON.stringify(well));\n                var defaultValue = this.emptyWellWithDefaultVal;\n                for (var key in defaultValue){\n                  if (key in wellCopy){\n                    wellCopy[key] = defaultValue[key];\n                    this._applyFieldData(key, defaultValue[key]);\n                  }\n                }\n                this.engine.derivative[tile.index] = wellCopy;\n              } else {\n                delete this.engine.derivative[tile.index];\n              }\n            }\n          }\n        }\n        // update multiplex remove all field\n        this._getAllMultipleVal(wells);\n        this.applyFieldWarning(wells);\n        // create well when default field is sent for the cases when user delete all fields during disabledNewDeleteWell mode\n        this._colorMixer();\n        this.derivativeChange();\n      },\n\n      processWellData: function(newData, curWell, noOfSelectedObjects, wellList) {\n\n        if (!wellList){\n          wellList = [];\n        }\n        for (var id in newData) {\n          var v;\n          if (newData[id] !== undefined && newData[id] !== null ) {\n            if (newData[id].multi){\n              var curData = newData[id];\n              var preData = curWell[id];\n              var newDt = this._getMultiData(preData, curData, id, noOfSelectedObjects);\n              // need to replace newData\n              v = JSON.parse(JSON.stringify(newDt));\n            } else {\n              v = JSON.parse(JSON.stringify(newData[id]));\n            }\n          } else {\n            v = JSON.parse(JSON.stringify(newData[id]));\n          }\n          curWell[id] = v;\n          wellList.push(curWell);\n        }\n\n        return {\n          well: curWell,\n          wells: wellList\n        }\n      },\n\n      _getMultiData: function(preData, curData, fieldId, noOfSelectedObjects) {\n        var addNew = curData.added;\n        var removed = curData.removed;\n        if (addNew) {\n          if (preData){\n            if (addNew.value) {\n              var add = true;\n              for (var listIdx in preData) {\n                var multiplexData = preData[listIdx];\n                // for cases when the add new data exist in well\n                if (multiplexData[fieldId].toString() === addNew.id.toString()) {\n                  add = false;\n                  // update subfield value\n                  preData = preData.map(function(val) {\n                    if (val[fieldId].toString() === addNew.id.toString()) {\n                      for (var subFieldId in val) {\n                        // over write previous data if only one well is selected\n                        if (subFieldId in addNew.value && subFieldId !== fieldId){\n                          if (noOfSelectedObjects === 1) {\n                            val[subFieldId] = addNew.value[subFieldId];\n                          } else if (addNew.value[subFieldId]) {\n                            val[subFieldId] = addNew.value[subFieldId];\n                          }\n                        }\n                      }\n                    }\n                    return val;\n                  })\n                }\n              }\n              if (add) {\n                preData.push(addNew.value);\n              }\n            } else if (preData.indexOf(addNew) < 0) {\n              preData.push(addNew);\n            }\n          } else {\n            preData = [];\n            if (addNew.value) {\n              preData.push(addNew.value);\n            } else if (addNew){\n              preData.push(addNew);\n            }\n          }\n        }\n\n        var removeListIndex = function(preData, removeIndex) {\n          var newPreData = [];\n          for (var idx in preData) {\n            if (parseInt(idx) !== parseInt(removeIndex)){\n              newPreData.push(preData[idx]);\n            }\n          }\n          return newPreData;\n        };\n\n        if (removed) {\n          var removeIndex;\n          // for multiplex field\n          if (removed.value) {\n            for (var listIdx in preData) {\n              var multiplexData = preData[listIdx];\n              if (multiplexData[fieldId].toString() === removed.id.toString()) {\n                removeIndex = listIdx;\n              }\n            }\n            // remove nested element\n            preData = removeListIndex(preData, removeIndex);\n          } else {\n            if (preData){\n              removeIndex = preData.indexOf(removed);\n              if (removeIndex >= 0) {\n                preData = removeListIndex(preData, removeIndex);\n              }\n            }\n          }\n        }\n        if (preData && (preData.length == 0)) {\n          preData = null; \n        }\n        return preData\n      },\n\n      _colorMixer: function() {\n        if (!this.undoRedoActive) {\n            var data = this.createObject();\n            this.addToUndoRedo(data);\n        }\n        this.engine.searchAndStack(); \n        this.engine.applyColors();\n        this.mainFabricCanvas.renderAll();\n      },\n\n      derivativeChange: function(){\n          this._trigger(\"updateWells\", null, this.createObject());\n      },\n\n      createObject: function() {\n        var derivative = $.extend(true, {}, this.engine.derivative); \n        var checkboxes = this.globalSelectedAttributes.slice(); \n        var selectedAreas = this.selectedAreas.slice(); \n        var focalWell = this.focalWell;\n\n        return {\n          \"derivative\": derivative,\n          \"checkboxes\": checkboxes,\n          \"selectedAreas\": selectedAreas,\n          \"focalWell\": focalWell,\n          \"requiredField\": this.requiredField\n        };\n      }\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.addDataToFields = function() {\n\n    return {\n\n      _addDataToTabFields: function(values) {\n        // Configure how data is added to tab fields\n        for (var id in values) {\n          this._applyFieldData(id, values[id]);\n        }\n      },\n\n      _applyFieldData: function(id, v) {\n        this.fieldMap[id].setValue(v); \n      }\n    }\n  }\n})(jQuery, fabric)","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.addTabData = function() {\n\n    return {\n\n      fieldList: [], \n      fieldMap: {},\n      autoId: 1,\n\n      _addTabData: function() {\n          // Here we may need more changes because attributes format likely to change\n          var tabData = this.options.attributes.tabs;\n          var that = this;\n          this.requiredField = [];\n          var multiplexFieldArray = [];\n          tabData.forEach(function (tab, tabPointer) {\n            if (tab[\"fields\"]) {\n              var tabFields = tab[\"fields\"];\n              var fieldArray = [];\n              var fieldArrayIndex = 0;\n              // Now we look for fields in the json\n              for (var field in tabFields) {\n                var data = tabFields[field];\n\n                if (!data.id) {\n                  data.id = \"Auto\" + that.autoId++;\n                  console.log(\"Field autoassigned id \" + data.id);\n                }\n                if (!data.type) {\n                  data.type = \"text\";\n                  console.log(\"Field \" + data.id + \" autoassigned type \" + data.type);\n                }\n\n                var field_val;\n                if (data.type === \"multiplex\") {\n                  field_val = that._makeMultiplexField(data, tabPointer, fieldArray);\n                  multiplexFieldArray.push(field_val);\n                } else {\n                  field_val = that._makeRegularField(data, tabPointer, fieldArray, true);\n                  if (data.type === \"multiselect\") {\n                    multiplexFieldArray.push(field_val);\n                  }\n                };\n              }\n\n              that.allDataTabs[tabPointer][\"fields\"] = fieldArray;\n            } else {\n              console.log(\"unknown format in field initialization\");\n            }\n          });\n          that.multipleFieldList = multiplexFieldArray;\n      },\n\n      _makeSubField: function (data, tabPointer, fieldArray) {\n        var that = this;\n        if (!data.id) {\n          data.id = \"Auto\" + that.autoId++;\n          console.log(\"Field autoassigned id \" + data.id);\n        }\n        if (!data.type) {\n          data.type = \"text\";\n          console.log(\"Field \" + data.id + \" autoassigned type \" + data.type);\n        }\n        var wrapperDiv = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-default-field\");\n        var wrapperDivLeftSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-left-side\");\n        var wrapperDivRightSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-right-side\");\n        var nameContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-name\").text(data.name);\n        var fieldContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-container\");\n\n        $(wrapperDivRightSide).append(nameContainer);\n        $(wrapperDivRightSide).append(fieldContainer);\n        $(wrapperDiv).append(wrapperDivLeftSide);\n        $(wrapperDiv).append(wrapperDivRightSide);\n        $(that.allDataTabs[tabPointer]).append(wrapperDiv);\n\n        var field = {\n          id: data.id,\n          name: data.name,\n          root: wrapperDiv,\n          data: data,\n          required: data.required || false\n        };\n\n        fieldArray.push(field);\n        that.fieldMap[data.id] = field;\n\n        return field;\n      },\n\n      _makeRegularField: function (data, tabPointer, fieldArray, checkbox){\n          var that = this;\n          var wrapperDiv = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-default-field\");\n          var wrapperDivLeftSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-left-side\");\n          var wrapperDivRightSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-right-side \");\n          var nameContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-name\").text(data.name);\n          var fieldContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-container\");\n\n          wrapperDivRightSide.append(nameContainer);\n          wrapperDivRightSide.append(fieldContainer);\n          wrapperDiv.append(wrapperDivLeftSide);\n          wrapperDiv.append(wrapperDivRightSide);\n          that.allDataTabs[tabPointer].append(wrapperDiv);\n\n          var field = {\n            id: data.id,\n            name: data.name,\n            root: wrapperDiv,\n            data: data,\n            required: data.required\n          };\n\n          if (field.required) {\n            that.requiredField.push(field.id);\n          }\n\n          fieldArray.push(field);\n          that.fieldList.push(field);\n          that.fieldMap[field.id] = field;\n\n          // Adding checkbox\n          if (checkbox) {\n            that._addCheckBox(field);\n          }\n          that._createField(field);\n\n          field.onChange = function () {\n            var v = field.getValue();\n            var data = {};\n            data[field.id] = v;\n            that._addAllData(data);\n          };\n          return field;\n      },\n\n      _makeMultiplexField: function (data, tabPointer, fieldArray) {\n        var that = this;\n        var wrapperDiv = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-default-field\");\n        var wrapperDivLeftSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-left-side\");\n        var wrapperDivRightSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-right-side \");\n        var nameContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-name\").text(data.name);\n        var fieldContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-container\");\n\n        wrapperDivRightSide.append(nameContainer);\n        wrapperDivRightSide.append(fieldContainer);\n        wrapperDiv.append(wrapperDivLeftSide);\n        wrapperDiv.append(wrapperDivRightSide);\n        that.allDataTabs[tabPointer].append(wrapperDiv);\n\n        var field = {\n          id: data.id,\n          name: data.name,\n          root: wrapperDiv,\n          data: data,\n          required: data.required\n        };\n\n        fieldArray.push(field);\n        that.fieldList.push(field);\n        that.fieldMap[data.id] = field;\n\n        var subFieldList = [];\n        //create subfields\n        var requiredSubField = [];\n        for (var subFieldKey in data.multiplexFields) {\n          var subFieldData = data.multiplexFields[subFieldKey];\n          var subField = that._makeSubField(subFieldData, tabPointer, fieldArray);\n          subFieldList.push(subField);\n\n          // stores required  subField\n          if (subFieldData.required) {\n            requiredSubField.push(subField.id);\n          }\n        }\n\n        //store required field\n        if (field.required || requiredSubField.length) {\n          this.requiredField.push ({\n            multiplexId: field.id,\n            subFields: requiredSubField\n          });\n        }\n\n        field.subFieldList = subFieldList;\n        that._createField(field);\n        that._addCheckBox(field);\n\n        subFieldList.forEach(function (subfield) {\n          subfield.mainMultiplexField = field;\n          fieldArray.push(subfield);\n          that._createField(subfield);\n          that._addCheckBox(subfield);\n          delete that.defaultWell[subfield.id];\n          // overwrite subField setvalue\n          subfield.onChange = function () {\n            var v = subfield.getValue();\n            var mainRefField = subfield.mainMultiplexField;\n            var curId = mainRefField.singleSelectValue();\n            //var curDataLs = mainRefField.detailData;\n            var curVal = {};\n            curVal[mainRefField.id] = curId;\n            //append subfields\n            curVal[subfield.id] = v;\n            var returnVal = {\n              id: curId,\n              value: curVal\n            };\n\n            field._changeMultiFieldValue(returnVal, null);\n            var curDataLs = mainRefField.detailData;\n            if (curDataLs !== null) {\n              curId = mainRefField.singleSelectValue(); \n              curDataLs = curDataLs.map(function(curData) {\n                if (curData[mainRefField.id] === curId) {\n                  curData[subfield.id] = v;\n                }\n                return curData;\n              });\n            }\n            mainRefField.detailData = curDataLs;\n          };\n\n        });\n\n        field.getValue = function(){\n          var v = field.input.select2('data');\n          if (v.length) {\n            return v.map(function (i) {\n              return i.id;\n            });\n          }\n          return null;\n        };\n\n        return field;\n      }\n    }\n  }\n\n})(jQuery, fabric);\n","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.addWarningMsg = function () {\n    // For those check boxes associated with every field in the tab\n    return {\n      fieldWarningMsg: function (field, text, include) {\n        var that = this;\n        var imgId = \"fieldWarning\" + field.id;\n        var img = $(\"<span>\").html(that._assets.warningImg).attr(\"id\", imgId).addClass(\"plate-field-warning-image\");\n        //field.root.find(\".plate-setup-tab-name\").append('<img id=\"theImg\" src=\"theImg.png\" />')\n        if (include) {\n          if (field.root.find(\"#\" + imgId).length <= 0){\n            field.root.find(\".plate-setup-tab-name\").text(\" \" + field.name);\n            field.root.find(\".plate-setup-tab-name\").prepend(img);\n\n            var popText = $(\"<div/>\").addClass(\"pop-out-text\");\n            popText.text(text);\n            field.root.find(\".plate-setup-tab-name\").append(popText);\n\n            $(\"#\" + imgId).hover(function (e) {\n              popText[0].style.display = 'flex';\n            }, function () {\n              popText.hide();\n            });\n          }\n\n\n        } else {\n          if (field.root.find(\"#\" + imgId).length > 0) {\n            field.root.find(\".plate-setup-tab-name\").text(field.name);\n            $(\"#\" + imgId).remove();\n          }\n        }\n      },\n\n      removeWarningMsg: function (field, text, include) {\n        var that = this;\n        var imgId = \"fieldWarning\" + field.id;\n        var img = $(\"<span>\").html(that._assets.warningImg).attr(\"id\", imgId).addClass(\"plate-field-warning-image\");\n        //field.root.find(\".plate-setup-tab-name\").append('<img id=\"theImg\" src=\"theImg.png\" />')\n        if (include) {\n          field.root.find(\".plate-setup-tab-name\").append(img);\n\n          var popText = $(\"<div/>\").addClass(\"pop-out-text\");\n          popText.text(text);\n          field.root.find(\".plate-setup-tab-name\").append(popText);\n\n          $(\"#\" + imgId).hover(function (e) {\n            popText[0].style.display = 'inline-block';\n          }, function () {\n            popText.hide();\n          });\n\n        } else {\n          $(\"#\" + imgId).remove();\n          if (field.root.find(\"#\" + imgId).length > 0) {\n            //field.root.find(\".plate-setup-tab-name\").remove(img);\n            $(\"#\" + imgId).remove();\n          }\n        }\n      },\n\n      applyFieldWarning: function(wells) {\n        var that = this;\n        var req = 0;\n        var fill = 0;\n        var fieldData = {};\n        that.fieldList.forEach(function(field){\n          fieldData[field.id] = [];\n        });\n        wells.forEach(function(well){\n          if (!that.engine.wellEmpty(well)){\n            for (var fieldId in fieldData) {\n              if (fieldId in well) {\n                fieldData[fieldId].push(well[fieldId]);\n              } else {\n                fieldData[fieldId].push(null);\n              }\n            }\n          }\n        });\n        for (var i = 0; i < that.fieldList.length; i++) {\n          var field = that.fieldList[i];\n          if (field.applyMultiplexSubFieldColor){\n            field.applyMultiplexSubFieldColor(fieldData[field.id]);\n          } else {\n            if (field.required) {\n              var include = false;\n              fieldData[field.id].forEach(function(val){\n                // for multiselect\n                if (val instanceof Array) {\n                  if (val.length === 0) {\n                    include = true;\n                  }\n                } else {\n                  if (val === null) {\n                    include = true;\n                  }\n                }\n              });\n              //field.root.find(\".plate-setup-tab-name\").css(\"background\", color);\n              that.fieldWarningMsg(field, \"required field\", include);\n            }\n          }\n        }\n      }\n    }\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.bottomTable = function() {\n    // for bottom table\n    return {\n      _bottomScreen: function() {\n        this.bottomContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-bottom-container\");\n        this.bottomTableContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-bottom-table-container\");\n        this.bottomTable = this._createElement(\"<table></table>\").addClass(\"plate-setup-bottom-table\");\n        this.bottomTableContainer.append(this.bottomTable);\n        this.bottomContainer.append(this.bottomTableContainer);\n        this.container.append(this.bottomContainer);\n      },\n\n      addBottomTableHeadings: function() {\n\n        this.bottomRow = this._createElement(\"<tr></tr>\");\n\n        var singleField = this._createElement(\"<th></th>\")\n          .text(\"Group\");\n        this.bottomRow.prepend(singleField);\n        // Now we append all the captions at the place.\n        this.bottomTable.empty();\n        this.bottomTable.append(this.bottomRow);\n\n        this.rowCounter = 1;\n\n        for (var i = 0; i < this.globalSelectedAttributes.length; i++) {\n          var attr = this.globalSelectedAttributes[i];\n          var field = this.fieldMap[attr];\n          var singleField = this._createElement(\"<th></th>\").text(field.name);\n          this.bottomRow.append(singleField);\n          this.rowCounter = this.rowCounter + 1;\n        }\n\n        this.adjustFieldWidth(this.bottomRow);\n      },\n\n      tileAttrText: function(tile, attr) {\n        var well = this.engine.derivative[tile.index];\n        var field = this.fieldMap[attr];\n        return field.getText(well[attr]);\n      },\n\n      addBottomTableRow: function(color, singleStack) {\n        var that = this;\n        var modelTile = this.allTiles[singleStack[0]];\n        var row = this._createElement(\"<tr></tr>\");\n        var plateIdDiv = this._createElement(\"<td></td>\").addClass(\"plate-setup-bottom-id\");\n        var numberText = this._createElement(\"<button/>\");\n        numberText.addClass(\"plate-setup-color-text\");\n        numberText.text(color);\n        plateIdDiv.append(numberText);\n\n        numberText.click(function(evt){\n          var addressToSelect = singleStack.map(function(addressIdx){\n            return that.indexToAddress(addressIdx)\n          });\n          if (evt.ctrlKey) {\n            that.getSelectedAddress().forEach(function(val){\n              if (addressToSelect.indexOf(val) < 0){\n                addressToSelect.push(val);\n              }\n            })\n          }\n          that.setSelectedWell(addressToSelect);\n          that._trigger(\"selectedWells\", null, {selectedAddress: that.getSelectedAddress()});\n        });\n\n        if (color > 0) {\n          color = ((color - 1) % (this.colorPairs.length - 1)) + 1;\n        }\n        var colorStops = this.colorPairs[color];\n\n        plateIdDiv.css(\"background\", \"linear-gradient(to right, \" + colorStops[0] + \" , \" + colorStops[1] + \")\");\n\n        row.append(plateIdDiv);\n\n        for (var i = 0; i < this.globalSelectedAttributes.length; i++) {\n          var attr = this.globalSelectedAttributes[i];\n          var text = this.tileAttrText(modelTile, attr);\n          var dataDiv = this._createElement(\"<td></td>\").text(text);\n          row.append(dataDiv);\n        }\n        this.bottomTable.append(row);\n        this.adjustFieldWidth(row);\n      },\n\n      bottomForFirstTime: function() {\n        this.addBottomTableHeadings();\n        // This is executed for the very first time.. !\n        var row = this._createElement(\"<tr></tr>\");\n\n        var colorStops = this.colorPairs[0];\n        var plateIdDiv = this._createElement(\"<td></td>\");\n        plateIdDiv.css(\"background\", \"-webkit-linear-gradient(left, \" + colorStops[0] + \" , \" + colorStops[1] + \")\");\n        row.append(plateIdDiv);\n        this.bottomTable.append(row);\n        this.createExportButton();\n      },\n\n      adjustFieldWidth: function(row) {\n\n        var length = this.rowCounter;\n        if ((length) * 150 > 1024) {\n          row.css(\"width\", (length) * 152 + \"px\");\n        }\n      },\n\n      downloadCSV: function(csv, filename) {\n        var csvFile;\n        var downloadLink;\n\n        // CSV file\n        csvFile = new Blob([csv], {\n          type: \"text/csv\"\n        });\n\n        // Download link\n        downloadLink = document.createElement(\"a\");\n\n        // File name\n        downloadLink.download = filename;\n\n        // Create a link to the file\n        downloadLink.href = window.URL.createObjectURL(csvFile);\n\n        // Hide download link\n        downloadLink.style.display = \"none\";\n\n        // Add the link to DOM\n        document.body.appendChild(downloadLink);\n\n        // Click download link\n        downloadLink.click();\n      },\n\n      exportData: function(format) {\n        var data = [];\n        var rows = document.querySelectorAll(\"table tr\");\n\n        var colorLocMap = {};\n        var colorLocIdxMap = this.engine.stackUpWithColor;\n        var dim = this.getDimensions();\n        var that = this;\n        for (var colorIdx in colorLocIdxMap) {\n          colorLocMap[colorIdx] = colorLocIdxMap[colorIdx].map(function (locIdx) {\n            return that.indexToAddress(locIdx, dim);\n          })\n        }\n\n        for (var i = 0; i < rows.length; i++) {\n          var row = [],\n            cols = rows[i].querySelectorAll(\"td, th\");\n\n          for (var j = 0; j < cols.length; j++) {\n            var v = \"\";\n            if (cols[j].innerText) {\n              if (format === \"csv\") {\n                v = '\"' + cols[j].innerText.replace(/\"/g, '\"\"') + '\"';\n              } else {\n                v = cols[j].innerText;\n              }\n            }\n            row.push(v);\n\n            // add location column\n            if (i === 0 && j === 0) {\n              if (format === \"csv\") {\n                row.push('\"Location\"');\n              } else if (format === 'clipboard') {\n                row.push(\"Location\");\n              }\n\n            }\n            if (i !== 0 && j === 0) {\n              var loc = '';\n              if (colorLocMap[parseInt(cols[j].innerText)]) {\n                if (format === \"csv\") {\n                  loc = '\"' + colorLocMap[parseInt(cols[j].innerText)].join(\",\") + '\"';\n                } else if (format === 'clipboard') {\n                  loc = colorLocMap[parseInt(cols[j].innerText)].join(\",\");\n                }\n              }\n              row.push(loc);\n            }\n          }\n\n          if (format === \"csv\") {\n            data.push(row.join(\",\"));\n          } else if (format === 'clipboard') {\n            data.push(row.join(\"\\t\"));\n            //data.push(row);   // for text type\n          }\n\n        }\n        if (format === \"csv\") {\n          // Download CSV file\n          this.downloadCSV(data.join(\"\\n\"), 'table.csv');\n        } else if (format === 'clipboard') {\n          //return formatTableToString(data);   // for text type\n          return data.join(\"\\n\");\n        }\n      },\n\n      createExportButton: function() {\n        var that = this;\n        var overlayContainer = $(\"<div>\").addClass(\"plate-setup-bottom-control-container\");\n\n        var descriptionDiv = $(\"<div>\").addClass(\"plate-setup-overlay-text-container\");\n        descriptionDiv.text(\"Color groups\");\n        overlayContainer.append(descriptionDiv);\n\n        var buttonContainer = $(\"<div>\").addClass(\"plate-setup-overlay-bottom-button-container\");\n\n        // create export csv option\n        var exportButton = $(\"<button/>\").addClass(\"plate-setup-button\");\n        exportButton.text(\"Export CSV\");\n        buttonContainer.append(exportButton);\n\n        exportButton.click(function() {\n          that.exportData('csv');\n          exportButton.text(\"Exported\");\n          exportButton[0].classList.remove(\"plate-setup-button\");\n          exportButton.addClass(\"plate-setup-clicked-button\");\n          setTimeout(resetExportText, 3000);\n        });\n\n        function resetExportText() {\n          exportButton.text(\"Export CSV\");\n          exportButton[0].classList.remove(\"plate-setup-clicked-button\");\n          exportButton.addClass(\"plate-setup-button\");\n        }\n\n        // creat clipboard option, CLipboard is an external js file located in vendor/asset/javascripts\n        var clipboardButton = $(\"<button/>\").addClass(\"plate-setup-button\");\n        clipboardButton.text(\"Copy To Clipboard\");\n        buttonContainer.append(clipboardButton);\n\n        var clipboard = new ClipboardJS(clipboardButton.get(0), {\n          text: function() {\n            return that.exportData(\"clipboard\");\n          }\n        });\n\n        clipboard.on('success', function(e) {\n          clipboardButton.text(\"Copied as tab-delimited format\");\n          clipboardButton[0].classList.remove(\"plate-setup-button\");\n          clipboardButton.addClass(\"plate-setup-clicked-button\");\n          setTimeout(resetClipboardText, 3000);\n        });\n\n        function resetClipboardText() {\n          clipboardButton.text(\"Copy To Clipboard\");\n          clipboardButton[0].classList.remove(\"plate-setup-clicked-button\");\n          clipboardButton.addClass(\"plate-setup-button\");\n        }\n\n        clipboard.on('error', function(e) {\n          clipboardButton.text(\"Failed to copy table to clipboard: browser may be incompatible\");\n          setTimeout(resetClipboardText, 3000);\n        });\n\n        overlayContainer.append(buttonContainer);\n        $(\".plate-setup-bottom-container\").prepend(overlayContainer);\n      }\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.canvas = function() {\n    //\n    return {\n\n      allSelectedObjects: null, // Contains all the selected objets, when click and drag.\n\n      allPreviouslySelectedObjects: null,\n\n      colorPointer: 0,\n\n      goldenRatio: 0.618033988749895,\n\n      _createCanvas: function() {\n        this.normalCanvas = this._createElement(\"<canvas>\").attr(\"id\", \"DNAcanvas\");\n        $(this.canvasContainer).append(this.normalCanvas);\n      },\n\n      _initiateFabricCanvas: function() {\n        var w = this.canvasContainer.width(); \n        var h = this.canvasContainer.height(); \n\n        this._setCanvasArea(w, h);\n\n        this.mainFabricCanvas = new fabric.Canvas('DNAcanvas', {\n            backgroundColor: '#f5f5f5',\n            selection: false,\n            stateful: false,\n            hoverCursor: \"pointer\",\n            renderOnAddRemove: false,\n          })\n          .setWidth(w)\n          .setHeight(h);\n      },\n\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.checkBox = function() {\n    // For those check boxes associated with every field in the tab\n    return {\n\n      globalSelectedAttributes: [],\n\n      _addCheckBox: function(field) {\n        var checkImage = $(\"<span>\").html(this._assets.dontImg).addClass(\"plate-setup-tab-check-box bg-light\")\n          .data(\"clicked\", false);\n        checkImage.data(\"linkedFieldId\", field.id);\n        field.root.find(\".plate-setup-tab-field-left-side\").empty().append(checkImage);\n        this._applyCheckboxHandler(checkImage); // Adding handler for change the image when clicked\n        field.checkbox = checkImage;\n      },\n\n      _applyCheckboxHandler: function(checkBoxImage) {\n        // We add checkbox handler here, thing is it s not checkbox , its an image and we change\n        // source\n        var that = this;\n        checkBoxImage.click(function(evt, machineClick) {\n          var checkBox = $(this);\n\n          var changes = {};\n          changes[checkBox.data(\"linkedFieldId\")] = !checkBox.data(\"clicked\");\n\n          that.changeCheckboxes(changes);\n        });\n      },\n\n      changeSubFieldsCheckboxes: function(field, changes) {\n        var that = this;\n        var subFieldToInclude = [];\n\n        field.subFieldList.forEach(function(subField) {\n          var checkImage = subField.checkbox;\n          var fieldId = checkImage.data(\"linkedFieldId\");\n          var clicked = checkImage.data(\"clicked\");\n          if (fieldId in changes) {\n            clicked = Boolean(changes[fieldId]);\n          }\n          checkImage.data(\"clicked\", clicked);\n          if (clicked) {\n            checkImage.html(that._assets.doImg);\n            subFieldToInclude.push(subField.id);\n          } else {\n            checkImage.html(that._assets.dontImg);\n          }\n        });\n        return subFieldToInclude;\n      },\n\n      changeCheckboxes: function(changes) {\n        var gsa = [];\n        var multiplexCheckedSubField = {};\n        for (var i = 0; i < this.fieldList.length; i++) {\n          var field = this.fieldList[i];\n          if (field.checkbox) {\n            if (field.subFieldList) {\n              multiplexCheckedSubField[field.id] = this.changeSubFieldsCheckboxes(field, changes);\n            }\n\n            var checkImage = field.checkbox;\n            var fieldId = checkImage.data(\"linkedFieldId\");\n            var clicked = checkImage.data(\"clicked\");\n            if (fieldId in changes) {\n              clicked = Boolean(changes[fieldId]);\n            }\n            checkImage.data(\"clicked\", clicked);\n            if (clicked) {\n              gsa.push(fieldId);\n              checkImage.html(this._assets.doImg);\n            } else {\n              checkImage.html(this._assets.dontImg);\n            }\n          }\n        }\n        this.globalSelectedMultiplexSubfield = multiplexCheckedSubField;\n        this.globalSelectedAttributes = gsa;\n        this._clearPresetSelection();\n        this._colorMixer();\n      },\n\n      setSubFieldCheckboxes: function(field, fieldIds) {\n        var that = this;\n        var subFieldToInclude = [];\n        field.subFieldList.forEach(function(subField) {\n          var checkImage = subField.checkbox;\n          var fieldId = checkImage.data(\"linkedFieldId\");\n          var clicked = fieldIds.indexOf(fieldId) >= 0;\n          checkImage.data(\"clicked\", clicked);\n          if (clicked) {\n            checkImage.html(that._assets.doImg);\n            subFieldToInclude.push(subField.id);\n          } else {\n            checkImage.html(that._assets.dontImg);\n          }\n        });\n        return subFieldToInclude;\n      },\n\n      setCheckboxes: function(fieldIds) {\n        fieldIds = fieldIds || [];\n        var gsa = [];\n        var multiplexCheckedSubField = {};\n\n        for (var i = 0; i < this.fieldList.length; i++) {\n          var field = this.fieldList[i];\n          if (field.checkbox) {\n            // special handling for multiplex field\n            if (field.subFieldList) {\n              multiplexCheckedSubField[field.id] = this.setSubFieldCheckboxes(field, fieldIds);\n            }\n\n            var checkImage = field.checkbox;\n            var fieldId = checkImage.data(\"linkedFieldId\");\n            var clicked = fieldIds.indexOf(fieldId) >= 0;\n            checkImage.data(\"clicked\", clicked);\n            if (clicked) {\n              gsa.push(fieldId);\n              checkImage.html(this._assets.doImg);\n            } else {\n\n              checkImage.html(this._assets.dontImg);\n            }\n          }\n        }\n        this.globalSelectedMultiplexSubfield = multiplexCheckedSubField;\n        this.globalSelectedAttributes = gsa;\n        this._clearPresetSelection();\n        this._colorMixer();\n      }\n\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.colorManager = function() {\n\n    return {\n        // See these are color pairs for the gradient.\n      colorPairs: [\n        [\"#e6e6e6\", \"#808080\"],\n        [\"#66e8ff\", \"#0082c8\"],\n        [\"#ff7fb1\", \"#e6194b\"],\n        [\"#a2ffb1\", \"#3cb44b\"],\n        [\"#f784ff\", \"#911eb4\"],\n        [\"#ffe897\", \"#f58231\"],\n        [\"#6666ff\", \"#0000FF\"],\n        [\"#ffff7f\", \"#ffe119\"],\n        [\"#acffff\", \"#46f0f0\"],\n        [\"#ff98ff\", \"#f032e6\"],\n        [\"#ffffa2\", \"#d2f53c\"],\n        [\"#ffffff\", \"#fabebe\"],\n        [\"#66e6e6\", \"#008080\"],\n        [\"#ffffff\", \"#e6beff\"],\n        [\"#ffd48e\", \"#aa6e28\"],\n        [\"#e66666\", \"#800000\"],\n        [\"#ffffff\", \"#aaffc3\"],\n        [\"#e6e666\", \"#808000\"],\n        [\"#ffffff\", \"#ffd8b1\"],\n        [\"#66a9ef\", \"#004389\"],\n        [\"#ff6672\", \"#a7000c\"],\n        [\"#66db72\", \"#00750c\"],\n        [\"#b866db\", \"#520075\"],\n        [\"#ffa966\", \"#b64300\"],\n        [\"#ffff66\", \"#c0a200\"],\n        [\"#6dffff\", \"#07b1b1\"],\n        [\"#ff66ff\", \"#b100a7\"],\n        [\"#f9ff66\", \"#93b600\"],\n        [\"#ffe5e5\", \"#bb7f7f\"],\n        [\"#66a7a7\", \"#004141\"],\n        [\"#ffe5ff\", \"#a77fc0\"],\n        [\"#d19566\", \"#6b2f00\"],\n        [\"#ffffef\", \"#c0bb89\"],\n        [\"#d1ffea\", \"#6bc084\"],\n        [\"#a7a766\", \"#414100\"],\n        [\"#ffffd8\", \"#c09972\"],\n        [\"#a5ffff\", \"#3fc1ff\"],\n        [\"#ffbef0\", \"#ff588a\"],\n        [\"#e1fff0\", \"#7bf38a\"],\n        [\"#ffc3ff\", \"#d05df3\"],\n        [\"#ffffd6\", \"#ffc170\"],\n        [\"#a5a5ff\", \"#3f3fff\"],\n        [\"#ffffbe\", \"#ffff58\"],\n        [\"#ebffff\", \"#85ffff\"],\n        [\"#ffd7ff\", \"#ff71ff\"],\n        [\"#a5ffff\", \"#3fbfbf\"],\n        [\"#ffffcd\", \"#e9ad67\"],\n        [\"#ffa5a5\", \"#bf3f3f\"],\n        [\"#ffffa5\", \"#bfbf3f\"]\n      ]\n    }\n  }\n\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.createCanvasElements = function() {\n    // this class manages creating all the elements within canvas\n    return {\n\n      scaleFactor: 1, \n\n      baseSizes: {\n        spacing: 48, \n        tile_radius: 22, \n        center_radius_complete: 10, \n        center_radius_incomplete: 14, \n        label_size: 14, \n        label_spacing: 24, \n        text_size: 13,\n        stroke: 0.5, \n        gap: 2\n      }, \n\n      _setCanvasArea: function(w, h) {\n        this.scaleFactor = Math.min(\n           h / (this.dimensions.rows * this.baseSizes.spacing + this.baseSizes.label_spacing), \n           w / (this.dimensions.cols * this.baseSizes.spacing + this.baseSizes.label_spacing));\n\n        var sizes = {}\n        for (var prop in this.baseSizes) {\n          sizes[prop] = this.baseSizes[prop] * this.scaleFactor; \n        }\n        this.sizes = sizes; \n      }, \n\n      _canvas: function() {\n        // Those 1,2,3 s and A,B,C s\n        this._fixRowAndColumn();\n\n        // All those circles in the canvas.\n        this._putCircles();\n      },\n\n      _fixRowAndColumn: function() {\n        var cols = this.dimensions.cols;\n        var rows = this.dimensions.rows;\n\n        var spacing = this.sizes.spacing;\n        var d1 = this.sizes.label_spacing / 2;\n        var d2 = this.sizes.label_spacing + this.sizes.spacing / 2; \n        var fontSize = this.sizes.label_size; \n\n        // For column\n        var top = d1; \n        var left = d2;  \n        for (var i = 1; i <= cols; i++) {\n          var tempFabricText = new fabric.IText(i.toString(), {\n            fill: 'black',\n            originX: 'center',\n            originY: 'center',\n            fontSize: fontSize,\n            top: top,\n            left: left,\n            fontFamily: '\"Roboto\", Arial, sans-serif',\n            selectable: false,\n            fontWeight: \"400\"\n          });\n          left += spacing; \n\n          this.mainFabricCanvas.add(tempFabricText);\n        }\n\n        // for row\n        top = d2; \n        left = d1; \n        for (var i = 1; i <= rows; i++) {\n          var tempFabricText = new fabric.IText(this.rowIndex[i-1], {\n            fill: 'black',\n            originX: 'center',\n            originY: 'center',\n            fontSize: fontSize,\n            top: top,\n            left: left,\n            fontFamily: '\"Roboto\", Arial, sans-serif',\n            selectable: false,\n            fontWeight: \"400\"\n          });\n          top += spacing; \n\n          this.mainFabricCanvas.add(tempFabricText);\n        }\n      },\n\n      _putCircles: function() {\n        var cols = this.dimensions.cols;\n        var rows = this.dimensions.rows;\n\n        var tileCounter = 0;\n        for (var row = 0; row < rows; row++) {\n          for (var col = 0; col < cols; col++) {\n            var index = this.allTiles.length; \n            var tile = this._createTile(row, col); \n            tile.index = tileCounter++; \n            this.allTiles.push(tile);\n            this.mainFabricCanvas.add(tile.background);\n            this.mainFabricCanvas.add(tile.highlight);\n            this.mainFabricCanvas.add(tile.circle);\n            this.mainFabricCanvas.add(tile.circleCenter);\n            this.mainFabricCanvas.add(tile.circleText);\n          }\n        }\n\n        this._addLargeRectangleOverlay();\n        this._fabricEvents();\n      },\n\n      _createTile: function (row, col) {\n        var tile = {}; \n\n        tile.visible = false; \n        tile.colorIndex = null; \n        tile.row = row; \n        tile.col = col; \n        tile.address = this.rowIndex[row] + (col + 1); \n\n        var top = (row + 1) * this.sizes.spacing;\n        var left = (col + 1) * this.sizes.spacing; \n\n        tile.background = new fabric.Circle({\n          top: top,\n          left: left,\n          radius: this.sizes.tile_radius,\n          originX: 'center',\n          originY: 'center',\n          hasControls: false,\n          hasBorders: false,\n          lockMovementX: true,\n          lockMovementY: true,\n          evented: false,\n        });\n\n        tile.background.setGradient(\"fill\", {\n          type: \"radial\",\n          x1: this.sizes.tile_radius, \n          x2: this.sizes.tile_radius, \n          y1: this.sizes.tile_radius + this.sizes.gap,\n          y2: this.sizes.tile_radius + this.sizes.gap,\n          r1: this.sizes.tile_radius - this.sizes.gap,\n          r2: this.sizes.tile_radius,\n          colorStops: {\n            0: 'rgba(0,0,0,0.1)',\n            1: 'rgba(0,0,0,0.2)'\n          }\n        });\n\n        tile.highlight = new fabric.Rect({\n          originX: 'center',\n          originY: 'center',\n          top: top,\n          left: left,\n          width: this.sizes.spacing,\n          height: this.sizes.spacing,\n          fill: \"rgba(0,0,0,0.4)\",\n          evented: false,\n          visible: false\n        });\n\n        tile.circle = new fabric.Circle({\n          originX: 'center',\n          originY: 'center',\n          top: top,\n          left: left,\n          radius: this.sizes.tile_radius,\n          stroke: 'gray',\n          strokeWidth: this.sizes.stroke,\n          evented: false, \n          visible: false\n        });\n\n        tile.circleCenter = new fabric.Circle({\n          originX: 'center',\n          originY: 'center',\n          top: top,\n          left: left,\n          radius: this.sizes.center_radius_incomplete,\n          fill: \"white\",\n          stroke: 'gray',\n          strokeWidth: this.sizes.stroke,\n          evented: false,\n          visible: false\n        });\n\n        tile.circleText = new fabric.IText(\"\", {\n          originX: 'center',\n          originY: 'center',\n          top: top,\n          left: left,\n          fill: 'black',\n          fontFamily: '\"Roboto\", Arial, sans-serif',\n          fontSize: this.sizes.text_size,\n          lockScalingX: true,\n          lockScalingY: true,\n          evented: false,\n          visible: false\n        });\n\n        return tile; \n      }, \n\n      setTileComplete: function (tile, complete) {\n        if (complete) {\n          tile.circleCenter.radius = this.sizes.center_radius_complete;\n          tile.circleText.fill = \"black\";\n          tile.circleText.fontWeight = 'normal';\n        } else {\n          tile.circleCenter.radius = this.sizes.center_radius_incomplete;\n          tile.circleText.fill = \"red\";\n          tile.circleText.fontWeight = 'bold';\n        }\n      }, \n\n      setTileVisible: function (tile, visible) {\n        tile.visible = visible;\n        tile.circle.visible = tile.visible;\n        tile.circleCenter.visible = tile.visible;\n        tile.circleText.visible = tile.visible;\n      },\n\n      setTileColor: function(tile, color, stackPointer) {\n        this.setTileVisible(tile, true);\n        tile.colorIndex = parseInt(color); \n        tile.circleText.text = String(tile.colorIndex);\n\n        if (color > 0) {\n          color = ((color - 1) % (this.colorPairs.length -1)) + 1;\n        }\n        var colorStops = this.colorPairs[color];\n\n        tile.circle.setGradient(\"fill\", {\n          y2: 2 * this.sizes.tile_radius,\n          colorStops: colorStops\n        });\n      },\n\n      _addLargeRectangleOverlay: function() {\n\n        this.overLay = new fabric.Rect({\n          width: 632,\n          height: 482,\n          left: 0,\n          top: 0,\n          opacity: 0.0,\n          originX: 'left',\n          originY: 'top',\n          lockMovementY: true,\n          lockMovementX: true,\n          selectable: false\n        });\n\n        this.mainFabricCanvas.add(this.overLay);\n      }\n    };\n  }\n})(jQuery, fabric);\n","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.createField = function() {\n    // It create those fields in the tab , there is 4 types of them.\n    return {\n\n      _createField: function(field) {\n        switch (field.data.type) {\n          case \"text\":\n            this._createTextField(field);\n            break;\n\n          case \"numeric\":\n            this._createNumericField(field);\n            break;\n\n          case \"select\":\n            this._createSelectField(field);\n            break;\n\n          case \"multiselect\":\n            this._createMultiSelectField(field);\n            break;\n\n          case \"boolean\":\n            this._createBooleanField(field);\n            break;\n\n          case \"multiplex\":\n            this._createMultiplexField(field);\n            break;\n        }\n      },\n\n      _createTextField: function(field) {\n        var id = field.id;\n        var that = this;\n        var input = this._createElement(\"<input>\").attr(\"id\", id)\n          .addClass(\"plate-setup-tab-input\");\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        that.defaultWell[id] = null;\n\n        field.parseValue = function(v) {\n          if (v) {\n            v = String(v);\n          } else {\n            v = null;\n          }\n          return v;\n        };\n\n        field.getValue = function() {\n          var v = input.val().trim();\n          if (v == \"\") {\n            v = null;\n          }\n          return v;\n        };\n\n        field.setValue = function(v) {\n          input.val(v);\n        };\n\n        field.getText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          return v;\n        };\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n        };\n\n        field.parseText = field.parseValue;\n\n        input.on(\"input\", function(e, generated) {\n          field.onChange();\n        });\n\n        field.input = input;\n      },\n\n      _createOpts: function(config) {\n        var opts = {\n          allowClear: true,\n          placeholder: \"select\",\n          minimumResultsForSearch: 10\n        };\n\n        if (config.options) {\n          opts.data = config.options;\n        } else if (config.query) {\n          var query = config.query;\n          if (config.delay) {\n            query = this._debounce(config.delay, query);\n          }\n          opts.query = query;\n        } else {\n          throw \"Must specify data or query\";\n        }\n        return opts;\n      },\n\n      _createSelectField: function(field) {\n        var id = field.id;\n        var that = this;\n        var input = this._createElement(\"<input/>\").attr(\"id\", id)\n          .addClass(\"plate-setup-tab-select-field\");\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        that.defaultWell[id] = null;\n\n        var opts = that._createOpts(field.data);\n        var optMap = {};\n        opts.data.forEach(function(opt) {\n          optMap[opt.id] = opt;\n        });\n\n        input.select2(opts);\n\n        field.parseValue = function(value) {\n          var v = value;\n\n          if (v == \"\") {\n            v = null;\n          }\n          if (v == null) {\n            return null;\n          }\n          if (v in optMap) {\n            return optMap[v].id;\n          } else {\n            throw \"Invalid value \" + value + \" for select field \" + id;\n          }\n        };\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n        };\n\n        field.getValue = function() {\n          var v = input.select2('data');\n          return v ? v.id : null;\n        };\n\n        field.setValue = function(v) {\n          if (v) {\n            v = optMap[v];\n          }\n          input.select2('data', v);\n        };\n\n        field.setOpts = function(v) {\n          input.select2('data', {});\n          opts.data = v || [];\n          input.select2(opts);\n        };\n\n        field.getText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          return optMap[v].text;\n        };\n\n        field.parseText = function(value) {\n          var v = value;\n\n          if (v == \"\") {\n            v = null;\n          }\n          if (v == null) {\n            return null;\n          }\n          if (v in optMap) {\n            return optMap[v].text;\n          } else {\n            throw \"Invalid text value \" + value + \" for select field \" + id;\n          }\n        };\n\n        input.on(\"change\", function(e, generated) {\n          field.onChange();\n        });\n\n        field.input = input;\n      },\n\n      _createMultiSelectField: function(field) {\n        var id = field.id;\n        var that = this;\n        var input = this._createElement(\"<input/>\").attr(\"id\", id)\n          .addClass(\"plate-setup-tab-multiselect-field\");\n        input.attr(\"multiple\", \"multiple\");\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        that.defaultWell[id] = null;\n\n        var separator = \",\";\n        var opts = that._createOpts(field.data);\n        opts.multiple = true;\n        var optMap = {};\n        opts.data.forEach(function(opt) {\n          optMap[opt.id] = opt;\n        });\n        input.select2(opts);\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n        };\n\n        field.parseValue = function(value) {\n          var v = value;\n          if (v && v.length) {\n            v = v.map(function(opt) {\n              if (opt in optMap) {\n                return optMap[opt].id;\n              } else {\n                throw \"Invalid value \" + opt + \" for multiselect field \" + id;\n              }\n            });\n          } else {\n            v = null;\n          }\n          return v;\n        };\n\n        field.setOpts = function(v) {\n          var allOpts = field.data.options;\n          var selectedVal = [];\n          for (var id in allOpts) {\n            var curOpts = allOpts[id];\n            if (v.indexOf(curOpts[\"id\"]) >= 0) {\n              selectedVal.push(curOpts);\n            }\n          }\n\n          opts.data = selectedVal;\n          input.select2(opts);\n        };\n\n        field.getValue = function() {\n          var v = input.select2('data');\n          if (v.length) {\n            return v.map(function(i) {\n              return i.id;\n            });\n          }\n          return null;\n        };\n\n        field.setValue = function(v) {\n          v = v || [];\n          v = v.map(function(i) {\n            return optMap[i];\n          });\n          input.select2('data', v);\n        };\n\n        field.getText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          if (v.length > 0) {\n            return v.map(function(v) {\n              return optMap[v].text\n            }).join(\"; \");\n          }\n          return \"\";\n        };\n\n        field.multiOnChange = function (added, removed) {\n          if (added) {\n            added = added.id.toString();\n          }\n          if (removed) {\n            removed = removed.id.toString();\n          }\n          var data = {\n          };\n          data[field.id] = {\n            multi: true,\n            added: added,\n            removed: removed\n          };\n\n          that._addAllData(data);\n        };\n\n        field.parseText = function(value){\n          var v = value;\n          if (v && v.length) {\n            v = v.map(function(opt) {\n              if (opt in optMap) {\n                return optMap[opt].text;\n              } else {\n                throw \"Invalid text value \" + opt + \" for multiselect field \" + id;\n              }\n            });\n          } else {\n            v = null;\n          }\n          return v;\n        };\n\n        input.on(\"change\", function(e, generated) {\n          var added = e.added;\n          var removed = e.removed;\n          //field.onChange();\n          field.multiOnChange(added, removed);\n        });\n\n        field.input = input;\n\n        that._createDeleteButton(field);\n      },\n\n      _createNumericField: function(field) {\n        var id = field.id;\n        var data = field.data;\n        var that = this;\n        var input = this._createElement(\"<input>\").addClass(\"plate-setup-tab-input\")\n          .attr(\"placeholder\", data.placeholder || \"\").attr(\"id\", id);\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        that.defaultWell[id] = null;\n\n        // Adding unit\n        var units = data.units || [];\n        var defaultUnit = data.defaultUnit || null;\n        var unitInput = null;\n        if (defaultUnit) {\n          if (units.length) {\n            if (units.indexOf(defaultUnit) < 0) {\n              defaultUnit = units[0];\n            }\n          } else {\n            units = [defaultUnit];\n          }\n        } else {\n          if (units.length) {\n            defaultUnit = units[0];\n          }\n        }\n\n        if (units.length) {\n          field.units = units;\n          field.hasUnits = true;\n          field.defaultUnit = defaultUnit;\n          if (units.length == 1) {\n            var unitText = $(\"<div></div>\").addClass(\"plate-setup-tab-unit\");\n            unitText.text(defaultUnit);\n            field.root.find(\".plate-setup-tab-field-container\").append(unitText);\n          } else {\n            unitInput = this._createElement(\"<input/>\").attr(\"id\", id)\n              .addClass(\"plate-setup-tab-label-select-field\");\n\n            field.root.find(\".plate-setup-tab-field-container\").append(unitInput);\n\n            var selected = null;\n            var unitData = units.map(function(unit) {\n              var o = {\n                id: unit,\n                text: unit\n              };\n              if (unit == defaultUnit) {\n                selected = o;\n              }\n              return o;\n            });\n\n            var opts = {\n              data: unitData,\n              allowClear: false,\n              minimumResultsForSearch: 10\n            };\n\n            unitInput.select2(opts);\n            unitInput.select2(\"data\", selected);\n          }\n        }\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n          if (unitInput) {\n            unitInput.prop(\"disabled\", bool);\n          }\n        };\n\n        field.setUnitOpts = function(opts) {\n          field.units = opts || null;\n          field.defaultUnit = null;\n\n          var newUnits = [];\n          var selected = null;\n          if (field.units && field.units.length) {\n            field.defaultUnit = field.units[0];\n            newUnits = field.units.map(function(curUnit) {\n              var cleanUnit = {\n                id: curUnit,\n                text: curUnit\n              };\n              if (curUnit == field.defaultUnit) {\n                selected = cleanUnit;\n              }\n              return cleanUnit;\n            });\n          }\n\n          var newOpts = {\n            data: newUnits,\n            allowClear: false,\n            minimumResultsForSearch: 10\n          };\n          unitInput.select2(newOpts);\n          unitInput.select2(\"data\", selected);\n        };\n\n        field.parseValue = function(value) {\n          var v;\n          if ($.isPlainObject(value)) {\n            if (field.hasUnits) {\n              v = field.parseRegularValue(value.value);\n              if (v === null) {\n                return null;\n              }\n              return {\n                value: v,\n                unit: field.parseUnit(value.unit)\n              };\n            } else {\n              throw \"Value must be plain numeric for numeric field \" + id;\n            }\n          } else {\n            if (field.hasUnits) {\n              v = field.parseRegularValue(value);\n              if (v === null) {\n                return null;\n              }\n              return {\n                value: v,\n                unit: field.defaultUnit\n              };\n            } else {\n              return field.parseRegularValue(value);\n            }\n          }\n        };\n\n        field.getValue = function() {\n          var v = field.getRegularValue();\n\n          if ((v === null) || isNaN(v)) {\n            return null;\n          } else if (field.hasUnits) {\n            var returnVal = {\n              value: v,\n              unit: field.getUnit()\n            };\n\n            if (field.data.hasMultiplexUnit) {\n              // include unitTypeId and UnitId to returnVal\n              for (var unitTypeKey in field.data.unitMap) {\n                var unitTypeUnits = field.data.unitMap[unitTypeKey];\n                unitTypeUnits.forEach(function(unit) {\n                  if (unit.text === returnVal.unit) {\n                    returnVal['unitTypeId'] = unitTypeKey;\n                    returnVal['unitId'] = unit.id;\n                  }\n                })\n              }\n            }\n            return returnVal;\n          } else {\n            return v;\n          }\n        };\n\n        field.setValue = function(value) {\n          if (field.hasUnits) {\n            if ($.isPlainObject(value)) {\n              field.setUnit(value.unit || field.defaultUnit);\n              field.setRegularValue(value.value);\n\n            } else {\n              field.setRegularValue(value);\n              field.setUnit(field.defaultUnit)\n            }\n          } else {\n            field.setRegularValue(value);\n          }\n        };\n\n        field.parseRegularValue = function(value) {\n          if (value == null) {\n            return null;\n          }\n          var v = String(value).trim();\n          if (v === \"\") {\n            return null;\n          }\n          v = Number(value);\n          if (isNaN(v)) {\n            throw \"Invalid value \" + value + \" for numeric field \" + id;\n          }\n          return v;\n        };\n\n        field.getRegularValue = function() {\n          var v = input.val().trim();\n          if (v == \"\") {\n            v = null;\n          } else {\n            v = Number(v);\n          }\n          return v;\n        };\n\n        field.setRegularValue = function(value) {\n          input.val(value);\n        };\n\n        field.parseUnit = function(unit) {\n          if (unit == null || unit === \"\") {\n            return field.defaultUnit;\n          }\n          for (var i = 0; i < units.length; i++) {\n            if (unit.toLowerCase() == units[i].toLowerCase()) {\n              return units[i];\n            }\n          }\n          throw \"Invalid unit \" + unit + \" for field \" + id;\n        };\n\n        field.getUnit = function() {\n          if (unitInput) {\n            return unitInput.val();\n          } else {\n            return field.defaultUnit;\n          }\n        };\n\n        field.setUnit = function(unit) {\n          if (unitInput) {\n            unit = unit || field.defaultUnit;\n            if (unit != null) {\n              unit = {\n                id: unit,\n                text: unit\n              };\n            }\n            unitInput.select2(\"data\", unit);\n          }\n        };\n\n        // val now contains unit\n        field.getText = function(val) {\n          if (typeof(val) === 'object' && val) {\n            var v = val.value;\n            var u = val.unit;\n            if (v == null) {\n              return \"\";\n            }\n            v = v.toString();\n            if (!u) {\n              u = defaultUnit;\n            }\n            if (u) {\n              v = v + \" \" + u;\n            }\n            return v;\n          } else {\n            return field.getRegularText(val);\n          }\n        };\n\n        field.getRegularText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          v = v.toString();\n          return v;\n        };\n\n        field.parseText = function(v){\n          var textVal = field.parseValue(v);\n          if (textVal && typeof(textVal) === \"object\"){\n            return textVal.value + textVal.unit;\n          } else if (textVal) {\n            return textVal\n          } else {\n            return null;\n          }\n        };\n\n        input.on(\"input\", function() {\n          var v = field.getRegularValue();\n          if (isNaN(v)) {\n            //flag field as invalid\n            input.addClass(\"invalid\");\n          } else {\n            input.removeClass(\"invalid\");\n          }\n          field.onChange();\n        });\n        if (unitInput) {\n          unitInput.on(\"change\", function() {\n            field.onChange();\n          });\n        }\n\n        field.input = input;\n        field.unitInput = unitInput;\n      },\n\n      _createBooleanField: function(field) {\n        var id = field.id;\n        var that = this;\n        var input = this._createElement(\"<input/>\").attr(\"id\", id)\n          .addClass(\"plate-setup-tab-select-field\");\n        that.defaultWell[id] = null;\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        var tval = {\n          id: \"true\",\n          text: \"true\"\n        };\n        var fval = {\n          id: \"false\",\n          text: \"false\"\n        };\n        var opts = {\n          data: [tval, fval],\n          placeholder: \"select\",\n          allowClear: true,\n          minimumResultsForSearch: -1,\n          initSelection: function(element, callback) {\n            var v = element.val();\n            callback({\n              id: v,\n              text: v\n            });\n          }\n        };\n\n        input.select2(opts);\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n        };\n\n        field.parseValue = function(value) {\n          if (value == null) {\n            return null;\n          }\n          var v = String(value).trim().toLowerCase();\n          if (v == \"true\") {\n            v = true;\n          } else if (v == \"false\") {\n            v = false;\n          } else if (v == \"\") {\n            v = null;\n          } else {\n            throw \"Invalid value \" + value + \" for boolean field \" + id;\n          }\n          return v;\n        };\n\n        field.getValue = function() {\n          var v = input.val();\n          switch (v) {\n            case \"true\":\n              return true;\n            case \"false\":\n              return false;\n            default:\n              return null;\n          }\n        };\n\n        field.setValue = function(v) {\n          if (v == true || v == \"true\") {\n            v = tval;\n          } else if (v == false || v == \"false\") {\n            v = fval;\n          } else {\n            v = null;\n          }\n          input.select2('data', v);\n        };\n\n        field.getText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          return v.toString();\n        };\n\n        field.parseText = field.parseValue;\n\n        input.on(\"change\", function(e) {\n          field.onChange();\n        });\n\n        field.input = input;\n      },\n\n      _createMultiplexField: function(field) {\n        var that = this;\n        // make correct multiplex data\n        this._createMultiSelectField(field);\n        // overwrite default well for multiplex field\n        that.defaultWell[field.id] = [];\n\n        // single select\n        var nameContainer1 = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-name-singleSelect\").text(\"Select to edit\");\n        var fieldContainer1 = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-container-singleSelect\");\n        field.root.find(\".plate-setup-tab-field-right-side\").append(nameContainer1, fieldContainer1);\n\n        field.singleSelect = this._createElement(\"<input/>\").attr(\"id\", field.id + \"SingleSelect\")\n          .addClass(\"plate-setup-tab-multiplex-single-select-field\");\n\n        field.singleSelect.appendTo(fieldContainer1);\n\n        field.singleSelectValue = function () {\n          var v = field.singleSelect.select2(\"data\");\n          if (v != null) {\n            v = v.id;\n          }\n          return v;\n        };\n\n        var setSingleSelectOptions = function (v, selected_v) {\n          var opts = {\n            allowClear: false,\n            placeholder: \"select\",\n            minimumResultsForSearch: 10,\n            data: v || []\n          }\n          if (!selected_v) {\n            if (opts.data.length) {\n              selected_v = opts.data[0];\n            } else {\n              selected_v = null;\n            }\n          }\n          field.singleSelect.select2('data', []);\n          field.singleSelect.select2(opts);\n          field.singleSelect.select2('data', selected_v);\n          field.singleSelect.prop(\"disabled\", opts.data.length == 0);\n        };\n\n        var singleSelectChange = function () {\n          var v = field.singleSelectValue();\n\n          field.updateSubFieldUnitOpts(v);\n\n          var curData = field.detailData || [];\n          var curSubField = null;\n          curData.forEach(function(val) {\n            if (val[field.id] === v) {\n              curSubField = val;\n            }\n          });\n\n          if (curSubField) {\n            // setvalue for subfield\n            field.subFieldList.forEach(function(subField) {\n              subField.disabled(false);\n              subField.setValue(curSubField[subField.id]);\n            });\n          } else {\n            field.subFieldList.forEach(function(subField) {\n              subField.disabled(true);\n              subField.setValue(null);\n            });\n          }\n          that.readOnlyHandler();\n        };\n\n        setSingleSelectOptions([]);\n\n        field.singleSelect.on(\"change\", singleSelectChange);\n\n        field._changeMultiFieldValue = function(added, removed) {\n          var newSubFieldValue = {};\n          for (var subFieldName in field.data.multiplexFields) {\n            var subFieldId = field.data.multiplexFields[subFieldName].id;\n            newSubFieldValue[subFieldId] = null;\n          }\n\n          var val;\n          if (added) {\n            if (added.value) {\n              val = added.value;\n            } else {\n              newSubFieldValue[field.id] = added.id;\n              val = newSubFieldValue;\n            }\n            added = {\n              id: added.id,\n              value: val\n            };\n          }\n\n          if (removed) {\n            if (removed.value){\n              val = removed.value;\n            } else {\n              newSubFieldValue[field.id] = removed.id;\n              val = newSubFieldValue;\n            }\n            removed = {\n              id: removed.id,\n              value: val\n            };\n          }\n\n          var data = {};\n          data[field.id] = {\n            multi: true,\n            added: added,\n            removed: removed\n          };\n          that._addAllData(data);\n        };\n\n        var multiselectSetValue = field.setValue;\n\n        // overwrite multiplex set value\n        field.setValue = function(v) {\n          // used to keep track of initially loaded multiplex data\n          field.detailData = v;\n          var multiselectValues = null;\n          if (v && v.length) {\n            multiselectValues = v.map(function(val) {\n              return val[field.id]\n            });\n          }\n\n          multiselectSetValue(multiselectValues);\n          var newOptions = field.input.select2('data') || [];\n          setSingleSelectOptions(newOptions);\n          singleSelectChange();\n        };\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n          field.subFieldList.forEach(function(subField) {\n            subField.disabled(bool);\n          });\n          if (bool) {\n            nameContainer1.text(\"Select to inspect\");\n          } else {\n            nameContainer1.text(\"Select to edit\");\n          }\n        };\n\n        field.parseValue = function(value) {\n          var v = value;\n          if (v && v.length) {\n            v = v.map(function(opt) {\n              var valMap = {};\n              valMap[field.id] = opt[field.id];\n              for (var subFieldId in opt) {\n                field.subFieldList.forEach(function(subField) {\n                  if (subField.id === subFieldId) {\n                    valMap[subField.id] = subField.parseValue(opt[subFieldId]);\n                  }\n                });\n              }\n              return valMap;\n            });\n          } else {\n            v = null;\n          }\n          return v;\n        };\n\n        field.updateSubFieldUnitOpts = function(val) {\n          var curOpts;\n          field.data.options.forEach(function(opt) {\n            if (opt.id === val) {\n              curOpts = opt;\n            }\n          });\n          field.subFieldList.forEach(function(subField) {\n            if (subField.data.hasMultiplexUnit) {\n              if (curOpts && curOpts.hasOwnProperty(\"unitOptions\")) {\n\t\t\t\t\t\t\t\tsubField.setUnitOpts(curOpts.unitOptions[subField.id]);\n              } else {\n                subField.setUnitOpts(null);\n              }\n            }\n          })\n        };\n\n        field.multiOnChange = function(added, removed) {\n          field._changeMultiFieldValue(added, removed);\n          var v = field.getValue();\n          var curData = field.detailData;\n          var curIds = [];\n          var curOpt = null;\n          //reshape data for saveback\n          if (curData) {\n            curIds = curData.map(function(val) {\n              return val[field.id]\n            });\n          }\n\n          var newMultiplexVal = [];\n          var selectList = [];\n          if (v) {\n            v.forEach(function(selectedVal) {\n              if (curData) {\n                curData.forEach(function(val) {\n                  if (val[field.id] === selectedVal) {\n                    newMultiplexVal.push(val)\n                  }\n                });\n              }\n              // cases when adding new data\n              if (curIds.indexOf(selectedVal) < 0) {\n                var newVal = {};\n                newVal[field.id] = selectedVal;\n\n                field.updateSubFieldUnitOpts(selectedVal);\n                field.subFieldList.forEach(function(subfield) {\n                  // special handling for subfield which has multiplexUnit\n                  if (subfield.hasUnits) {\n                    if (subfield.data.hasMultiplexUnit) {\n                      subfield.disabled(false);\n                      field.data.options.forEach(function(opt) {\n                        if (opt.id === selectedVal) {\n                          var val = {\n                            value: null,\n                            unit: subfield.units[0]\n                          };\n                          newVal[subfield.id] = subfield.parseValue(val);\n                        }\n                      });\n                    } else {\n                      if (subfield.data.units) {\n                        if (subfield.data.units.length > 1){\n                          subfield.disabled(false);\n                        }\n                      }\n                      var val = {\n                        value: null,\n                        unit: subfield.defaultUnit\n                      };\n                      newVal[subfield.id] = subfield.parseValue(val);\n                    }\n                  }\n                   else {\n                    newVal[subfield.id] = subfield.parseValue(null);\n                  }\n                });\n                newMultiplexVal.push(newVal);\n              }\n            });\n\n            // make data for single select options\n            v.forEach(function(selectId) {\n              field.data.options.forEach(function(opt) {\n                if (opt.id === selectId) {\n                  selectList.push(opt);\n                }\n              });\n            });\n            // set the newest selected to be the current obj\n            curOpt = selectList[v.length - 1];\n          }\n\n          field.detailData = newMultiplexVal;\n          setSingleSelectOptions(selectList, curOpt);\n          singleSelectChange();\n        };\n\n        field.getText = function(v) {\n          if (v === null) {\n            return \"\";\n          }\n          // get subfields that is selected from the checkbox\n          if (field.id in that.globalSelectedMultiplexSubfield) {\n            var checkedSubfields = that.globalSelectedMultiplexSubfield[field.id];\n            var returnVal = [];\n            for (var valIdx in v) {\n              var subV = v[valIdx];\n              var subText = [];\n              for (var optId in field.data.options) {\n                var opt = field.data.options[optId];\n                if (opt.id === subV[field.id]) {\n                  subText.push(opt.text);\n                }\n              }\n              field.subFieldList.forEach(function(subField) {\n                if (checkedSubfields.indexOf(subField.id) >= 0) {\n                  var x = subField.getText(subV[subField.id]);\n                  subText.push(subField.name + \": \" + x);\n                }\n              });\n              returnVal.push(\"{\" + subText.join(\", \") + \"}\");\n            }\n            return returnVal.join(\";\");\n          }\n        };\n\n        field.parseText = function(v) {\n          if (v === null) {\n            return \"\";\n          } else {\n            var returnVal = [];\n            for (var valIdx in v) {\n              var subV = v[valIdx];\n              var subText = [];\n              for (var optId in field.data.options) {\n                var opt = field.data.options[optId];\n                if (opt.id === subV[field.id]) {\n                  subText.push(opt.text);\n                }\n              }\n              field.subFieldList.forEach(function(subField) {\n                var x = subField.getText(subV[subField.id]);\n                if (x) {\n                  subText.push(x);\n                }\n              });\n              returnVal.push(subText);\n            }\n            return returnVal;\n          }\n        };\n\n        field.checkMultiplexCompletion = function(valList) {\n          var valCount = 0;\n          var completionPct = 0;\n          var include = false;\n          function getSubfieldStatus (vals) {\n            var req = 0;\n            var fill = 0;\n            for (var subFieldId in field.subFieldList) {\n              var subField = field.subFieldList[subFieldId];\n              var curVal = vals[subField.id];\n              if (subField.required) {\n                include = true;\n                req++;\n                if (typeof(curVal) === 'object' && curVal) {\n                  if (curVal.value) {\n                    fill++;\n                  }\n                } else if (curVal) {\n                  fill++;\n                }\n              }\n            }\n            return fill/req;\n          }\n\n          // for cases has value in multiplex field\n          if (valList) {\n            if (valList.length > 0){\n              for (var idx in valList) {\n                valCount++;\n                var vals = valList[idx];\n                completionPct += getSubfieldStatus(vals);\n              }\n            } else if (field.required) {\n              include = true;\n              valCount = 1;\n            }\n          }  else if (field.required) {\n            include = true;\n            valCount = 1;\n          }\n\n          return {\n            include: include,\n            completionPct: completionPct/valCount\n          };\n        };\n\n        // valList contains all of the vals for selected val\n        field.applyMultiplexSubFieldColor = function(valList){\n          function updateSubFieldWarningMap (vals) {\n            for (var subFieldId in field.subFieldList) {\n              var subField = field.subFieldList[subFieldId];\n              // loop through each well's multiplexval list\n              if (vals === null){\n                if (field.required && subField.required){\n                  subFieldWarningMap[subField.id].warningStatus.push(true);\n                }\n              } else if (typeof(vals) === \"object\") {\n                if (vals.length === 0) {\n                  if (field.required && subField.required){\n                    subFieldWarningMap[subField.id].warningStatus.push(true);\n                  }\n                } else {\n                  for (var multiplexIdx in vals) {\n                    var curVal = vals[multiplexIdx][subField.id];\n                    if (subField.required) {\n                      if (typeof(curVal) === 'object' && curVal) {\n                        if (!curVal.value) {\n                          subFieldWarningMap[subField.id].warningStatus.push(true);\n                        } else {\n                          subFieldWarningMap[subField.id].warningStatus.push(false);\n                        }\n                      } else if (!curVal) {\n                        subFieldWarningMap[subField.id].warningStatus.push(true);\n                      } else {\n                        subFieldWarningMap[subField.id].warningStatus.push(false);\n                      }\n                    }\n                  }\n                }\n              }\n            }\n          }\n\n          var subFieldWarningMap = {};\n          field.subFieldList.forEach(function(subField){\n            if (subField.required) {\n              subFieldWarningMap[subField.id] = {\n                field: subField,\n                warningStatus: []\n              };\n            }\n          });\n\n          valList.forEach(function(multiplexVals) {\n            updateSubFieldWarningMap(multiplexVals);\n          });\n          // turn off main field when all subfield are filled\n\n          var requiredSubField = [];\n          var mainFieldStatus = [];\n          for (var subFieldId in subFieldWarningMap){\n            var subField = subFieldWarningMap[subFieldId].field;\n            if (subFieldWarningMap[subFieldId].warningStatus.indexOf(true) >= 0) {\n              var text =  subField.name + \" is a required subfield for \" + field.name + \", please make sure all \" + field.name + \" have \" + subField.name;\n              if (field.required){\n                that.fieldWarningMsg(subField, text, true);\n                mainFieldStatus.push(true);\n              } else {\n                that.fieldWarningMsg(subField, text, true);\n                mainFieldStatus.push(true);\n              }\n            } else {\n              that.fieldWarningMsg(subField, \"none\", false);\n              mainFieldStatus.push(false);\n            }\n          }\n          var mainFieldWarning = false;\n          if (mainFieldStatus.indexOf(true) < 0) {\n            mainFieldWarning = false;\n          } else {\n            mainFieldWarning = true;\n          }\n          var warningText;\n          if (field.required) {\n            warningText = field.name + \" is a required field, please also fix missing required subfield(s) below\";\n          } else {\n            warningText = field.name + \" is not a required field, please fix missing required subfield(s) below or remove selected \" + field.name;\n          }\n          that.fieldWarningMsg(field, warningText, mainFieldWarning);\n        };\n\n        field.parseMainFieldVal = function(val) {\n          var optMap = field.data.options;\n          for (var idx = 0; idx < optMap.length; idx++){\n            var curOpt = optMap[idx];\n            if (curOpt.id === val){\n              return curOpt.text\n            }\n          }\n        };\n      },\n\n      _deleteDialog: function (field) {\n        var that = this;\n\n        var valMap = field.allSelectedMultipleVal;\n        var valToRemove;\n        if (valMap) {\n          valToRemove = Object.keys(valMap);\n        } else {\n          valToRemove = [];\n        }\n\n\n        var dialogDiv = $(\"<div/>\").addClass(\"delete-dialog modal\");\n        $('body').append(dialogDiv);\n\n        function killDialog() {\n          dialogDiv.hide();\n          dialogDiv.remove();\n        }\n\n        var dialogContent = $(\"<div/>\").addClass(\"modal-content\").appendTo(dialogDiv);\n        var tableArea = $(\"<div/>\").appendTo(dialogContent);\n        var buttonRow = $(\"<div/>\").addClass(\"dialog-buttons\").css(\"justify-content\", \"flex-end\").appendTo(dialogContent);\n\n        if (valToRemove.length > 0){\n          // apply CSS property for table\n          $(\"<p/>\").text(field.name + \" in selected wells: choose items to delete and click the delete button below\").appendTo(tableArea);\n\n          var table = that._deleteDialogTable(field, valMap);\n          table.appendTo(tableArea);\n          table.addClass(\"plate-popout-table\");\n          table.find('td').addClass(\"plate-popout-td\");\n          table.find('th').addClass(\"plate-popout-th\");\n          table.find('tr').addClass(\"plate-popout-tr\");\n          if (!that.readOnly) {\n            var deleteCheckedButton = $(\"<button class='multiple-field-manage-delete-button'>Delete Checked Items</button>\");\n            buttonRow.append(deleteCheckedButton);\n            deleteCheckedButton.click(function() {\n              table.find(\"input:checked\").each(function () {\n                var val = this.value;\n                field.multiOnChange(null, {id: val});\n              });\n              // refresh selected fields after updating the multiplex field value\n              that.decideSelectedFields();\n              killDialog();\n            });\n          }\n\n        } else {\n          $(\"<p/>\").text(\"No \" + field.name + \" in the selected wells\").appendTo(tableArea);\n        }\n\n        var cancelButton = $(\"<button>Cancel</button>\");\n        buttonRow.append(cancelButton);\n        cancelButton.click(killDialog);\n\n        dialogDiv.show();\n\n        window.onclick = function(event) {\n          if (event.target == dialogDiv[0]) {\n            killDialog();\n          }\n        }\n      },\n\n      _deleteDialogTable: function (field, valMap) {\n        var that = this;\n        var colName = [field.name, \"Counts\"]; //Added because it was missing... no idea what the original should have been\n        if (!that.readOnly) {\n          colName.push(\"Delete\");\n        }\n        var table = $('<table/>');\n        var thead = $('<thead/>').appendTo(table);\n        var tr = $('<tr/>').appendTo(thead);\n\n        tr.append(colName.map(function (text) {\n          return $('<th/>').text(text);\n        }));\n\n        var tbody = $(\"<tbody/>\").appendTo(table);\n\n        field.data.options.forEach(function (opt) {\n          if (opt.id in valMap) {\n            var tr = $('<tr/>').appendTo(tbody);\n            var checkbox = $(\"<input type='checkbox'>\").prop(\"value\", opt.id);\n            $(\"<td/>\").text(opt.text).appendTo(tr);\n            $(\"<td/>\").text(valMap[opt.id]).appendTo(tr);\n            if (!that.readOnly) {\n              $(\"<td/>\").append(checkbox).appendTo(tr);\n            }\n          }\n        });\n\n        return table;\n      },\n\n      _createDeleteButton: function (field) {\n        var that = this;\n        var deleteButton = $(\"<button/>\").addClass(\"plate-setup-remove-all-button\");\n        deleteButton.id = field.id + \"Delete\";\n        deleteButton.text(\"Manage \" + field.name + \"...\");\n        var buttonContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-remove-all-button-container\");\n        buttonContainer.append(deleteButton);\n\n        field.deleteButton = deleteButton;\n        field.root.find(\".plate-setup-tab-field-right-side\").append(buttonContainer);\n\n        deleteButton.click(function () {\n          that._deleteDialog(field);\n        });\n      }\n\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.engine = function(THIS) {\n    // Methods which look after data changes and stack up accordingly\n    // Remember THIS points to plateLayOutWidget and 'this' points to engine\n    // Use THIS to refer parent this.\n    return {\n      engine: {\n\n        derivative: {},\n        stackUpWithColor: {},\n        stackPointer: 2,\n\n        wellEmpty: function (well) {\n          for (var prop in well) {\n            var curVal = well[prop];\n            if (curVal !== null && curVal !== undefined) {\n              if (Array.isArray(curVal)) {\n                if (curVal.length > 0) {\n                  return false;\n                }\n              } else {\n                return false;\n              }\n            }\n          }\n          return true;\n        },\n\n        searchAndStack: function() {\n          // This method search and stack the change we made.\n          this.stackUpWithColor = {};\n          this.stackPointer = 1;\n          var derivativeJson = {};\n          for (var idx in this.derivative) {\n            var data = this.derivative[idx];\n            var wellData = {};\n            for (var i = 0; i < THIS.globalSelectedAttributes.length; i++) {\n              var attr = THIS.globalSelectedAttributes[i]; \n\n              if (attr in THIS.globalSelectedMultiplexSubfield){\n                var selectedSubFields = THIS.globalSelectedMultiplexSubfield[attr];\n                var newMultiplexVal = [];\n                for (var multiplexIdx in data[attr]){\n                  var curMultiplexVals = data[attr][multiplexIdx];\n                  var newVal = {};\n                  newVal[attr] = curMultiplexVals[attr];\n                  selectedSubFields.forEach(function (subFieldId) {\n                    newVal[subFieldId] = curMultiplexVals[subFieldId];\n                  });\n                  newMultiplexVal.push(newVal);\n                }\n                wellData[attr] = newMultiplexVal;\n              } else {\n                if (data[attr] != null) {\n                  wellData[attr] = data[attr];\n                }\n              }\n            }\n            if ($.isEmptyObject(wellData)) {\n              derivativeJson[idx] = null; \n            } else {\n              derivativeJson[idx] = JSON.stringify(wellData);\n            }\n          }\n\n          while (!$.isEmptyObject(derivativeJson)) {\n            var keys = Object.keys(derivativeJson).map(function (k) {return parseFloat(k, 10);});\n            keys.sort(function (a, b) {return a-b;}); \n\n            var refDerivativeIndex = keys[0];\n            var referenceDerivative = derivativeJson[refDerivativeIndex];\n            var arr = [];\n\n            if (!referenceDerivative) {\n              // if no checked box has value, push it to first spot\n              if (this.stackUpWithColor[0]) {\n                this.stackUpWithColor[0].push(refDerivativeIndex);\n              } else {\n                this.stackUpWithColor[0] = [refDerivativeIndex];\n              }\n\n              delete derivativeJson[refDerivativeIndex];\n            } else {\n              // if checked boxes have values\n              for (var i = 0; i < keys.length; i++) {\n                var idx = keys[i]; \n                if (referenceDerivative == derivativeJson[idx]) {\n                  arr.push(idx);\n                  this.stackUpWithColor[this.stackPointer] = arr;\n                  delete derivativeJson[idx];\n                }\n              }\n              if (arr.length > 0)\n                this.stackPointer++;\n            }\n          }\n        },\n\n        applyColors: function() {\n\n          var wholeNoTiles = 0;\n          var wholePercentage = 0;\n\n          THIS.addBottomTableHeadings();\n\n          for (var i = 0; i < THIS.allTiles.length; i++) {\n            var tile = THIS.allTiles[i];\n            THIS.setTileVisible(tile, false);\n          }\n\n          for (var color = 0; color < this.stackPointer; color++) {\n            var arr = this.stackUpWithColor[color];\n            if (arr) {\n              THIS.addBottomTableRow(color, arr);\n\n              for (var tileIndex in arr) {\n                wholeNoTiles++;\n                var index = this.stackUpWithColor[color][tileIndex]; \n                var tile = THIS.allTiles[index];\n                var well = this.derivative[index];\n                THIS.setTileColor(tile, color, this.stackPointer); \n                // Checks if all the required fields are filled\n                var completion = this.checkCompletion(well, tile);\n                THIS.setTileComplete(tile, completion == 1); \n                wholePercentage = wholePercentage + completion;\n              }\n            }\n          }\n\n          wholePercentage = Math.floor(100 * wholePercentage / wholeNoTiles);\n\n          if (isNaN(wholePercentage)) {\n            THIS.overLayTextContainer.text(\"Completion Percentage: 0%\");\n          } else {\n            THIS.overLayTextContainer.text(\"Completion Percentage: \" + wholePercentage + \"%\");\n          }\n        },\n\n        checkCompletion: function(wellData, tile) {\n          var req = 0; \n          var fill = 0;\n          for (var i = 0; i < THIS.fieldList.length; i++) {\n            var field = THIS.fieldList[i];\n            if (field.checkMultiplexCompletion){\n              // also apply color\n              var multiplexStatus = field.checkMultiplexCompletion(wellData[field.id]);\n              if (multiplexStatus.include) {\n                fill += multiplexStatus.completionPct;\n                req++;\n              }\n            } else {\n              if (field.required) {\n                req++;\n                if (wellData[field.id] !== null) {\n                  fill++;\n                }\n              }\n            }\n          }\n          if (req === fill) {\n            return 1; \n          }\n          return fill / req;\n        },\n      }\n    }\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.fabricEvents = function() {\n    // This object contains Menu items and how it works;\n    return {\n      colorToIndex: {},\n      startCoords: {\n        x: 0,\n        y: 0\n      },\n      focalWell: {\n        row: 0,\n        col: 0\n      },\n      selectedAreas: [],\n\n      _clickCoords: function(evt) {\n        //Get XY Coords for a given event. \n        var rect = evt.e.target.getBoundingClientRect();\n        return {\n          x: evt.e.clientX - rect.left,\n          y: evt.e.clientY - rect.top\n        };\n      },\n\n      _fabricEvents: function() {\n        // Set up event handling. \n        var that = this;\n\n        $(that.target).on(\"getPlates\", function(evt, data) {\n          // This method should be compatable to redo/undo.\n          that.getPlates(JSON.parse(data));\n        });\n\n        that.mainFabricCanvas.on(\"mouse:down\", function(evt) {\n          // Start selecting new area\n          that.selecting = true;\n          var coords = that._clickCoords(evt);\n\n          var areas = that.selectedAreas.slice();\n          var focalWell = that.focalWell;\n          var startCoords = that._wellToCoords(focalWell, true);\n          var rect = that._coordsToRect(startCoords, coords);\n\n          if (evt.e.ctrlKey) {\n            //adding new area\n            startCoords = coords;\n            rect = that._coordsToRect(startCoords, coords);\n            focalWell = that._coordsToWell(startCoords);\n            if (evt.e.shiftKey) {\n              //replacing existing areas\n              areas = [that._rectToArea(rect)];\n            } else {\n              areas.push(that._rectToArea(rect));\n            }\n          } else {\n            if (evt.e.shiftKey) {\n              //Altering last area\n              areas[areas.length - 1] = that._rectToArea(rect);\n            } else {\n              //Creating new area\n              startCoords = coords;\n              rect = that._coordsToRect(startCoords, coords);\n              focalWell = that._coordsToWell(startCoords);\n              areas = [that._rectToArea(rect)];\n            }\n          }\n\n          that.startCoords = startCoords;\n          that.setSelection(areas, focalWell);\n          that.mainFabricCanvas.renderAll();\n        });\n\n        that.mainFabricCanvas.on(\"mouse:move\", function(evt) {\n          if (that.selecting) {\n            // continue selecting new area\n            var areas = that.selectedAreas.slice();\n            var endCoords = that._clickCoords(evt);\n            var rect = that._coordsToRect(that.startCoords, endCoords);\n            var area = that._rectToArea(rect);\n            if (area) {\n              areas[areas.length - 1] = area;\n            }\n\n            that.setSelection(areas, that.focalWell);\n            that.mainFabricCanvas.renderAll();\n          }\n\n        });\n\n        that.mainFabricCanvas.on(\"mouse:up\", function(evt) {\n          // finish selecting new area\n          that.selecting = false;\n          var areas = that.selectedAreas.slice();\n          var endCoords = that._clickCoords(evt);\n          var rect = that._coordsToRect(that.startCoords, endCoords);\n          var area = that._rectToArea(rect);\n          if (area) {\n            areas[areas.length - 1] = area;\n          }\n\n          that.setSelection(areas, that.focalWell);\n          that.decideSelectedFields();\n          that.mainFabricCanvas.renderAll();\n          that._trigger(\"selectedWells\", null, {selectedAddress: that.getSelectedAddress()});\n        });\n      },\n\n      setSelection: function(areas, focalWell) {\n        this.selectedAreas = areas;\n        this.focalWell = focalWell;\n        this.allSelectedObjects = this._areasToTiles(areas);\n        this._setSelectedTiles();\n        this._setFocalWellRect(this.focalWell);\n        document.activeElement.blur();\n      },\n\n      _setFocalWellRect: function(well) {\n        var flag;\n        // check if not allow to add or delete existing wells\n        if (this.disableAddDeleteWell) {\n          var address = this.locToAddress({\n            r: well.row,\n            c: well.col\n          });\n          if  (this.addressAllowToEdit.indexOf(address) < 0) {\n            flag = false;\n            this.setFieldsDisabled(true);\n          } else {\n            flag = true;\n            this.setFieldsDisabled(false);\n          }\n        } else if (well) {\n          flag = true;\n        }\n\n        if (flag) {\n          var rect = this._areaToRect(this._wellToArea(well));\n          var strokeWidth = 2;\n          if (this.focalWellRect) {\n            //update focalWellRect\n            this.focalWellRect.top = rect.top;\n            this.focalWellRect.left = rect.left;\n            this.focalWellRect.width = rect.width - strokeWidth;\n            this.focalWellRect.height = rect.height - strokeWidth;\n          } else {\n            //create focalWellRect\n            this.focalWellRect = new fabric.Rect({\n              width: rect.width - strokeWidth,\n              height: rect.height - strokeWidth,\n              left: rect.left,\n              top: rect.top,\n              fill: null,\n              strokeWidth: strokeWidth,\n              stroke: \"black\",\n              selectable: false\n            });\n            this.mainFabricCanvas.add(this.focalWellRect);\n          }\n        } else {\n          //clear focalWellRect\n          this.mainFabricCanvas.remove(this.focalWellRect);\n          this.focalWellRect = null;\n        }\n      },\n\n      _setSelectedTiles: function() {\n        // Update selected tile display only\n        var selectedTiles = this.allSelectedObjects;\n        this.allTiles.forEach(function(tile) {\n          var selected = selectedTiles.indexOf(tile) >= 0;\n          tile.highlight.visible = selected;\n        })\n      },\n\n      _getSelectedWells: function () {\n        var that = this; \n        return this.allSelectedObjects.map(function (tile) {\n          var well = that.engine.derivative[tile.index];\n          if (!well) {\n            well = that.defaultWell; \n          }\n          return well; \n        }); \n      },\n\n      _getCommonFields: function (wells) {\n        if (wells.length) {\n          var referenceWell = wells[0];\n          var referenceFields = $.extend(true, {}, referenceWell);\n          for (var i = 1; i < wells.length; i++) {\n            var fields = wells[i];\n            for (var field in referenceFields) {\n              if (Array.isArray(referenceFields[field])) {\n                var refArr = referenceFields[field]; \n                var agrArr = []; \n                for (var j = 0; j < refArr.length; j++) {\n                  var v = refArr[j];\n                  if (v && typeof(v) === \"object\") {\n                    if (this.containsObject(v, fields[field])) {\n                      agrArr.push(v);\n                    }\n                  } else {\n                    if ($.inArray(v, fields[field]) >= 0) {\n                      agrArr.push(v);\n                    }\n                  }\n                }\n                referenceFields[field] = agrArr; \n              } else {\n                if (fields[field] && typeof(fields[field]) ===\"object\" && referenceFields[field] && typeof(referenceFields[field]) ===\"object\"){\n                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){\n                    delete referenceFields[field];\n                  }\n                } else if (referenceFields[field] != fields[field]) {\n                  delete referenceFields[field];\n                }\n              }\n            }\n          }\n          return referenceFields\n        } else {\n          return {};\n        }\n      },\n\n      containsObject: function(obj, list) {\n        var equality = [];\n        if (list) {\n          list.forEach(function(val) {\n            //evaluate val and obj\n            var evaluate = [];\n            Object.keys(val).forEach(function(listKey){\n              if (Object.keys(obj).indexOf(listKey) >= 0){\n                var curVal = val[listKey];\n                if (typeof(curVal) === 'object' && curVal) {\n                  if (obj[listKey]){\n                    evaluate.push((curVal.unit === obj[listKey].unit) && (curVal.value === obj[listKey].value));\n                  } else {\n                    // when obj[listKey] is null but curVal is not\n                    evaluate.push(false);\n                  }\n                } else {\n                  evaluate.push(curVal === obj[listKey]);\n                }\n              }\n            });\n            equality.push(evaluate.indexOf(false) < 0);\n          });\n          return equality.indexOf(true) >= 0;\n        } else {\n          return false;\n        }\n      },\n\n      _getCommonWell: function (wells) {\n        if (wells.length) {\n          var referenceWell = wells[0];\n          var referenceFields = $.extend(true, {}, referenceWell);\n          for (var i = 1; i < wells.length; i++) {\n            var well = wells[i];\n            var fields = well;\n            for (var field in referenceFields) {\n              if (Array.isArray(referenceFields[field])) {\n                var refArr = referenceFields[field]; \n                var agrArr = []; \n                for (var j = 0; j < refArr.length; j++) {\n                  var v = refArr[j];\n                  // for multiplex field\n                  if (typeof(refArr[j]) ===\"object\"){\n                    if (this.containsObject(v, fields[field])) {\n                      agrArr.push(v);\n                    }\n                  } else {\n                    if ($.inArray(v, fields[field]) >= 0) {\n                      agrArr.push(v);\n                    }\n                  }\n                }\n                referenceFields[field] = agrArr; \n              } else {\n                if (fields[field] && typeof(fields[field]) ===\"object\" && referenceFields[field] && typeof(referenceFields[field]) ===\"object\"){\n                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){\n                    referenceFields[field] = null;\n                  }\n                } else if (referenceFields[field] != fields[field]) {\n                  referenceFields[field] = null;\n                }\n\n              }\n            }\n          }\n          return referenceFields;\n        } else {\n          return this.defaultWell; \n        }\n      }, \n\n      _getAllMultipleVal: function (wells) {\n        var multipleFieldList = this.multipleFieldList;\n\n        multipleFieldList.forEach(function(multiplexField) {\n          if(wells.length) {\n            var curMultipleVal = {};\n            wells.forEach(function (wellData) {\n              var id = multiplexField.id;\n              if (wellData[id]){\n                if (wellData[id].length > 0) {\n                  wellData[id].forEach(function (multipleVal) {\n                    if (typeof(multipleVal) === 'object') {\n                      if (multipleVal[id] in curMultipleVal) {\n                        curMultipleVal[multipleVal[id]] ++;\n                      } else {\n                        curMultipleVal[multipleVal[id]] = 1;\n                      }\n                    } else {\n                      if (multipleVal in curMultipleVal) {\n                        curMultipleVal[multipleVal] ++;\n\n                      } else {\n                        curMultipleVal[multipleVal] = 1;\n                      }\n                    }\n                  })\n                }\n              }\n            });\n            multiplexField.allSelectedMultipleVal = curMultipleVal;\n          } else {\n            multiplexField.allSelectedMultipleVal = null\n          }\n        });\n      },\n\n      decideSelectedFields: function() {\n        var wells = this._getSelectedWells();\n        this._getAllMultipleVal(wells);\n        this.applyFieldWarning(wells);\n        var well = this._getCommonWell(wells); \n        this._addDataToTabFields(well);\n      },\n\n      // get well value differences for each well in wellsHash\n      getDifferentWellsVals: function(wellsHash) {\n        var wells = [];\n        for (var wellId in wellsHash){\n          wells.push(wellsHash[wellId]);\n        }\n        var differentWellsVals = {};\n        if (wells.length > 1){\n          var commonWell = this._getCommonWell(wells);\n          var allFieldVal = {};\n          for (var fieldIdx in wellsHash[0]) {\n            allFieldVal[fieldIdx] = [];\n          }\n          for (var wellIdx in wells){\n            var diffWellVal = {};\n            var curWellData = wells[wellIdx];\n            for (var fieldId in curWellData) {\n              var commonVal = commonWell[fieldId];\n              var curVal = curWellData[fieldId];\n              var newVal = null;\n              if (Array.isArray(curVal)) {\n                // get uncommonVal\n                newVal = [];\n                for (var idx = 0; idx < curVal.length; idx ++){\n                  var curMultiVal = curVal[idx];\n                  // multiplex field\n                  if (curMultiVal && typeof(curMultiVal === \"object\")){\n                    if (!this.containsObject(curMultiVal, commonVal)) {\n                      newVal.push(curMultiVal);\n                      if (!this.containsObject(curMultiVal, allFieldVal[fieldId])) {\n                        allFieldVal[fieldId].push(curMultiVal);\n                      }\n                    }\n                  } else {\n                    if (commonVal.indexOf(curMultiVal) >= 0) {\n                      newVal.push(curMultiVal);\n                      if (!allFieldVal[fieldId].indexOf(curMultiVal) >= 0) {\n                        allFieldVal[fieldId].push(curMultiVal);\n                      }\n                    }\n                  }\n                }\n              } else if (curVal && typeof(curVal) === \"object\"){\n                if (commonVal && typeof(commonVal) ===\"object\"){\n                  if (!((curVal.value === commonVal.value) || (curVal.unit === commonVal.unit))){\n                    newVal = curVal;\n                    if (!this.containsObject(curVal, allFieldVal[fieldId])) {\n                      allFieldVal[fieldId].push(curVal);\n                    }\n                  }\n                } else {\n                  newVal = curVal;\n                  if (!this.containsObject(curVal, allFieldVal[fieldId])) {\n                    allFieldVal[fieldId].push(curVal);\n                  }\n                }\n              } else if (curVal !== commonVal) {\n                newVal = curVal;\n                if (!allFieldVal[fieldId].indexOf(curVal) >= 0) {\n                  allFieldVal[fieldId].push(curVal);\n                }\n              }\n              diffWellVal[fieldId] = newVal;\n            }\n\n\n            differentWellsVals[wellIdx] = diffWellVal;\n          }\n\n          // clean up step for fields that are empty\n          for (var fieldId in allFieldVal) {\n            if (allFieldVal[fieldId].length === 0) {\n              for (var wellIdx in differentWellsVals){\n                delete differentWellsVals[wellIdx][fieldId];\n              }\n            }\n          }\n\n          return differentWellsVals;\n        } else if (wellsHash[0]) {\n          var well = {};\n          for (var fieldId in wellsHash[0]) {\n            var curVal = wellsHash[0][fieldId];\n            if (Array.isArray(curVal)){\n              if (curVal.length > 0) {\n                well[fieldId] = curVal\n              }\n            } else if (curVal){\n              well[fieldId] = curVal;\n            }\n          }\n          return {\n            0: well\n          };\n        }\n      },\n\n      // get all wells that has data\n      getWellSetAddressWithData: function(){\n        var address = [];\n        var derivative = this.engine.derivative;\n        for (var id in derivative){\n          address.push(this.indexToAddress(id));\n        }\n        return address;\n      }\n\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\nplateLayOutWidget.assets = function () {\n    return {\n        _assets: {\n            doImg: '&#10003;',\n            dontImg: '',\n            warningImg: '&#9888;'\n        }\n    };\n};\n","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.interface = function() {\n    // interface holds all the methods to put the interface in place\n    return {\n\n      _createInterface: function() {\n\n        var divIdentifier = '<div></div>';\n        this.container = this._createElement(divIdentifier).addClass(\"plate-setup-wrapper\");\n        this.topSection = this._createElement(divIdentifier).addClass(\"plate-setup-top-section\");\n\n        this.topLeft = this._createElement(divIdentifier).addClass(\"plate-setup-top-left\");\n        this.topRight = this._createElement(divIdentifier).addClass(\"plate-setup-top-right\");\n\n        this.overLayContainer = this._createElement(divIdentifier).addClass(\"plate-setup-overlay-container\");\n        this.canvasContainer = this._createElement(divIdentifier).addClass(\"plate-setup-canvas-container\");\n\n        this._createOverLay();\n        $(this.topLeft).append(this.overLayContainer);\n\n        this._createCanvas();\n        $(this.topLeft).append(this.canvasContainer);\n\n\n        $(this.topSection).append(this.topLeft);\n        $(this.topSection).append(this.topRight);\n\n        $(this.container).append(this.topSection);\n        $(this.element).append(this.container);\n\n        this._initiateFabricCanvas();\n\n        this._createTabAtRight();\n        this._createTabs();\n\n        this._placePresetTabs();\n        // Bottom of the screen\n        this._bottomScreen();\n        // Canvas\n        this._canvas();\n\n        this.bottomForFirstTime();\n\n        var that = this;\n        this._setShortcuts();\n        $(document.body).keyup(function(e) {\n          that._handleShortcuts(e);\n        });\n\n        this._configureUndoRedoArray();\n      },\n\n      _createElement: function(element) {\n        return $(element);\n      },\n\n      _setShortcuts: function () {\n        var that = this; \n        window.addEventListener(\"cut\", function (e) {\n          if (document.activeElement == document.body) {\n            that.copyCriteria();\n            that.clearCriteria();\n            e.preventDefault();\n          }\n        });\n        window.addEventListener(\"copy\", function (e) {\n          if (document.activeElement == document.body) {\n            that.copyCriteria();\n            e.preventDefault();\n          }\n        });\n        window.addEventListener(\"paste\", function (e) {\n          if (document.activeElement == document.body) {\n            that.pasteCriteria();\n            e.preventDefault();\n          }\n        });\n      },\n\n      _handleShortcuts: function(e) {\n        if (document.activeElement === document.body) {\n          if (e.keyCode == 46) {\n            this.clearCriteria();\n            e.preventDefault();\n          } else if (e.ctrlKey || e.metaKey) {\n            if (e.keyCode == 90) {\n              if (e.shiftKey) {\n                this.redo();\n              } else {\n                this.undo();\n              }\n              e.preventDefault();\n            } else if (e.keyCode == 89) {\n              this.redo();\n              e.preventDefault();\n            }\n          }\n        }\n      },\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.loadPlate = function(THIS) {\n    // Methods which look after data changes and stack up accordingly\n    // Remember THIS points to plateLayOutWidget and 'this' points to engine\n    return {\n\n      getPlates: function (data) {\n        //sanitize input\n        var derivative = {}; \n        for (var index in data.derivative) {\n          var well = data.derivative[index]; \n          derivative[index] = this.sanitizeWell(well); \n        }\n\n        var checkboxes = data.checkboxes || []; \n        var selection = this.sanitizeAreas(data.selectedAreas, data.focalWell); \n\n        var sanitized = {\n          \"derivative\": derivative,\n          \"checkboxes\": checkboxes,\n          \"selectedAreas\": selection.selectedAreas,\n          \"focalWell\": selection.focalWell\n        }; \n\n        this.setData(sanitized);\n      }, \n\n      sanitizeAreas: function (selectedAreas, focalWell) {\n        var that = this; \n        var rows = this.dimensions.rows;\n        var cols = this.dimensions.cols;\n\n        if (!selectedAreas) {\n          selectedAreas = [];\n        }\n        if (selectedAreas.length) {\n          selectedAreas = selectedAreas.map(function (area) {\n            return {\n              minCol: that._coordIndex(Math.min(area.minCol, area.maxCol), cols), \n              minRow: that._coordIndex(Math.min(area.minRow, area.maxRow), rows), \n              maxCol: that._coordIndex(Math.max(area.minCol, area.maxCol), cols), \n              maxRow: that._coordIndex(Math.max(area.minRow, area.maxRow), rows)\n            }; \n          }); \n          var area = selectedAreas[selectedAreas.length - 1];\n          if (focalWell && !this._wellInArea(focalWell, area)) {\n            focalWell = null;\n          }\n          if (!focalWell) {\n            focalWell = {\n              row: area.minRow,\n              col: area.minCol\n            };\n          }\n        } else {\n          if (!focalWell) {\n            focalWell = {\n              row: 0,\n              col: 0\n            };\n          }\n          selectedAreas = [this._wellToArea(focalWell)];\n        }\n        return {\n          selectedAreas: selectedAreas, \n          focalWell: focalWell\n        };\n      }, \n\n      sanitizeWell: function (well) {\n        var newWell = {};\n        for (var i = 0; i < this.fieldList.length; i++) {\n          var field = this.fieldList[i];\n          newWell[field.id] = field.parseValue(well[field.id]);\n        }\n        return newWell; \n      }, \n\n      setData: function(data) {\n        this.engine.derivative = $.extend(true, {}, data.derivative);\n        this.setCheckboxes(data.checkboxes);\n        this.setSelection(data.selectedAreas, data.focalWell);\n        this._colorMixer();\n        this.decideSelectedFields();\n        this.mainFabricCanvas.renderAll();\n      },\n\n    }\n  }\n})(jQuery, fabric);","var GET_PLATES = 'getPlates';\nvar IS_READ_ONLY = 'isReadOnly';\nvar IS_DISABLE_ADD_DELETE_WELL = 'isDisableAddDeleteWell';\nvar GET_SELECTED_OBJECT = 'getSelectedObject';\nvar SETSELECTEDWELL = 'setSelectedWell';","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.overlay = function() {\n    // overlay holds all the methods to put the part just above the canvas which contains all those\n    // 'completion percentage' annd 'copy Criteria' button etc ...\n    return {\n\n      _createOverLay: function() {\n\n        var that = this;\n        this.overLayTextContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-overlay-text-container\");\n        this.overLayTextContainer.text(\"Completion Percentage:\");\n        this.overLayContainer.append(this.overLayTextContainer);\n        this.overLayButtonContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-overlay-button-container\");\n        this.overLayContainer.append(this.overLayButtonContainer);\n\n        this.clearCriteriaButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.clearCriteriaButton.text(\"Clear\");\n        this.overLayButtonContainer.append(this.clearCriteriaButton);\n\n        this.clearCriteriaButton.click(function(evt) {\n          that.clearCriteria();\n        });\n\n        this.copyCriteriaButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.copyCriteriaButton.text(\"Copy\");\n        this.overLayButtonContainer.append(this.copyCriteriaButton);\n\n        this.copyCriteriaButton.click(function(evt) {\n          that.copyCriteria();\n        });\n\n        this.pasteCriteriaButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.pasteCriteriaButton.text(\"Paste\");\n        this.overLayButtonContainer.append(this.pasteCriteriaButton);\n\n        this.pasteCriteriaButton.click(function(evt) {\n          that.pasteCriteria();\n        });\n\n        this.undoButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.undoButton.text(\"Undo\");\n        this.overLayButtonContainer.append(this.undoButton);\n\n        this.undoButton.click(function(evt) {\n          that.undo();\n        });\n\n        this.redoButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.redoButton.text(\"Redo\");\n        this.overLayButtonContainer.append(this.redoButton);\n\n        this.redoButton.click(function(evt) {\n          that.redo();\n        });\n\n      },\n\n      clearCriteria: function() {\n        if (this.allSelectedObjects) {\n          var noOfSelectedObjects = this.allSelectedObjects.length;\n          var hasWellUpdate = false;\n          for (var objectIndex = 0; objectIndex < noOfSelectedObjects; objectIndex++) {\n            var tile = this.allSelectedObjects[objectIndex];\n            if (tile.index in this.engine.derivative) {\n              // handling for clearing well when not allowed to add or delete wells\n              if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {\n                var well = JSON.parse(JSON.stringify(this.defaultWell));\n                var defaultValue = this.emptyWellWithDefaultVal;\n                for (var key in defaultValue){\n                  if (key in well) {\n                    well[key] = defaultValue[key];\n                    this._applyFieldData(key, defaultValue[key]);\n                  } else {\n                    console.log(\"Well does not contain key: \" + key + \", please contact support\");\n                  }\n                }\n                this.engine.derivative[tile.index] = well;\n              } else {\n                delete this.engine.derivative[tile.index];\n              }\n              hasWellUpdate = true;\n            }\n          }\n          if (hasWellUpdate){\n            this.derivativeChange();\n          }\n\n          this._colorMixer();\n          this.decideSelectedFields();\n        } else {\n          alert(\"Please select any well\");\n        }\n      },\n\n      copyCriteria: function() {\n        if (this.allSelectedObjects) {\n          var wells = this._getSelectedWells(); \n          this.commonWell = this._getCommonFields(wells); \n        } else {\n          alert(\"Please select any well.\");\n        }\n      },\n\n      pasteCriteria: function() {\n        if (this.commonWell) {\n          this._addAllData(this.commonWell);\n          this.decideSelectedFields();\n          this.mainFabricCanvas.renderAll();\n        }\n      }\n    };\n  }\n})(jQuery, fabric);","$.widget(\"DNA.plateLayOut\", {\n\n  plateLayOutWidget: {},\n\n  options: {\n    value: 0\n  },\n\n  allTiles: [], // All tiles containes all thise circles in the canvas\n\n  addressToLoc: function (layoutAddress) {\n    var m = /^([A-Z]+)(\\d+)$/.exec(layoutAddress.trim().toUpperCase())\n    if (m) {\n      var row_v = m[1]; \n      var col = parseInt(m[2])-1;\n      var row; \n      for (var i = 0; i < row_v.length; i++) {\n        var c = row_v.charCodeAt(i) - 65; \n        if (i) {\n            row += 1;\n            row *= 26; \n            row += c ; \n        } else {\n            row = c;\n        }\n      }\n      return {\n        r: row, \n        c: col\n      };\n    } else {\n      throw layoutAddress + \" not a proper layout address\"; \n    }\n  },\n\n  locToIndex: function (loc, dimensions) {\n    if (!dimensions) {\n      dimensions = this.dimensions;\n    }\n    if (loc.r < 0) {\n      t\n    }\n    if (!(loc.r >= 0 && loc.r < dimensions.rows)) {\n      throw \"Row index \" + (loc.r + 1) + \" invalid\"; \n    }\n    if (!(loc.c >= 0 && loc.c < dimensions.cols)) {\n      throw \"Column index \" + (loc.c + 1) + \" invalid\"; \n    }\n    return loc.r*dimensions.cols + loc.c; \n  },\n\n  addressToIndex: function (layoutAddress, dimensions) {\n    var loc = this.addressToLoc(layoutAddress); \n    return this.locToIndex(loc, dimensions); \n  }, \n\n  _rowKey: function (i) {\n    var c1 = i % 26;\n    var c2 = (i - c1) / 26;\n    var code = String.fromCharCode(65 + c1);\n    if (c2 > 0) {\n      code = String.fromCharCode(64 + c2) + code;\n    }\n    return code;\n  }, \n\n  indexToLoc: function (index, dimensions) {\n    if (!dimensions) {\n      dimensions = this.dimensions;\n    }\n\n    if (index >= dimensions.rows * dimensions.cols) {\n      throw \"Index too high: \" + index.toString(10); \n    }\n    var loc = {}; \n    loc.c = index % dimensions.cols;\n    loc.r = (index - loc.c) / dimensions.cols;\n\n    return loc; \n  },\n\n  locToAddress: function (loc) {\n    return this._rowKey(loc.r) + (loc.c + 1).toString(10);\n  },\n\n  indexToAddress: function (index, dimensions) {\n    var loc = this.indexToLoc(index, dimensions); \n    return this.locToAddress(loc); \n  },\n\n  getDimensions: function () {\n    return $.extend(true, {}, this.dimensions);\n  },\n\n  _create: function() {\n    var rows = parseInt(this.options.numRows || 8);\n    var cols = parseInt(this.options.numCols || 12);\n    this.dimensions = {\n      rows: rows,\n      cols: cols\n    };\n    this.rowIndex = [];\n    for (var i = 0; i < rows; i++) {\n      this.rowIndex.push(this._rowKey(i));\n    }\n\n    this.target = (this.element[0].id) ? \"#\" + this.element[0].id : \".\" + this.element[0].className;\n\n    // Import classes from other files.. Here we import it using extend and add it to this\n    // object. internally we add to widget.DNA.getPlates.prototype.\n    // Helpers are methods which return other methods and objects.\n    // add Objects to plateLayOutWidget and it will be added to this object.\n    // set read only well\n    if (this.options.readOnly){\n      this.isReadOnly(true);\n    }\n\n    for (var component in plateLayOutWidget) {\n      // Incase some properties has to initialize with data from options hash,\n      // we provide it sending this object.\n      $.extend(this, new plateLayOutWidget[component](this));\n    }\n\n    this.imgSrc = this.options.imgSrc || \"assets\";\n\n    this._createInterface();\n\n    this._trigger(\"created\", null, this);\n\n    return this;\n  },\n\n  _init: function() {\n    // This is invoked when the user use the plugin after _create is called.\n    // The point is _create is invoked for the very first time and for all other\n    // times _init is used.\n  },\n\n  addData: function() {\n    alert(\"wow this is good\");\n  },\n\n  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}\n  getTextDerivative: function(wellsData) {\n    var textDerivative = {};\n    var fieldMap = this.fieldMap;\n    for (var idx in wellsData){\n      var textValWell = {};\n      var textFieldIdWell = {};\n      var curWellData = wellsData[idx];\n      for (var fieldId in curWellData){\n        if (fieldId in this.fieldMap){\n          var field = this.fieldMap[fieldId];\n          var textVal = field.parseText(curWellData[fieldId]);\n          textFieldIdWell[field.name] = textVal;\n          textValWell[fieldId] = textVal;\n        } else {\n          // do not convert if not a field (ex: layout_address)\n          textFieldIdWell[fieldId] = curWellData[fieldId];\n          textValWell[fieldId] = curWellData[fieldId];\n        }\n      }\n      textDerivative[idx] = {\n        textVal: textValWell,\n        textFieldVal: textFieldIdWell\n      };\n    }\n\n    return textDerivative;\n  },\n\n  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}\n  getWellsDifferences: function(wellsData) {\n    return this.getDifferentWellsVals(wellsData);\n  },\n\n  setFieldsDisabled: function(flag){\n    this.fieldList.forEach(function(field){\n      field.disabled(flag);\n    });\n  },\n\n  isReadOnly: function(flag){\n    if (flag){\n      this.readOnly = true;\n    } else {\n      this.readOnly = false;\n    }\n    this.readOnlyHandler();\n  },\n\n  readOnlyHandler: function(){\n    if (this.readOnly){\n      this.overLayButtonContainer.css(\"display\", \"none\");\n      $('.multiple-field-manage-delete-button').css(\"display\", \"none\");\n      this.setFieldsDisabled(true);\n    } else {\n      this.overLayButtonContainer.css(\"display\", \"flex\");\n      $('.multiple-field-manage-delete-button').css(\"display\", \"none\");\n      if (!this.disableAddDeleteWell) {\n        this.setFieldsDisabled(false);\n      }\n    }\n  },\n\n  disableAddDeleteWell: null,\n  // column_with_default_val will be used to determine empty wells, format: {field_name: default_val}\n  isDisableAddDeleteWell: function(flag, column_with_default_val){\n    if (flag){\n      this.disableAddDeleteWell = true;\n      this.addressAllowToEdit = this.getWellSetAddressWithData();\n      // configure undo redo action\n      this.actionPointer = 0;\n      this.undoRedoArray = [];\n      this.undoRedoArray.push(this.createObject());\n      if (column_with_default_val) {\n        this.emptyWellWithDefaultVal = column_with_default_val;\n      }\n    } else {\n      this.disableAddDeleteWell = false;\n      this.setFieldsDisabled(false);\n      this.emptyWellWithDefaultVal = null;\n    }\n    this._fabricEvents();\n  },\n\n  getSelectedObject: function() {\n    var selectedAddress = [];\n    for (var i = 0; i < this.allSelectedObjects.length; i++){\n      selectedAddress.push(this.allSelectedObjects[i].address);\n    }\n    var selectedObjects = {};\n    var derivative = this.engine.derivative;\n    for (var loc in derivative){\n      var address = this.indexToAddress(loc);\n      if (selectedAddress.indexOf(address) >= 0) {\n        selectedObjects[address] = derivative[loc];\n      }\n    }\n    return selectedObjects;\n  },\n\n  getSelectedIndex: function() {\n    return this.allSelectedObjects.map(function(selectedObj){\n        return that.addressToIndex(selectedObj.address)\n    });\n  },\n\n  getSelectedAddress: function() {\n    return this.allSelectedObjects.map(function(selectedObj){\n      return selectedObj.address;\n    });\n  },\n\n  setSelectedWell: function(addressList) {\n    var areas = [];\n    var minRow = 999;\n    var locMap = {};\n    for (var id = 0; id < addressList.length; id++){\n      var wellIdx = this.addressToIndex(addressList[id]);\n      var loc = this.indexToLoc(wellIdx);\n      areas.push({\n        minCol: loc.c,\n        minRow: loc.r,\n        maxCol: loc.c,\n        maxRow: loc.r\n      });\n      if (loc.r <= minRow) {\n        minRow = loc.r;\n        if (loc.r in locMap) {\n          locMap[loc.r].push(loc.c);\n        } else {\n          locMap[loc.r] = [loc.c];\n        }\n      }\n    }\n    var focalWell = {\n      row: minRow,\n      col: Math.min.apply(null, locMap[minRow])\n    };\n\n    this.setSelection(areas, focalWell);\n    this.decideSelectedFields();\n    this.mainFabricCanvas.renderAll();\n  }\n\n});","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.preset = function(me) {\n    // All the preset action goes here\n    return {\n\n      presets: [],\n\n      _placePresetTabs: function() {\n        var presets = this.options.attributes.presets;\n\n        if (presets && presets.length) {\n          this.wellAttrContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-well-attr-container\")\n            .text(\"Checkbox presets\");\n          this.tabContainer.append(this.wellAttrContainer);\n\n          this.presetTabContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-preset-container\");\n          this.tabContainer.append(this.presetTabContainer);\n\n          for (var i = 0; i < presets.length; i++) {\n            var preset = presets[i];\n            var divText = this._createElement(\"<div></div>\").addClass(\"plate-setup-prest-tab-div\")\n              .text(preset.title);\n\n            var presetButton = this._createElement(\"<div></div>\").addClass(\"plate-setup-prest-tab\")\n              .data(\"preset\", preset.fields).append(divText);\n            this.presetTabContainer.append(presetButton);\n\n            var that = this;\n            presetButton.click(function() {\n              var preset = $(this);\n              that._selectPreset(preset);\n            });\n            this.presets.push(presetButton);\n          }\n        }\n      },\n\n      _clearPresetSelection: function() {\n        for (var j = 0; j < this.presets.length; j++) {\n          var p = this.presets[j]; \n          p.removeClass(\"plate-setup-prest-tab-selected\")\n            .addClass(\"plate-setup-prest-tab\"); \n        }\n      },\n\n      _selectPreset: function (preset) {\n        this.setCheckboxes(preset.data(\"preset\")); \n        preset.removeClass(\"plate-setup-prest-tab\")\n          .addClass(\"plate-setup-prest-tab-selected\");\n      },\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.tabs = function() {\n    // Tabs crete and manage tabs at the right side of the canvas.\n    return {\n\n      allTabs: [],\n\n      defaultWell: {},\n\n      allDataTabs: [], // To hold all the tab contents. this contains all the tabs and its elements and elements\n      // Settings as a whole. its very usefull, when we have units for a specific field.\n      // it goes like tabs-> individual field-> units and checkbox\n\n      _createTabAtRight: function() {\n        this.tabContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-tab-container\");\n        $(this.topRight).append(this.tabContainer);\n      },\n\n      _createTabs: function() {\n        // this could be done using z-index. just imagine few cards stacked up.\n        // Check if options has tab data.\n        // Originally we will be pulling tab data from developer.\n        // Now we are building upon dummy data.\n        this.tabHead = this._createElement(\"<div></div>\").addClass(\"plate-setup-tab-head\");\n        $(this.tabContainer).append(this.tabHead);\n\n        var tabData = this.options.attributes.tabs;\n        var that = this;\n\n        tabData.forEach(function (tab, tabIndex) {\n          that.allTabs[tabIndex] = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab\");\n          $(that.allTabs[tabIndex]).data(\"index\", tabIndex)\n            .text(tab.name);\n\n          $(that.allTabs[tabIndex]).click(function() {\n            that._tabClickHandler(this);\n          });\n\n          $(that.tabHead).append(that.allTabs[tabIndex]);\n        }); \n\n        this.tabDataContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-tab-data-container\");\n        $(this.tabContainer).append(this.tabDataContainer);\n\n        this._addDataTabs(tabData);\n\n        $(this.allTabs[0]).click();\n\n        this._addTabData();\n      },\n\n      _tabClickHandler: function(clickedTab) {\n\n        if (this.selectedTab) {\n          $(this.selectedTab).removeClass(\"plate-setup-tab-selected\")\n            .addClass(\"plate-setup-tab\");\n\n          var previouslyClickedTabIndex = $(this.selectedTab).data(\"index\");\n          $(this.allDataTabs[previouslyClickedTabIndex]).css(\"z-index\", 0);\n          this.readOnlyHandler();\n        }\n\n        $(clickedTab).addClass(\"plate-setup-tab-selected\");\n\n        this.selectedTab = clickedTab;\n\n        var clickedTabIndex = $(clickedTab).data(\"index\");\n        $(this.allDataTabs[clickedTabIndex]).css(\"z-index\", 1000);\n      },\n\n      _addDataTabs: function(tabs) {\n\n        var tabIndex = 0;\n\n        for (var tabData in tabs) {\n          this.allDataTabs[tabIndex++] = this._createElement(\"<div></div>\").addClass(\"plate-setup-data-div\")\n            .css(\"z-index\", 0);\n          $(this.tabDataContainer).append(this.allDataTabs[tabIndex - 1]);\n        }\n      }\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.undoRedoManager = function(THIS) {\n\n    return {\n\n      undoRedoArray: [],\n\n      actionPointer: null,\n\n      addToUndoRedo: function(data) {\n\n        if (this.actionPointer != null) {\n          var i = this.actionPointer + 1; \n          if (i < this.undoRedoArray.length) {\n            this.undoRedoArray.splice(i, this.undoRedoArray.length - i);\n          }\n        }\n        this.actionPointer = null;\n        this.undoRedoArray.push($.extend(true, {}, data));\n      },\n\n      _configureUndoRedoArray: function() {\n\n        var data = {\n          checkboxes: [],\n          derivative: {},\n          selectedAreas: [{\n            minRow: 0,\n            minCol: 0,\n            maxRow: 0,\n            maxCol: 0\n          }],\n          focalWell: {\n            row: 0,\n            col: 0\n          }\n        };\n\n        this.undoRedoArray = []; \n        this.actionPointer = null; \n        this.undoRedoArray.push($.extend({}, data));\n      },\n\n      undo: function() {\n        console.log(\"undo\");\n        return this.shiftUndoRedo(-1); \n      },\n\n      redo: function() {\n        console.log(\"redo\");\n        return this.shiftUndoRedo(1); \n      }, \n\n      shiftUndoRedo: function (pointerDiff) {\n        var pointer = this.actionPointer;\n        if (pointer == null) {\n          pointer = this.undoRedoArray.length - 1; \n        }\n        pointer += pointerDiff; \n        return this.setUndoRedo(pointer); \n      }, \n\n      setUndoRedo: function (pointer) {\n        if (pointer < 0) {\n          return false; \n        }\n        if (pointer >= this.undoRedoArray.length) {\n          return false; \n        }\n        this.undoRedoActive = true; \n        this.setData(this.undoRedoArray[pointer]);\n        this.actionPointer = pointer; \n        this.undoRedoActive = false;\n        this.derivativeChange();\n        return true;\n      }\n    }\n  };\n\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.wellArea = function(fabric) {\n\n    return {\n\n      _areasToTiles: function(areas) {\n        //Convert areas to tiles\n        var cols = this.dimensions.cols;\n        var that = this;\n        return areas.reduce(function(tiles, area) {\n          if (area) {\n            for (var r = area.minRow; r <= area.maxRow; r++) {\n              for (var c = area.minCol; c <= area.maxCol; c++) {\n                var tile = that.allTiles[c + cols * r];\n                if (tiles.indexOf(tile) < 0) {\n                  if (that.disableAddDeleteWell){\n                    if(that.addressAllowToEdit.indexOf(tile.address) >= 0){\n                      tiles.push(tile);\n                    }\n                  } else {\n                    tiles.push(tile);\n                  }\n                }\n              }\n            }\n          }\n          return tiles;\n        }, []);\n      },\n\n      _encodeArea: function(area) {\n        //Encode area as string\n        if ((area.minRow == area.maxRow) && (area.minCol == area.maxCol)) {\n          return this.rowIndex[area.minRow] + area.minCol.toString(10);\n        } else {\n          return this.rowIndex[area.minRow] + area.minCol.toString(10) + \":\" + this.rowIndex[area.maxRow] + area.maxCol.toString(10);\n        }\n      },\n\n      _encodeAreas: function(areas) {\n        //Encode an array of areas as a string\n        var that = this;\n        return areas.map(function(area) {\n          return that._encodeArea(area);\n        }).join(\",\");\n      },\n\n      _decodeWell: function(wellAddress) {\n        var that = this;\n        var adRx = new RegExp(\"^\\\\s*(\" + that.rowIndex.join(\"|\") + \")(\\\\d+)\\\\s*$\")\n        var rcRx = /^\\s*R(\\d+)C(\\d+)\\s*$/i;\n\n        var match;\n        match = wellAddress.match(adRx);\n        if (match) {\n          var row = that.rowIndex.indexOf(match[1]);\n          if (row >= 0) {\n            return {\n              row: row,\n              col: parseInt(match[2]) - 1\n            };\n          }\n        }\n        match = wellAddress.match(rcRx);\n        if (match) {\n          return {\n            row: parseInt(match[1]) - 1,\n            col: parseInt(match[2]) - 1\n          };\n        }\n\n        throw \"Invalid well address: \" + wellAddress;\n      },\n\n      _decodeArea: function(areaAddress) {\n        //Decode single area as string\n        var that = this;\n        var wells = areaAddress.split(\":\").map(function(wellAddress) {\n          return that._decodeWell(wellAddress);\n        })\n        if (wells.length == 1) {\n          return {\n            minRow: wells[0].row,\n            minCol: wells[0].col,\n            maxRow: wells[0].row,\n            maxCol: wells[0].col\n          }\n        } else if (wells.length == 2) {\n          var minRow = Math.min(wells[0].row, wells[1].row)\n          return {\n            minRow: Math.min(wells[0].row, wells[1].row),\n            minCol: Math.min(wells[0].col, wells[1].col),\n            maxRow: Math.max(wells[0].row, wells[1].row),\n            maxCol: Math.max(wells[0].col, wells[1].col)\n          }\n        } else {\n          throw \"Invalid address: \" + areaAddress;\n        }\n      },\n\n      _decodeAreas: function(areasAddress) {\n        //Decode single area as string\n        var that = this;\n        return areasAddress.split(\",\").map(function(areaAddress) {\n          return that._decodeArea(areaAddress);\n        });\n      },\n\n      _wellToArea: function(well) {\n        //Convert a well to an area\n        return {\n          minCol: well.col,\n          minRow: well.row,\n          maxCol: well.col,\n          maxRow: well.row\n        }\n      },\n\n      _wellInArea: function(well, area) {\n        //Determine if a well lies within an area\n        return well.row >= area.minRow && well.row <= area.maxRow && well.col >= area.minCol && well.col <= area.maxCol;\n      },\n\n      _coordsToRect: function(startCoords, endCoords) {\n        //Convert two XY coords to a bounding box\n        var left = Math.min(startCoords.x, endCoords.x);\n        var top = Math.min(startCoords.y, endCoords.y);\n        var height = Math.abs(endCoords.y - startCoords.y);\n        var width = Math.abs(endCoords.x - startCoords.x);\n        return {\n          top: top,\n          left: left,\n          height: height,\n          width: width\n        };\n      },\n\n      _coordIndex: function(v, count) {\n        var i;\n        if (v < 0) {\n          i = 0;\n        } else if (v >= count) {\n          i = count - 1;\n        } else {\n          i = Math.floor(v);\n        }\n        return i;\n      },\n\n      _coordsToWell: function(coord) {\n        //Convert a coordinate to a well\n        var cols = this.dimensions.cols;\n        var rows = this.dimensions.rows;\n\n        var w = this.sizes.spacing; \n        var m = this.sizes.label_spacing; \n\n        var x = (coord.x - m) / w;\n        var y = (coord.y - m) / w;\n\n        var row = this._coordIndex(y, rows);\n        var col = this._coordIndex(x, cols);\n\n        return {\n          row: row,\n          col: col,\n        };\n      },\n\n      _wellToCoords: function(well, center) {\n        //Convert a well to a coordinate\n        var w = this.sizes.spacing; \n        var m = this.sizes.label_spacing; \n        var x = well.col * w + m;\n        var y = well.row * w + m;\n        if (center) {\n          var hw = w/2;\n          x = x + hw;\n          y = y + hw;\n        }\n\n        return {\n          x: x,\n          y: y\n        };\n      },\n\n      _areaToRect: function(area) {\n        //Convert area to rectangle\n        var rows = area.maxRow - area.minRow + 1;\n        var cols = area.maxCol - area.minCol + 1;\n\n        var w = this.sizes.spacing; \n        var m = this.sizes.label_spacing; \n\n        return {\n          top: area.minRow * w + m,\n          left: area.minCol * w + m,\n          height: rows * w,\n          width: cols * w\n        }\n      },\n\n      _rectToArea: function(rect) {\n        //Convert a rectangular region to an area\n        var rows = this.dimensions.rows;\n        var cols = this.dimensions.cols;\n\n        var w = this.sizes.spacing; \n        var m = this.sizes.label_spacing; \n\n        var left = (rect.left - m) / w;\n        var top = (rect.top - m) / w;\n        var height = rect.height / w;\n        var width = rect.width / w;\n        var right = left + width;\n        var bottom = top + height;\n\n        //select whole row\n        if (right < 0) {\n          right = cols;\n        }\n        if (left >= cols) {\n          left = 0;\n        }\n        //select whole col\n        if (bottom < 0) {\n          bottom = rows;\n        }\n        if (top <= 0) {\n          top = 0;\n        }\n\n        return {\n          minCol: this._coordIndex(left, cols),\n          minRow: this._coordIndex(top, rows),\n          maxCol: this._coordIndex(right, cols),\n          maxRow: this._coordIndex(bottom, rows)\n        };\n      }\n\n    }\n  }\n})(jQuery, fabric);"]}
\ No newline at end of file
diff --git a/src/js/bottom-table.js b/src/js/bottom-table.js
index f6c46a1..c728ea6 100755
--- a/src/js/bottom-table.js
+++ b/src/js/bottom-table.js
@@ -264,7 +264,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         });
 
         overlayContainer.append(buttonContainer);
-        $(".plate-setup-bottom-container").prepend(overlayContainer);
+        this.bottomContainer.prepend(overlayContainer);
       }
     };
   }
diff --git a/src/js/engine.js b/src/js/engine.js
index b543e8d..35316cd 100755
--- a/src/js/engine.js
+++ b/src/js/engine.js
@@ -10,6 +10,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
       engine: {
 
         derivative: {},
+        colorMap: new Map(),
         stackUpWithColor: {},
         stackPointer: 2,
 
@@ -121,7 +122,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
                 var index = this.stackUpWithColor[color][tileIndex]; 
                 var tile = THIS.allTiles[index];
                 var well = this.derivative[index];
-                THIS.setTileColor(tile, color, this.stackPointer); 
+                this.colorMap.set(index, color);
+                THIS.setTileColor(tile, color);
                 // Checks if all the required fields are filled
                 var completion = this.checkCompletion(well, tile);
                 THIS.setTileComplete(tile, completion == 1); 
diff --git a/src/js/example.js b/src/js/example.js
index 82c7141..4080092 100644
--- a/src/js/example.js
+++ b/src/js/example.js
@@ -194,6 +194,7 @@ window.onload = function () {
         numRows: 8,
         numCols: 12,
         attributes: attributes,
+        // scrollToGroup: false, // optional
 
         updateWells: function (event, data) {
             //data has changed
diff --git a/src/js/fabric-events.js b/src/js/fabric-events.js
index e86d5b0..589b2fa 100755
--- a/src/js/fabric-events.js
+++ b/src/js/fabric-events.js
@@ -105,6 +105,9 @@ var plateLayOutWidget = plateLayOutWidget || {};
           that.decideSelectedFields();
           that.mainFabricCanvas.renderAll();
           that._trigger("selectedWells", null, {selectedAddress: that.getSelectedAddress()});
+          if(that.options.scrollToGroup === undefined || that.options.scrollToGroup) {
+            that.selectObjectInBottomTab();
+          }
         });
       },
 
diff --git a/src/js/plate-layout.js b/src/js/plate-layout.js
index 87bf4ec..398d286 100755
--- a/src/js/plate-layout.js
+++ b/src/js/plate-layout.js
@@ -1,287 +1,331 @@
 $.widget("DNA.plateLayOut", {
 
-  plateLayOutWidget: {},
-
-  options: {
-    value: 0
-  },
-
-  allTiles: [], // All tiles containes all thise circles in the canvas
-
-  addressToLoc: function (layoutAddress) {
-    var m = /^([A-Z]+)(\d+)$/.exec(layoutAddress.trim().toUpperCase())
-    if (m) {
-      var row_v = m[1]; 
-      var col = parseInt(m[2])-1;
-      var row; 
-      for (var i = 0; i < row_v.length; i++) {
-        var c = row_v.charCodeAt(i) - 65; 
-        if (i) {
-            row += 1;
-            row *= 26; 
-            row += c ; 
+    plateLayOutWidget: {},
+
+    options: {
+        value: 0
+    },
+
+    allTiles: [], // All tiles containes all thise circles in the canvas
+
+    addressToLoc: function (layoutAddress) {
+        var m = /^([A-Z]+)(\d+)$/.exec(layoutAddress.trim().toUpperCase())
+        if (m) {
+            var row_v = m[1];
+            var col = parseInt(m[2]) - 1;
+            var row;
+            for (var i = 0; i < row_v.length; i++) {
+                var c = row_v.charCodeAt(i) - 65;
+                if (i) {
+                    row += 1;
+                    row *= 26;
+                    row += c;
+                } else {
+                    row = c;
+                }
+            }
+            return {
+                r: row,
+                c: col
+            };
         } else {
-            row = c;
+            throw layoutAddress + " not a proper layout address";
         }
-      }
-      return {
-        r: row, 
-        c: col
-      };
-    } else {
-      throw layoutAddress + " not a proper layout address"; 
-    }
-  },
+    },
 
-  locToIndex: function (loc, dimensions) {
-    if (!dimensions) {
-      dimensions = this.dimensions;
-    }
-    if (loc.r < 0) {
-      t
-    }
-    if (!(loc.r >= 0 && loc.r < dimensions.rows)) {
-      throw "Row index " + (loc.r + 1) + " invalid"; 
-    }
-    if (!(loc.c >= 0 && loc.c < dimensions.cols)) {
-      throw "Column index " + (loc.c + 1) + " invalid"; 
-    }
-    return loc.r*dimensions.cols + loc.c; 
-  },
-
-  addressToIndex: function (layoutAddress, dimensions) {
-    var loc = this.addressToLoc(layoutAddress); 
-    return this.locToIndex(loc, dimensions); 
-  }, 
-
-  _rowKey: function (i) {
-    var c1 = i % 26;
-    var c2 = (i - c1) / 26;
-    var code = String.fromCharCode(65 + c1);
-    if (c2 > 0) {
-      code = String.fromCharCode(64 + c2) + code;
-    }
-    return code;
-  }, 
+    locToIndex: function (loc, dimensions) {
+        if (!dimensions) {
+            dimensions = this.dimensions;
+        }
+        if (loc.r < 0) {
+            t
+        }
+        if (!(loc.r >= 0 && loc.r < dimensions.rows)) {
+            throw "Row index " + (loc.r + 1) + " invalid";
+        }
+        if (!(loc.c >= 0 && loc.c < dimensions.cols)) {
+            throw "Column index " + (loc.c + 1) + " invalid";
+        }
+        return loc.r * dimensions.cols + loc.c;
+    },
+
+    addressToIndex: function (layoutAddress, dimensions) {
+        var loc = this.addressToLoc(layoutAddress);
+        return this.locToIndex(loc, dimensions);
+    },
+
+    _rowKey: function (i) {
+        var c1 = i % 26;
+        var c2 = (i - c1) / 26;
+        var code = String.fromCharCode(65 + c1);
+        if (c2 > 0) {
+            code = String.fromCharCode(64 + c2) + code;
+        }
+        return code;
+    },
 
-  indexToLoc: function (index, dimensions) {
-    if (!dimensions) {
-      dimensions = this.dimensions;
-    }
+    indexToLoc: function (index, dimensions) {
+        if (!dimensions) {
+            dimensions = this.dimensions;
+        }
 
-    if (index >= dimensions.rows * dimensions.cols) {
-      throw "Index too high: " + index.toString(10); 
-    }
-    var loc = {}; 
-    loc.c = index % dimensions.cols;
-    loc.r = (index - loc.c) / dimensions.cols;
-
-    return loc; 
-  },
-
-  locToAddress: function (loc) {
-    return this._rowKey(loc.r) + (loc.c + 1).toString(10);
-  },
-
-  indexToAddress: function (index, dimensions) {
-    var loc = this.indexToLoc(index, dimensions); 
-    return this.locToAddress(loc); 
-  },
-
-  getDimensions: function () {
-    return $.extend(true, {}, this.dimensions);
-  },
-
-  _create: function() {
-    var rows = parseInt(this.options.numRows || 8);
-    var cols = parseInt(this.options.numCols || 12);
-    this.dimensions = {
-      rows: rows,
-      cols: cols
-    };
-    this.rowIndex = [];
-    for (var i = 0; i < rows; i++) {
-      this.rowIndex.push(this._rowKey(i));
-    }
+        if (index >= dimensions.rows * dimensions.cols) {
+            throw "Index too high: " + index.toString(10);
+        }
+        var loc = {};
+        loc.c = index % dimensions.cols;
+        loc.r = (index - loc.c) / dimensions.cols;
+
+        return loc;
+    },
+
+    locToAddress: function (loc) {
+        return this._rowKey(loc.r) + (loc.c + 1).toString(10);
+    },
+
+    indexToAddress: function (index, dimensions) {
+        var loc = this.indexToLoc(index, dimensions);
+        return this.locToAddress(loc);
+    },
+
+    getDimensions: function () {
+        return $.extend(true, {}, this.dimensions);
+    },
+
+    _create: function () {
+        var rows = parseInt(this.options.numRows || 8);
+        var cols = parseInt(this.options.numCols || 12);
+        this.dimensions = {
+            rows: rows,
+            cols: cols
+        };
+        this.rowIndex = [];
+        for (var i = 0; i < rows; i++) {
+            this.rowIndex.push(this._rowKey(i));
+        }
 
-    this.target = (this.element[0].id) ? "#" + this.element[0].id : "." + this.element[0].className;
+        this.target = (this.element[0].id) ? "#" + this.element[0].id : "." + this.element[0].className;
 
-    // Import classes from other files.. Here we import it using extend and add it to this
-    // object. internally we add to widget.DNA.getPlates.prototype.
-    // Helpers are methods which return other methods and objects.
-    // add Objects to plateLayOutWidget and it will be added to this object.
-    // set read only well
-    if (this.options.readOnly){
-      this.isReadOnly(true);
-    }
+        // Import classes from other files.. Here we import it using extend and add it to this
+        // object. internally we add to widget.DNA.getPlates.prototype.
+        // Helpers are methods which return other methods and objects.
+        // add Objects to plateLayOutWidget and it will be added to this object.
+        // set read only well
+        if (this.options.readOnly) {
+            this.isReadOnly(true);
+        }
 
-    for (var component in plateLayOutWidget) {
-      // Incase some properties has to initialize with data from options hash,
-      // we provide it sending this object.
-      $.extend(this, new plateLayOutWidget[component](this));
-    }
+        for (var component in plateLayOutWidget) {
+            // Incase some properties has to initialize with data from options hash,
+            // we provide it sending this object.
+            $.extend(this, new plateLayOutWidget[component](this));
+        }
 
-    this.imgSrc = this.options.imgSrc || "assets";
-
-    this._createInterface();
-
-    this._trigger("created", null, this);
-
-    return this;
-  },
-
-  _init: function() {
-    // This is invoked when the user use the plugin after _create is called.
-    // The point is _create is invoked for the very first time and for all other
-    // times _init is used.
-  },
-
-  addData: function() {
-    alert("wow this is good");
-  },
-
-  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
-  getTextDerivative: function(wellsData) {
-    var textDerivative = {};
-    var fieldMap = this.fieldMap;
-    for (var idx in wellsData){
-      var textValWell = {};
-      var textFieldIdWell = {};
-      var curWellData = wellsData[idx];
-      for (var fieldId in curWellData){
-        if (fieldId in this.fieldMap){
-          var field = this.fieldMap[fieldId];
-          var textVal = field.parseText(curWellData[fieldId]);
-          textFieldIdWell[field.name] = textVal;
-          textValWell[fieldId] = textVal;
-        } else {
-          // do not convert if not a field (ex: layout_address)
-          textFieldIdWell[fieldId] = curWellData[fieldId];
-          textValWell[fieldId] = curWellData[fieldId];
+        this.imgSrc = this.options.imgSrc || "assets";
+
+        this._createInterface();
+
+        this._trigger("created", null, this);
+
+        return this;
+    },
+
+    _init: function () {
+        // This is invoked when the user use the plugin after _create is called.
+        // The point is _create is invoked for the very first time and for all other
+        // times _init is used.
+    },
+
+    addData: function () {
+        alert("wow this is good");
+    },
+
+    // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
+    getTextDerivative: function (wellsData) {
+        var textDerivative = {};
+        var fieldMap = this.fieldMap;
+        for (var idx in wellsData) {
+            var textValWell = {};
+            var textFieldIdWell = {};
+            var curWellData = wellsData[idx];
+            for (var fieldId in curWellData) {
+                if (fieldId in this.fieldMap) {
+                    var field = this.fieldMap[fieldId];
+                    var textVal = field.parseText(curWellData[fieldId]);
+                    textFieldIdWell[field.name] = textVal;
+                    textValWell[fieldId] = textVal;
+                } else {
+                    // do not convert if not a field (ex: layout_address)
+                    textFieldIdWell[fieldId] = curWellData[fieldId];
+                    textValWell[fieldId] = curWellData[fieldId];
+                }
+            }
+            textDerivative[idx] = {
+                textVal: textValWell,
+                textFieldVal: textFieldIdWell
+            };
         }
-      }
-      textDerivative[idx] = {
-        textVal: textValWell,
-        textFieldVal: textFieldIdWell
-      };
-    }
 
-    return textDerivative;
-  },
-
-  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
-  getWellsDifferences: function(wellsData) {
-    return this.getDifferentWellsVals(wellsData);
-  },
-
-  setFieldsDisabled: function(flag){
-    this.fieldList.forEach(function(field){
-      field.disabled(flag);
-    });
-  },
-
-  isReadOnly: function(flag){
-    if (flag){
-      this.readOnly = true;
-    } else {
-      this.readOnly = false;
-    }
-    this.readOnlyHandler();
-  },
-
-  readOnlyHandler: function(){
-    if (this.readOnly){
-      this.overLayButtonContainer.css("display", "none");
-      $('.multiple-field-manage-delete-button').css("display", "none");
-      this.setFieldsDisabled(true);
-    } else {
-      this.overLayButtonContainer.css("display", "flex");
-      $('.multiple-field-manage-delete-button').css("display", "none");
-      if (!this.disableAddDeleteWell) {
-        this.setFieldsDisabled(false);
-      }
-    }
-  },
-
-  disableAddDeleteWell: null,
-  // column_with_default_val will be used to determine empty wells, format: {field_name: default_val}
-  isDisableAddDeleteWell: function(flag, column_with_default_val){
-    if (flag){
-      this.disableAddDeleteWell = true;
-      this.addressAllowToEdit = this.getWellSetAddressWithData();
-      // configure undo redo action
-      this.actionPointer = 0;
-      this.undoRedoArray = [];
-      this.undoRedoArray.push(this.createObject());
-      if (column_with_default_val) {
-        this.emptyWellWithDefaultVal = column_with_default_val;
-      }
-    } else {
-      this.disableAddDeleteWell = false;
-      this.setFieldsDisabled(false);
-      this.emptyWellWithDefaultVal = null;
-    }
-    this._fabricEvents();
-  },
+        return textDerivative;
+    },
 
-  getSelectedObject: function() {
-    var selectedAddress = [];
-    for (var i = 0; i < this.allSelectedObjects.length; i++){
-      selectedAddress.push(this.allSelectedObjects[i].address);
-    }
-    var selectedObjects = {};
-    var derivative = this.engine.derivative;
-    for (var loc in derivative){
-      var address = this.indexToAddress(loc);
-      if (selectedAddress.indexOf(address) >= 0) {
-        selectedObjects[address] = derivative[loc];
-      }
-    }
-    return selectedObjects;
-  },
-
-  getSelectedIndex: function() {
-    return this.allSelectedObjects.map(function(selectedObj){
-        return that.addressToIndex(selectedObj.address)
-    });
-  },
-
-  getSelectedAddress: function() {
-    return this.allSelectedObjects.map(function(selectedObj){
-      return selectedObj.address;
-    });
-  },
-
-  setSelectedWell: function(addressList) {
-    var areas = [];
-    var minRow = 999;
-    var locMap = {};
-    for (var id = 0; id < addressList.length; id++){
-      var wellIdx = this.addressToIndex(addressList[id]);
-      var loc = this.indexToLoc(wellIdx);
-      areas.push({
-        minCol: loc.c,
-        minRow: loc.r,
-        maxCol: loc.c,
-        maxRow: loc.r
-      });
-      if (loc.r <= minRow) {
-        minRow = loc.r;
-        if (loc.r in locMap) {
-          locMap[loc.r].push(loc.c);
+    // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
+    getWellsDifferences: function (wellsData) {
+        return this.getDifferentWellsVals(wellsData);
+    },
+
+    setFieldsDisabled: function (flag) {
+        this.fieldList.forEach(function (field) {
+            field.disabled(flag);
+        });
+    },
+
+    isReadOnly: function (flag) {
+        if (flag) {
+            this.readOnly = true;
         } else {
-          locMap[loc.r] = [loc.c];
+            this.readOnly = false;
         }
-      }
-    }
-    var focalWell = {
-      row: minRow,
-      col: Math.min.apply(null, locMap[minRow])
-    };
+        this.readOnlyHandler();
+    },
+
+    readOnlyHandler: function () {
+        if (this.readOnly) {
+            this.overLayButtonContainer.css("display", "none");
+            $('.multiple-field-manage-delete-button').css("display", "none");
+            this.setFieldsDisabled(true);
+        } else {
+            this.overLayButtonContainer.css("display", "flex");
+            $('.multiple-field-manage-delete-button').css("display", "none");
+            if (!this.disableAddDeleteWell) {
+                this.setFieldsDisabled(false);
+            }
+        }
+    },
+
+    disableAddDeleteWell: null,
+    // column_with_default_val will be used to determine empty wells, format: {field_name: default_val}
+    isDisableAddDeleteWell: function (flag, column_with_default_val) {
+        if (flag) {
+            this.disableAddDeleteWell = true;
+            this.addressAllowToEdit = this.getWellSetAddressWithData();
+            // configure undo redo action
+            this.actionPointer = 0;
+            this.undoRedoArray = [];
+            this.undoRedoArray.push(this.createObject());
+            if (column_with_default_val) {
+                this.emptyWellWithDefaultVal = column_with_default_val;
+            }
+        } else {
+            this.disableAddDeleteWell = false;
+            this.setFieldsDisabled(false);
+            this.emptyWellWithDefaultVal = null;
+        }
+        this._fabricEvents();
+    },
 
-    this.setSelection(areas, focalWell);
-    this.decideSelectedFields();
-    this.mainFabricCanvas.renderAll();
-  }
+    getSelectedObject: function () {
+        var selectedAddress = [];
+        for (var i = 0; i < this.allSelectedObjects.length; i++) {
+            selectedAddress.push(this.allSelectedObjects[i].address);
+        }
+        var selectedObjects = {};
+        var derivative = this.engine.derivative;
+        for (var index in derivative) {
+            var address = this.indexToAddress(index);
+            if (selectedAddress.indexOf(address) >= 0) {
+                var well = JSON.parse(JSON.stringify(derivative[index]));
+                well.colorIndex = this.engine.colorMap.get(Number(index));
+                selectedObjects[address] = well;
+            }
+        }
+        return selectedObjects;
+    },
+
+    selectObjectInBottomTab: function () {
+        var selectedObjects = this.getSelectedObject();
+        var selectedObjectAddress;
+        for (var prop in selectedObjects) {
+            if (!selectedObjectAddress) {
+                selectedObjectAddress = prop;
+            } else {
+                return;  // scroll to matching group only if a single well has been selected
+            }
+        }
+        if (selectedObjects[selectedObjectAddress]) {
+            var colorIndex = selectedObjects[selectedObjectAddress].colorIndex;
+            var trs = document.querySelectorAll('table.plate-setup-bottom-table tr');
+            for (var i = 1; i < trs.length; i++) { // start at 1 to skip the table headers
+                var tds = trs[i].children;
+                var isSelected = tds[0].querySelector('button').innerHTML === colorIndex.toString();
+                for (var j = 1; j < tds.length; j++) {
+                    if (isSelected) {
+                        tds[j].style.background = '#22cb94';
+                    } else {
+                        tds[j].style.background = '#ffffff';
+                    }
+                }
+                if (isSelected) {
+                    scrollTo(document.querySelector('.plate-setup-bottom-table-container'), tds[0].offsetTop, 300);
+                }
+            }
+        }
+    },
+
+    getSelectedIndex: function () {
+        return this.allSelectedObjects.map(function (selectedObj) {
+            return that.addressToIndex(selectedObj.address)
+        });
+    },
+
+    getSelectedAddress: function () {
+        return this.allSelectedObjects.map(function (selectedObj) {
+            return selectedObj.address;
+        });
+    },
+
+    setSelectedWell: function (addressList) {
+        var areas = [];
+        var minRow = 999;
+        var locMap = {};
+        for (var id = 0; id < addressList.length; id++) {
+            var wellIdx = this.addressToIndex(addressList[id]);
+            var loc = this.indexToLoc(wellIdx);
+            areas.push({
+                minCol: loc.c,
+                minRow: loc.r,
+                maxCol: loc.c,
+                maxRow: loc.r
+            });
+            if (loc.r <= minRow) {
+                minRow = loc.r;
+                if (loc.r in locMap) {
+                    locMap[loc.r].push(loc.c);
+                } else {
+                    locMap[loc.r] = [loc.c];
+                }
+            }
+        }
+        var focalWell = {
+            row: minRow,
+            col: Math.min.apply(null, locMap[minRow])
+        };
+
+        this.setSelection(areas, focalWell);
+        this.decideSelectedFields();
+        this.mainFabricCanvas.renderAll();
+    }
 
-});
\ No newline at end of file
+});
+
+// https://stackoverflow.com/questions/17733076/smooth-scroll-anchor-links-without-jquery
+function scrollTo(element, to, duration) {
+    if (duration <= 0) return;
+    var difference = to - element.scrollTop;
+    var perTick = difference / duration * 10;
+    setTimeout(function () {
+        element.scrollTop = element.scrollTop + perTick;
+        if (element.scrollTop === to) return;
+        scrollTo(element, to, duration - 10);
+    }, 10);
+}
\ No newline at end of file

From a1ddba00b0d60809a361fca7939c26b4f82a7511 Mon Sep 17 00:00:00 2001
From: Jeremy Gore <jeremy.gore@tessella.com>
Date: Thu, 14 Mar 2019 12:35:16 -0400
Subject: [PATCH 05/10] Remove obsolete imgSrc option

---
 README.md                      |    1 -
 dist/css/plate-map.css         |  491 ----
 dist/css/plate-map.min.css     |    2 -
 dist/css/plate-map.min.css.map |    1 -
 dist/js/plate-map.js           | 4360 --------------------------------
 dist/js/plate-map.min.js       |    2 -
 dist/js/plate-map.min.js.map   |    1 -
 dist/package.json              |   49 -
 src/js/plate-layout.js         |    2 -
 9 files changed, 4909 deletions(-)
 delete mode 100644 dist/css/plate-map.css
 delete mode 100644 dist/css/plate-map.min.css
 delete mode 100644 dist/css/plate-map.min.css.map
 delete mode 100755 dist/js/plate-map.js
 delete mode 100755 dist/js/plate-map.min.js
 delete mode 100644 dist/js/plate-map.min.js.map
 delete mode 100644 dist/package.json

diff --git a/README.md b/README.md
index c3cba77..6b643d1 100644
--- a/README.md
+++ b/README.md
@@ -138,7 +138,6 @@ the Github repository.
     $("#my-plate-layout").plateLayOut({
       numRows: 8,
       numCols: 12,
-      imgSrc:  "css",
       readOnly: false,  // optional
       attributes: attributes,
       updateWells: function(event, data) {
diff --git a/dist/css/plate-map.css b/dist/css/plate-map.css
deleted file mode 100644
index f44a69c..0000000
--- a/dist/css/plate-map.css
+++ /dev/null
@@ -1,491 +0,0 @@
-@import url(http://fonts.googleapis.com/css?family=Roboto);
-
-.plate-setup-container {
-  width: 1024px;
-  height: 768px;
-  position: relative;
-  float: left;
-}
-
-.plate-setup-wrapper {
-  position: absolute;
-  top: 0;
-  left: 0;
-  bottom: 0;
-  right: 0;
-  flex-direction: column;
-  background-color: #f5f5f5;
-}
-
-.plate-setup-top-section {
-  height: 540px;
-  top: 0;
-  left: 0;
-  right: 0;
-  position: absolute;
-}
-
-.plate-setup-top-left {
-  width: 674px;
-  top: 0;
-  bottom: 0;
-  position: absolute;
-}
-
-.plate-setup-top-right {
-  left: 674px;
-  top: 0;
-  bottom: 0;
-  right: 0;
-  position: absolute;
-}
-
-.plate-setup-overlay-container {
-  height: 32px;
-  top: 10px;
-  left: 16px;
-  right: 16px;
-  position: inherit;
-  background-color: #464646;
-  border-radius: 2px;
-  display: flex;
-  justify-content: space-between;
-  align-items: baseline;
-  vertical-align: middle;
-}
-
-.plate-setup-overlay-radio-container {
-  width: 32px;
-  height: 32px;
-}
-
-.plate-setup-overlay-text-container {
-  color: white;
-  font-size: 12px;
-  line-height: 30px;
-  height: 32px;
-  font-family: "Roboto", Arial, sans-serif;
-  margin: 2px 8px;
-  flex: 1 1 auto;
-}
-
-.plate-setup-overlay-button-container, .plate-setup-overlay-bottom-button-container {
-  flex: 0 0 auto;
-  display: flex;
-  flex: 1 1 0;
-}
-
-.plate-setup-button {
-  height: 23px;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  border: none;
-  background-color: white;
-  border-radius: 2px;
-  margin-right: 4px;
-  flex: 1 0 0;
-  white-space: nowrap;
-}
-
-.plate-setup-clicked-button {
-  height: 23px;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  border: none;
-  background-color: aquamarine;
-  border-radius: 2px;
-  margin-right: 4px;
-  flex: 1 0 0;
-  white-space: nowrap;
-}
-
-
-.plate-setup-canvas-container {
-  top: 52px;
-  left: 16px;
-  right: 16px;
-  bottom: 10px;
-  position: absolute;
-}
-
-.plate-setup-tab-container {
-  position: absolute;
-  top:10px;
-  left:10px;
-  bottom: 10px;
-  right: 10px;
-  background-color: white;
-  border: solid 1px #e1e1e1;
-}
-
-.plate-setup-tab-head {
-  left: 0;
-  right: 0;
-  height: 23px;
-  border-bottom: solid 1px #e1e1e1;
-  background-color: #f5f5f5;
-  display: flex;
-}
-
-.plate-setup-tab {
-  height: 23px;
-  background-color: #ebebeb;
-  border-right: solid 1px #e1e1e1;
-  cursor: pointer;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 10px;
-  text-align: center;
-  padding: 5px;
-  box-sizing: border-box;
-  flex: 1 1 auto;
-  white-space: nowrap;
-  overflow: hidden;
-}
-
-.plate-setup-tab:last-child {
-  border-right: none;
-}
-
-.plate-setup-tab-selected {
-  height: 24px;
-  background-color: white;
-  color: #00506e;
-  flex-shrink: 0;
-}
-
-.plate-setup-tab-data-container {
-  left: 0;
-  right: 0;
-  height: 442px;
-  border-bottom: solid 1px #e1e1e1;
-  position: absolute;
-  font-family: "Roboto", Arial, sans-serif;
-}
-
-.plate-setup-data-div {
-  top: 0;
-  left: 0;
-  bottom: 0;
-  right: 0;
-  position: absolute;
-  background-color: white;
-  overflow: auto;
-}
-
-.plate-setup-well-attr-container {
-  top: 472px;
-  left: 0;
-  right: 0;
-  height: 20px;
-  box-sizing: border-box;
-  padding: 0px 16px;
-  color: #00506e;
-  text-align: center;
-  position: absolute;
-  font-size: 10px;
-  font-family: "Roboto", Arial, sans-serif;
-}
-
-.plate-setup-preset-container {
-  top: 490px;
-  left: 0;
-  right: 0;
-  height: 22px;
-  position: absolute;
-  box-sizing: border-box;
-  padding: 0px 16px;
-  text-align: center;
-  display: flex;
-  justify-content: center;
-}
-
-.plate-setup-prest-tab {
-  display: inline-block;
-  flex-basis: 50px;
-  padding: 0 5px;
-  margin: 0 1px;
-  height: 20px;
-  background-color: white;
-  border: solid 1px #e1e1e1;
-  border-radius: 2px;
-  cursor: pointer;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 10px;
-  text-align: center;
-}
-
-.plate-setup-prest-tab-selected {
-  display: inline-block;
-  flex-basis: 50px;
-  padding: 0 5px;
-  margin: 0 1px;
-  height: 20px;
-  background-color: #e1e1e1;
-  border: solid 1px #e1e1e1;
-  border-radius: 2px;
-  cursor: pointer;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 11px;
-  text-align: center;
-  color: #00506e;
-}
-
-.plate-setup-prest-tab-div {
-  padding-top: 3px;
-}
-
-.plate-setup-tab-default-field {
-  display: flex;
-  padding: 10px 16px 0 16px;
-}
-
-.plate-setup-tab-field-left-side {
-  width: 32px;
-  padding-top: 16px;
-}
-
-.plate-setup-tab-field-right-side {
-  flex: 1;
-}
-
-.plate-setup-tab-name {
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  display: inline-block;
-  line-height: 16px;
-}
-
-.plate-setup-tab-name-singleSelect {
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  margin-top: 5px;
-}
-
-
-.plate-setup-tab-name-missing {
-  height: 20px;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  background: red;
-}
-
-
-.plate-setup-tab-field-container, .plate-setup-tab-field-container-singleSelect {
-  width: 100%;
-  display: flex;
-}
-
-.plate-setup-tab-input, .plate-setup-tab-select-field, .plate-setup-tab-multiplex-single-select-field {
-  height: 28px;
-  flex: 1 1 auto;
-  width: 30px;
-  margin: auto;
-}
-
-.plate-setup-tab-multiselect-field {
-  min-height: 28px;
-  flex: 1 1 auto;
-  width: 30px;
-}
-
-.plate-setup-tab-label-select-field, .plate-setup-tab-unit {
-  width: 130px;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  height: 28px;
-  box-sizing: border-box;
-  padding-left: 5px;
-}
-
-.plate-setup-tab-unit {
-  font-family: "Roboto", Arial, sans-serif;
-  line-height: 26px;
-  color: #444;
-  white-space: nowrap;
-}
-
-.plate-setup-tab-check-box {
-  cursor: pointer;
-  border: 1px solid gray;
-  display: inline-block;
-  height: 16px;
-  width: 16px;
-  text-align: center;
-  line-height: 16px;
-}
-
-.plate-setup-bottom-control-container {
-  top: 0;
-  left: 0;
-  right: 0;
-  height: 32px;
-  background-color: #464646;
-  position: absolute;
-  display: flex;
-  justify-content:space-between;
-  align-items: baseline;
-  vertical-align: middle;
-}
-
-.plate-setup-bottom-container {
-  top: 540px;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  position: absolute;
-  background-color: #e1e1e1;
-}
-
-.plate-setup-bottom-table-container {
-  top: 32px;
-  left: 0;
-  bottom: 0;
-  right: 0;
-  position: absolute;
-  overflow: auto;
-}
-
-
-.plate-setup-bottom-table {
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 14px;
-  border-collapse: collapse;
-  width: 100%;
-}
-
-.plate-setup-bottom-table th {
-  border: solid #c2c2c2 1px;
-  padding: 5px 10px;
-  font-weight: bold;
-  font-size: 12px;
-  text-align: left;
-}
-
-.plate-setup-bottom-table td {
-  border: solid #c2c2c2 1px;
-  padding: 5px 10px;
-  background-color: white;
-}
-
-.plate-setup-color-text {
-  font-size: 14px;
-  border: none;
-  border-radius: 2px;
-  padding: 3px 15px;
-  background-color: WHITE;
-  margin-right: 4px;
-}
-
-.plate-setup-bottom-id {
-  width: 40px;
-  text-align: center;
-  background-image: linear-gradient(to right, rgba(255,255,255,0.3), transparent)
-}
-
-input.invalid {
-  background-color: pink;
-}
-
-.plate-setup-remove-all-button-container {
-  text-align: left;
-}
-
-.plate-setup-remove-all-button{
-  width: 100%;
-  font-family: "Roboto", Arial, sans-serif;
-  font-size: 12px;
-  text-overflow: ellipsis;
-  text-align: left;
-  white-space: nowrap;
-  border: 1px solid #aaa;
-  border-top: none;
-  color: #444;
-  background-color: #fff;
-  background-image: linear-gradient(to top, #eee 0%, #fff 50%);
-}
-/* Modal Content */
-
-.modal {
-  display: none; /* Hidden by default */
-  position: fixed; /* Stay in place */
-  z-index: 2000; /* Sit on top */
-  padding-top: 100px; /* Location of the box */
-  left: 0;
-  top: 0;
-  width: 100%; /* Full width */
-  height: 100%; /* Full height */
-  overflow: auto; /* Enable scroll if needed */
-  background-color: rgb(0,0,0); /* Fallback color */
-  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
-}
-
-.modal-content {
-  font-family: 'Roboto', sans-serif;
-  font-size: 14px;
-  background-color: #fefefe;
-  margin: auto;
-  padding: 20px;
-  border: 1px solid #888;
-}
-
-.delete-dialog .modal-content {
-  width: 550px;
-}
-
-.modal-content > * {
-  width: 100%;
-}
-
-.dialog-buttons {
-  margin-top: 10px;
-  display: inline-block;
-  text-align: right;
-}
-
-.dialog-buttons button {
-  margin-left: 4px;
-}
-
-.plate-popout-table {
-  border-collapse: collapse;
-  width: 100%;
-  border: 1px solid black;
-  padding: 5px;
-}
-
-.plate-popout-th {
-  text-align: left;
-  background-color: white;
-  color: black;
-  font-size: 12px;
-  border: 1px solid black;
-  padding: 5px;
-}
-
-.plate-popout-tr:hover {
-  background-color: #f5f5f5;
-  border: 1px solid black;
-  padding: 5px;
-}
-
-.plate-popout-td {
-  text-align: left;
-  font-size: 11px;
-  border: 1px solid black;
-  padding: 5px;
-}
-
-.plate-field-warning-image{
-  vertical-align: baseline;
-  margin: 0px 0 0px;
-}
-
-.pop-out-text {
-  position: fixed;
-  display: none;
-  background: white;
-  border: 1px solid;
-  float: left;
-  margin-top: -44px;
-  z-Index: 99999 !important;
-}
diff --git a/dist/css/plate-map.min.css b/dist/css/plate-map.min.css
deleted file mode 100644
index d7ff6e2..0000000
--- a/dist/css/plate-map.min.css
+++ /dev/null
@@ -1,2 +0,0 @@
-@import url(http://fonts.googleapis.com/css?family=Roboto);.plate-setup-container{width:1024px;height:768px;position:relative;float:left}.plate-setup-wrapper{position:absolute;top:0;left:0;bottom:0;right:0;flex-direction:column;background-color:#f5f5f5}.plate-setup-top-section{height:540px;top:0;left:0;right:0;position:absolute}.plate-setup-top-left{width:674px;top:0;bottom:0;position:absolute}.plate-setup-top-right{left:674px;top:0;bottom:0;right:0;position:absolute}.plate-setup-overlay-container{height:32px;top:10px;left:16px;right:16px;position:inherit;background-color:#464646;border-radius:2px;display:flex;justify-content:space-between;align-items:baseline;vertical-align:middle}.plate-setup-overlay-radio-container{width:32px;height:32px}.plate-setup-overlay-text-container{color:#fff;font-size:12px;line-height:30px;height:32px;font-family:Roboto,Arial,sans-serif;margin:2px 8px;flex:1 1 auto}.plate-setup-overlay-bottom-button-container,.plate-setup-overlay-button-container{flex:0 0 auto;display:flex;flex:1 1 0}.plate-setup-button{height:23px;font-family:Roboto,Arial,sans-serif;font-size:12px;border:none;background-color:#fff;border-radius:2px;margin-right:4px;flex:1 0 0;white-space:nowrap}.plate-setup-clicked-button{height:23px;font-family:Roboto,Arial,sans-serif;font-size:12px;border:none;background-color:#7fffd4;border-radius:2px;margin-right:4px;flex:1 0 0;white-space:nowrap}.plate-setup-canvas-container{top:52px;left:16px;right:16px;bottom:10px;position:absolute}.plate-setup-tab-container{position:absolute;top:10px;left:10px;bottom:10px;right:10px;background-color:#fff;border:solid 1px #e1e1e1}.plate-setup-tab-head{left:0;right:0;height:23px;border-bottom:solid 1px #e1e1e1;background-color:#f5f5f5;display:flex}.plate-setup-tab{height:23px;background-color:#ebebeb;border-right:solid 1px #e1e1e1;cursor:pointer;font-family:Roboto,Arial,sans-serif;font-size:10px;text-align:center;padding:5px;box-sizing:border-box;flex:1 1 auto;white-space:nowrap;overflow:hidden}.plate-setup-tab:last-child{border-right:none}.plate-setup-tab-selected{height:24px;background-color:#fff;color:#00506e;flex-shrink:0}.plate-setup-tab-data-container{left:0;right:0;height:442px;border-bottom:solid 1px #e1e1e1;position:absolute;font-family:Roboto,Arial,sans-serif}.plate-setup-data-div{top:0;left:0;bottom:0;right:0;position:absolute;background-color:#fff;overflow:auto}.plate-setup-well-attr-container{top:472px;left:0;right:0;height:20px;box-sizing:border-box;padding:0 16px;color:#00506e;text-align:center;position:absolute;font-size:10px;font-family:Roboto,Arial,sans-serif}.plate-setup-preset-container{top:490px;left:0;right:0;height:22px;position:absolute;box-sizing:border-box;padding:0 16px;text-align:center;display:flex;justify-content:center}.plate-setup-prest-tab{display:inline-block;flex-basis:50px;padding:0 5px;margin:0 1px;height:20px;background-color:#fff;border:solid 1px #e1e1e1;border-radius:2px;cursor:pointer;font-family:Roboto,Arial,sans-serif;font-size:10px;text-align:center}.plate-setup-prest-tab-selected{display:inline-block;flex-basis:50px;padding:0 5px;margin:0 1px;height:20px;background-color:#e1e1e1;border:solid 1px #e1e1e1;border-radius:2px;cursor:pointer;font-family:Roboto,Arial,sans-serif;font-size:11px;text-align:center;color:#00506e}.plate-setup-prest-tab-div{padding-top:3px}.plate-setup-tab-default-field{display:flex;padding:10px 16px 0 16px}.plate-setup-tab-field-left-side{width:32px;padding-top:16px}.plate-setup-tab-field-right-side{flex:1}.plate-setup-tab-name{font-family:Roboto,Arial,sans-serif;font-size:12px;display:inline-block;line-height:16px}.plate-setup-tab-name-singleSelect{font-family:Roboto,Arial,sans-serif;font-size:12px;margin-top:5px}.plate-setup-tab-name-missing{height:20px;font-family:Roboto,Arial,sans-serif;font-size:12px;background:red}.plate-setup-tab-field-container,.plate-setup-tab-field-container-singleSelect{width:100%;display:flex}.plate-setup-tab-input,.plate-setup-tab-multiplex-single-select-field,.plate-setup-tab-select-field{height:28px;flex:1 1 auto;width:30px;margin:auto}.plate-setup-tab-multiselect-field{min-height:28px;flex:1 1 auto;width:30px}.plate-setup-tab-label-select-field,.plate-setup-tab-unit{width:130px;overflow:hidden;text-overflow:ellipsis;height:28px;box-sizing:border-box;padding-left:5px}.plate-setup-tab-unit{font-family:Roboto,Arial,sans-serif;line-height:26px;color:#444;white-space:nowrap}.plate-setup-tab-check-box{cursor:pointer;border:1px solid gray;display:inline-block;height:16px;width:16px;text-align:center;line-height:16px}.plate-setup-bottom-control-container{top:0;left:0;right:0;height:32px;background-color:#464646;position:absolute;display:flex;justify-content:space-between;align-items:baseline;vertical-align:middle}.plate-setup-bottom-container{top:540px;left:0;right:0;bottom:0;position:absolute;background-color:#e1e1e1}.plate-setup-bottom-table-container{top:32px;left:0;bottom:0;right:0;position:absolute;overflow:auto}.plate-setup-bottom-table{font-family:Roboto,Arial,sans-serif;font-size:14px;border-collapse:collapse;width:100%}.plate-setup-bottom-table th{border:solid #c2c2c2 1px;padding:5px 10px;font-weight:700;font-size:12px;text-align:left}.plate-setup-bottom-table td{border:solid #c2c2c2 1px;padding:5px 10px;background-color:#fff}.plate-setup-color-text{font-size:14px;border:none;border-radius:2px;padding:3px 15px;background-color:#fff;margin-right:4px}.plate-setup-bottom-id{width:40px;text-align:center;background-image:linear-gradient(to right,rgba(255,255,255,.3),transparent)}input.invalid{background-color:pink}.plate-setup-remove-all-button-container{text-align:left}.plate-setup-remove-all-button{width:100%;font-family:Roboto,Arial,sans-serif;font-size:12px;text-overflow:ellipsis;text-align:left;white-space:nowrap;border:1px solid #aaa;border-top:none;color:#444;background-color:#fff;background-image:linear-gradient(to top,#eee 0,#fff 50%)}.modal{display:none;position:fixed;z-index:2000;padding-top:100px;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,.4)}.modal-content{font-family:Roboto,sans-serif;font-size:14px;background-color:#fefefe;margin:auto;padding:20px;border:1px solid #888}.delete-dialog .modal-content{width:550px}.modal-content>*{width:100%}.dialog-buttons{margin-top:10px;display:inline-block;text-align:right}.dialog-buttons button{margin-left:4px}.plate-popout-table{border-collapse:collapse;width:100%;border:1px solid #000;padding:5px}.plate-popout-th{text-align:left;background-color:#fff;color:#000;font-size:12px;border:1px solid #000;padding:5px}.plate-popout-tr:hover{background-color:#f5f5f5;border:1px solid #000;padding:5px}.plate-popout-td{text-align:left;font-size:11px;border:1px solid #000;padding:5px}.plate-field-warning-image{vertical-align:baseline;margin:0 0 0}.pop-out-text{position:fixed;display:none;background:#fff;border:1px solid;float:left;margin-top:-44px;z-Index:99999!important}
-/*# sourceMappingURL=plate-map.min.css.map */
\ No newline at end of file
diff --git a/dist/css/plate-map.min.css.map b/dist/css/plate-map.min.css.map
deleted file mode 100644
index 1d3e613..0000000
--- a/dist/css/plate-map.min.css.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["plate-layout.css"],"names":[],"mappings":"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","file":"plate-map.min.css","sourcesContent":["@import url(http://fonts.googleapis.com/css?family=Roboto);\n\n.plate-setup-container {\n  width: 1024px;\n  height: 768px;\n  position: relative;\n  float: left;\n}\n\n.plate-setup-wrapper {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  flex-direction: column;\n  background-color: #f5f5f5;\n}\n\n.plate-setup-top-section {\n  height: 540px;\n  top: 0;\n  left: 0;\n  right: 0;\n  position: absolute;\n}\n\n.plate-setup-top-left {\n  width: 674px;\n  top: 0;\n  bottom: 0;\n  position: absolute;\n}\n\n.plate-setup-top-right {\n  left: 674px;\n  top: 0;\n  bottom: 0;\n  right: 0;\n  position: absolute;\n}\n\n.plate-setup-overlay-container {\n  height: 32px;\n  top: 10px;\n  left: 16px;\n  right: 16px;\n  position: inherit;\n  background-color: #464646;\n  border-radius: 2px;\n  display: flex;\n  justify-content: space-between;\n  align-items: baseline;\n  vertical-align: middle;\n}\n\n.plate-setup-overlay-radio-container {\n  width: 32px;\n  height: 32px;\n}\n\n.plate-setup-overlay-text-container {\n  color: white;\n  font-size: 12px;\n  line-height: 30px;\n  height: 32px;\n  font-family: \"Roboto\", Arial, sans-serif;\n  margin: 2px 8px;\n  flex: 1 1 auto;\n}\n\n.plate-setup-overlay-button-container, .plate-setup-overlay-bottom-button-container {\n  flex: 0 0 auto;\n  display: flex;\n  flex: 1 1 0;\n}\n\n.plate-setup-button {\n  height: 23px;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  border: none;\n  background-color: white;\n  border-radius: 2px;\n  margin-right: 4px;\n  flex: 1 0 0;\n  white-space: nowrap;\n}\n\n.plate-setup-clicked-button {\n  height: 23px;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  border: none;\n  background-color: aquamarine;\n  border-radius: 2px;\n  margin-right: 4px;\n  flex: 1 0 0;\n  white-space: nowrap;\n}\n\n\n.plate-setup-canvas-container {\n  top: 52px;\n  left: 16px;\n  right: 16px;\n  bottom: 10px;\n  position: absolute;\n}\n\n.plate-setup-tab-container {\n  position: absolute;\n  top:10px;\n  left:10px;\n  bottom: 10px;\n  right: 10px;\n  background-color: white;\n  border: solid 1px #e1e1e1;\n}\n\n.plate-setup-tab-head {\n  left: 0;\n  right: 0;\n  height: 23px;\n  border-bottom: solid 1px #e1e1e1;\n  background-color: #f5f5f5;\n  display: flex;\n}\n\n.plate-setup-tab {\n  height: 23px;\n  background-color: #ebebeb;\n  border-right: solid 1px #e1e1e1;\n  cursor: pointer;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 10px;\n  text-align: center;\n  padding: 5px;\n  box-sizing: border-box;\n  flex: 1 1 auto;\n  white-space: nowrap;\n  overflow: hidden;\n}\n\n.plate-setup-tab:last-child {\n  border-right: none;\n}\n\n.plate-setup-tab-selected {\n  height: 24px;\n  background-color: white;\n  color: #00506e;\n  flex-shrink: 0;\n}\n\n.plate-setup-tab-data-container {\n  left: 0;\n  right: 0;\n  height: 442px;\n  border-bottom: solid 1px #e1e1e1;\n  position: absolute;\n  font-family: \"Roboto\", Arial, sans-serif;\n}\n\n.plate-setup-data-div {\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  position: absolute;\n  background-color: white;\n  overflow: auto;\n}\n\n.plate-setup-well-attr-container {\n  top: 472px;\n  left: 0;\n  right: 0;\n  height: 20px;\n  box-sizing: border-box;\n  padding: 0px 16px;\n  color: #00506e;\n  text-align: center;\n  position: absolute;\n  font-size: 10px;\n  font-family: \"Roboto\", Arial, sans-serif;\n}\n\n.plate-setup-preset-container {\n  top: 490px;\n  left: 0;\n  right: 0;\n  height: 22px;\n  position: absolute;\n  box-sizing: border-box;\n  padding: 0px 16px;\n  text-align: center;\n  display: flex;\n  justify-content: center;\n}\n\n.plate-setup-prest-tab {\n  display: inline-block;\n  flex-basis: 50px;\n  padding: 0 5px;\n  margin: 0 1px;\n  height: 20px;\n  background-color: white;\n  border: solid 1px #e1e1e1;\n  border-radius: 2px;\n  cursor: pointer;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 10px;\n  text-align: center;\n}\n\n.plate-setup-prest-tab-selected {\n  display: inline-block;\n  flex-basis: 50px;\n  padding: 0 5px;\n  margin: 0 1px;\n  height: 20px;\n  background-color: #e1e1e1;\n  border: solid 1px #e1e1e1;\n  border-radius: 2px;\n  cursor: pointer;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 11px;\n  text-align: center;\n  color: #00506e;\n}\n\n.plate-setup-prest-tab-div {\n  padding-top: 3px;\n}\n\n.plate-setup-tab-default-field {\n  display: flex;\n  padding: 10px 16px 0 16px;\n}\n\n.plate-setup-tab-field-left-side {\n  width: 32px;\n  padding-top: 16px;\n}\n\n.plate-setup-tab-field-right-side {\n  flex: 1;\n}\n\n.plate-setup-tab-name {\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  display: inline-block;\n  line-height: 16px;\n}\n\n.plate-setup-tab-name-singleSelect {\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  margin-top: 5px;\n}\n\n\n.plate-setup-tab-name-missing {\n  height: 20px;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  background: red;\n}\n\n\n.plate-setup-tab-field-container, .plate-setup-tab-field-container-singleSelect {\n  width: 100%;\n  display: flex;\n}\n\n.plate-setup-tab-input, .plate-setup-tab-select-field, .plate-setup-tab-multiplex-single-select-field {\n  height: 28px;\n  flex: 1 1 auto;\n  width: 30px;\n  margin: auto;\n}\n\n.plate-setup-tab-multiselect-field {\n  min-height: 28px;\n  flex: 1 1 auto;\n  width: 30px;\n}\n\n.plate-setup-tab-label-select-field, .plate-setup-tab-unit {\n  width: 130px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  height: 28px;\n  box-sizing: border-box;\n  padding-left: 5px;\n}\n\n.plate-setup-tab-unit {\n  font-family: \"Roboto\", Arial, sans-serif;\n  line-height: 26px;\n  color: #444;\n  white-space: nowrap;\n}\n\n.plate-setup-tab-check-box {\n  cursor: pointer;\n  border: 1px solid gray;\n  display: inline-block;\n  height: 16px;\n  width: 16px;\n  text-align: center;\n  line-height: 16px;\n}\n\n.plate-setup-bottom-control-container {\n  top: 0;\n  left: 0;\n  right: 0;\n  height: 32px;\n  background-color: #464646;\n  position: absolute;\n  display: flex;\n  justify-content:space-between;\n  align-items: baseline;\n  vertical-align: middle;\n}\n\n.plate-setup-bottom-container {\n  top: 540px;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  position: absolute;\n  background-color: #e1e1e1;\n}\n\n.plate-setup-bottom-table-container {\n  top: 32px;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  position: absolute;\n  overflow: auto;\n}\n\n\n.plate-setup-bottom-table {\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 14px;\n  border-collapse: collapse;\n  width: 100%;\n}\n\n.plate-setup-bottom-table th {\n  border: solid #c2c2c2 1px;\n  padding: 5px 10px;\n  font-weight: bold;\n  font-size: 12px;\n  text-align: left;\n}\n\n.plate-setup-bottom-table td {\n  border: solid #c2c2c2 1px;\n  padding: 5px 10px;\n  background-color: white;\n}\n\n.plate-setup-color-text {\n  font-size: 14px;\n  border: none;\n  border-radius: 2px;\n  padding: 3px 15px;\n  background-color: WHITE;\n  margin-right: 4px;\n}\n\n.plate-setup-bottom-id {\n  width: 40px;\n  text-align: center;\n  background-image: linear-gradient(to right, rgba(255,255,255,0.3), transparent)\n}\n\ninput.invalid {\n  background-color: pink;\n}\n\n.plate-setup-remove-all-button-container {\n  text-align: left;\n}\n\n.plate-setup-remove-all-button{\n  width: 100%;\n  font-family: \"Roboto\", Arial, sans-serif;\n  font-size: 12px;\n  text-overflow: ellipsis;\n  text-align: left;\n  white-space: nowrap;\n  border: 1px solid #aaa;\n  border-top: none;\n  color: #444;\n  background-color: #fff;\n  background-image: linear-gradient(to top, #eee 0%, #fff 50%);\n}\n/* Modal Content */\n\n.modal {\n  display: none; /* Hidden by default */\n  position: fixed; /* Stay in place */\n  z-index: 2000; /* Sit on top */\n  padding-top: 100px; /* Location of the box */\n  left: 0;\n  top: 0;\n  width: 100%; /* Full width */\n  height: 100%; /* Full height */\n  overflow: auto; /* Enable scroll if needed */\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */\n}\n\n.modal-content {\n  font-family: 'Roboto', sans-serif;\n  font-size: 14px;\n  background-color: #fefefe;\n  margin: auto;\n  padding: 20px;\n  border: 1px solid #888;\n}\n\n.delete-dialog .modal-content {\n  width: 550px;\n}\n\n.modal-content > * {\n  width: 100%;\n}\n\n.dialog-buttons {\n  margin-top: 10px;\n  display: inline-block;\n  text-align: right;\n}\n\n.dialog-buttons button {\n  margin-left: 4px;\n}\n\n.plate-popout-table {\n  border-collapse: collapse;\n  width: 100%;\n  border: 1px solid black;\n  padding: 5px;\n}\n\n.plate-popout-th {\n  text-align: left;\n  background-color: white;\n  color: black;\n  font-size: 12px;\n  border: 1px solid black;\n  padding: 5px;\n}\n\n.plate-popout-tr:hover {\n  background-color: #f5f5f5;\n  border: 1px solid black;\n  padding: 5px;\n}\n\n.plate-popout-td {\n  text-align: left;\n  font-size: 11px;\n  border: 1px solid black;\n  padding: 5px;\n}\n\n.plate-field-warning-image{\n  vertical-align: baseline;\n  margin: 0px 0 0px;\n}\n\n.pop-out-text {\n  position: fixed;\n  display: none;\n  background: white;\n  border: 1px solid;\n  float: left;\n  margin-top: -44px;\n  z-Index: 99999 !important;\n}\n"]}
\ No newline at end of file
diff --git a/dist/js/plate-map.js b/dist/js/plate-map.js
deleted file mode 100755
index 8ab5e1c..0000000
--- a/dist/js/plate-map.js
+++ /dev/null
@@ -1,4360 +0,0 @@
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.addDataOnChange = function() {
-    // This object is invoked when something in the tab fields change
-    return {
-
-      _addAllData: function(data) {
-        // Method to add data when something changes in the tabs. Its going to be tricky , just starting.
-        if (this.allSelectedObjects) {
-          var noOfSelectedObjects = this.allSelectedObjects.length;
-          var wells = [];
-          for (var objectIndex = 0; objectIndex < noOfSelectedObjects; objectIndex++) {
-            var tile = this.allSelectedObjects[objectIndex];
-            var well;
-            if (tile.index in this.engine.derivative) {
-              well = this.engine.derivative[tile.index];
-            } else {
-              well = $.extend(true, {}, this.defaultWell); 
-              this.engine.derivative[tile.index] = well; 
-            }
-            var processedData = this.processWellData(data, well, noOfSelectedObjects, wells);
-            wells = processedData.wells;
-            well = processedData.well;
-            var empty = this.engine.wellEmpty(well);
-            if (empty) {
-              if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {
-                var wellCopy = JSON.parse(JSON.stringify(well));
-                var defaultValue = this.emptyWellWithDefaultVal;
-                for (var key in defaultValue){
-                  if (key in wellCopy){
-                    wellCopy[key] = defaultValue[key];
-                    this._applyFieldData(key, defaultValue[key]);
-                  }
-                }
-                this.engine.derivative[tile.index] = wellCopy;
-              } else {
-                delete this.engine.derivative[tile.index];
-              }
-            }
-          }
-        }
-        // update multiplex remove all field
-        this._getAllMultipleVal(wells);
-        this.applyFieldWarning(wells);
-        // create well when default field is sent for the cases when user delete all fields during disabledNewDeleteWell mode
-        this._colorMixer();
-        this.derivativeChange();
-      },
-
-      processWellData: function(newData, curWell, noOfSelectedObjects, wellList) {
-
-        if (!wellList){
-          wellList = [];
-        }
-        for (var id in newData) {
-          var v;
-          if (newData[id] !== undefined && newData[id] !== null ) {
-            if (newData[id].multi){
-              var curData = newData[id];
-              var preData = curWell[id];
-              var newDt = this._getMultiData(preData, curData, id, noOfSelectedObjects);
-              // need to replace newData
-              v = JSON.parse(JSON.stringify(newDt));
-            } else {
-              v = JSON.parse(JSON.stringify(newData[id]));
-            }
-          } else {
-            v = JSON.parse(JSON.stringify(newData[id]));
-          }
-          curWell[id] = v;
-          wellList.push(curWell);
-        }
-
-        return {
-          well: curWell,
-          wells: wellList
-        }
-      },
-
-      _getMultiData: function(preData, curData, fieldId, noOfSelectedObjects) {
-        var addNew = curData.added;
-        var removed = curData.removed;
-        if (addNew) {
-          if (preData){
-            if (addNew.value) {
-              var add = true;
-              for (var listIdx in preData) {
-                var multiplexData = preData[listIdx];
-                // for cases when the add new data exist in well
-                if (multiplexData[fieldId].toString() === addNew.id.toString()) {
-                  add = false;
-                  // update subfield value
-                  preData = preData.map(function(val) {
-                    if (val[fieldId].toString() === addNew.id.toString()) {
-                      for (var subFieldId in val) {
-                        // over write previous data if only one well is selected
-                        if (subFieldId in addNew.value && subFieldId !== fieldId){
-                          if (noOfSelectedObjects === 1) {
-                            val[subFieldId] = addNew.value[subFieldId];
-                          } else if (addNew.value[subFieldId]) {
-                            val[subFieldId] = addNew.value[subFieldId];
-                          }
-                        }
-                      }
-                    }
-                    return val;
-                  })
-                }
-              }
-              if (add) {
-                preData.push(addNew.value);
-              }
-            } else if (preData.indexOf(addNew) < 0) {
-              preData.push(addNew);
-            }
-          } else {
-            preData = [];
-            if (addNew.value) {
-              preData.push(addNew.value);
-            } else if (addNew){
-              preData.push(addNew);
-            }
-          }
-        }
-
-        var removeListIndex = function(preData, removeIndex) {
-          var newPreData = [];
-          for (var idx in preData) {
-            if (parseInt(idx) !== parseInt(removeIndex)){
-              newPreData.push(preData[idx]);
-            }
-          }
-          return newPreData;
-        };
-
-        if (removed) {
-          var removeIndex;
-          // for multiplex field
-          if (removed.value) {
-            for (var listIdx in preData) {
-              var multiplexData = preData[listIdx];
-              if (multiplexData[fieldId].toString() === removed.id.toString()) {
-                removeIndex = listIdx;
-              }
-            }
-            // remove nested element
-            preData = removeListIndex(preData, removeIndex);
-          } else {
-            if (preData){
-              removeIndex = preData.indexOf(removed);
-              if (removeIndex >= 0) {
-                preData = removeListIndex(preData, removeIndex);
-              }
-            }
-          }
-        }
-        if (preData && (preData.length == 0)) {
-          preData = null; 
-        }
-        return preData
-      },
-
-      _colorMixer: function() {
-        if (!this.undoRedoActive) {
-            var data = this.createObject();
-            this.addToUndoRedo(data);
-        }
-        this.engine.searchAndStack(); 
-        this.engine.applyColors();
-        this.mainFabricCanvas.renderAll();
-      },
-
-      derivativeChange: function(){
-          this._trigger("updateWells", null, this.createObject());
-      },
-
-      createObject: function() {
-        var derivative = $.extend(true, {}, this.engine.derivative); 
-        var checkboxes = this.globalSelectedAttributes.slice(); 
-        var selectedAreas = this.selectedAreas.slice(); 
-        var focalWell = this.focalWell;
-
-        return {
-          "derivative": derivative,
-          "checkboxes": checkboxes,
-          "selectedAreas": selectedAreas,
-          "focalWell": focalWell,
-          "requiredField": this.requiredField
-        };
-      }
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.addDataToFields = function() {
-
-    return {
-
-      _addDataToTabFields: function(values) {
-        // Configure how data is added to tab fields
-        for (var id in values) {
-          this._applyFieldData(id, values[id]);
-        }
-      },
-
-      _applyFieldData: function(id, v) {
-        this.fieldMap[id].setValue(v); 
-      }
-    }
-  }
-})(jQuery, fabric)
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.addTabData = function() {
-
-    return {
-
-      fieldList: [], 
-      fieldMap: {},
-      autoId: 1,
-
-      _addTabData: function() {
-          // Here we may need more changes because attributes format likely to change
-          var tabData = this.options.attributes.tabs;
-          var that = this;
-          this.requiredField = [];
-          var multiplexFieldArray = [];
-          tabData.forEach(function (tab, tabPointer) {
-            if (tab["fields"]) {
-              var tabFields = tab["fields"];
-              var fieldArray = [];
-              var fieldArrayIndex = 0;
-              // Now we look for fields in the json
-              for (var field in tabFields) {
-                var data = tabFields[field];
-
-                if (!data.id) {
-                  data.id = "Auto" + that.autoId++;
-                  console.log("Field autoassigned id " + data.id);
-                }
-                if (!data.type) {
-                  data.type = "text";
-                  console.log("Field " + data.id + " autoassigned type " + data.type);
-                }
-
-                var field_val;
-                if (data.type === "multiplex") {
-                  field_val = that._makeMultiplexField(data, tabPointer, fieldArray);
-                  multiplexFieldArray.push(field_val);
-                } else {
-                  field_val = that._makeRegularField(data, tabPointer, fieldArray, true);
-                  if (data.type === "multiselect") {
-                    multiplexFieldArray.push(field_val);
-                  }
-                };
-              }
-
-              that.allDataTabs[tabPointer]["fields"] = fieldArray;
-            } else {
-              console.log("unknown format in field initialization");
-            }
-          });
-          that.multipleFieldList = multiplexFieldArray;
-      },
-
-      _makeSubField: function (data, tabPointer, fieldArray) {
-        var that = this;
-        if (!data.id) {
-          data.id = "Auto" + that.autoId++;
-          console.log("Field autoassigned id " + data.id);
-        }
-        if (!data.type) {
-          data.type = "text";
-          console.log("Field " + data.id + " autoassigned type " + data.type);
-        }
-        var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
-        var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
-        var wrapperDivRightSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-right-side");
-        var nameContainer = that._createElement("<div></div>").addClass("plate-setup-tab-name").text(data.name);
-        var fieldContainer = that._createElement("<div></div>").addClass("plate-setup-tab-field-container");
-
-        $(wrapperDivRightSide).append(nameContainer);
-        $(wrapperDivRightSide).append(fieldContainer);
-        $(wrapperDiv).append(wrapperDivLeftSide);
-        $(wrapperDiv).append(wrapperDivRightSide);
-        $(that.allDataTabs[tabPointer]).append(wrapperDiv);
-
-        var field = {
-          id: data.id,
-          name: data.name,
-          root: wrapperDiv,
-          data: data,
-          required: data.required || false
-        };
-
-        fieldArray.push(field);
-        that.fieldMap[data.id] = field;
-
-        return field;
-      },
-
-      _makeRegularField: function (data, tabPointer, fieldArray, checkbox){
-          var that = this;
-          var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
-          var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
-          var wrapperDivRightSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-right-side ");
-          var nameContainer = that._createElement("<div></div>").addClass("plate-setup-tab-name").text(data.name);
-          var fieldContainer = that._createElement("<div></div>").addClass("plate-setup-tab-field-container");
-
-          wrapperDivRightSide.append(nameContainer);
-          wrapperDivRightSide.append(fieldContainer);
-          wrapperDiv.append(wrapperDivLeftSide);
-          wrapperDiv.append(wrapperDivRightSide);
-          that.allDataTabs[tabPointer].append(wrapperDiv);
-
-          var field = {
-            id: data.id,
-            name: data.name,
-            root: wrapperDiv,
-            data: data,
-            required: data.required
-          };
-
-          if (field.required) {
-            that.requiredField.push(field.id);
-          }
-
-          fieldArray.push(field);
-          that.fieldList.push(field);
-          that.fieldMap[field.id] = field;
-
-          // Adding checkbox
-          if (checkbox) {
-            that._addCheckBox(field);
-          }
-          that._createField(field);
-
-          field.onChange = function () {
-            var v = field.getValue();
-            var data = {};
-            data[field.id] = v;
-            that._addAllData(data);
-          };
-          return field;
-      },
-
-      _makeMultiplexField: function (data, tabPointer, fieldArray) {
-        var that = this;
-        var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
-        var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
-        var wrapperDivRightSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-right-side ");
-        var nameContainer = that._createElement("<div></div>").addClass("plate-setup-tab-name").text(data.name);
-        var fieldContainer = that._createElement("<div></div>").addClass("plate-setup-tab-field-container");
-
-        wrapperDivRightSide.append(nameContainer);
-        wrapperDivRightSide.append(fieldContainer);
-        wrapperDiv.append(wrapperDivLeftSide);
-        wrapperDiv.append(wrapperDivRightSide);
-        that.allDataTabs[tabPointer].append(wrapperDiv);
-
-        var field = {
-          id: data.id,
-          name: data.name,
-          root: wrapperDiv,
-          data: data,
-          required: data.required
-        };
-
-        fieldArray.push(field);
-        that.fieldList.push(field);
-        that.fieldMap[data.id] = field;
-
-        var subFieldList = [];
-        //create subfields
-        var requiredSubField = [];
-        for (var subFieldKey in data.multiplexFields) {
-          var subFieldData = data.multiplexFields[subFieldKey];
-          var subField = that._makeSubField(subFieldData, tabPointer, fieldArray);
-          subFieldList.push(subField);
-
-          // stores required  subField
-          if (subFieldData.required) {
-            requiredSubField.push(subField.id);
-          }
-        }
-
-        //store required field
-        if (field.required || requiredSubField.length) {
-          this.requiredField.push ({
-            multiplexId: field.id,
-            subFields: requiredSubField
-          });
-        }
-
-        field.subFieldList = subFieldList;
-        that._createField(field);
-        that._addCheckBox(field);
-
-        subFieldList.forEach(function (subfield) {
-          subfield.mainMultiplexField = field;
-          fieldArray.push(subfield);
-          that._createField(subfield);
-          that._addCheckBox(subfield);
-          delete that.defaultWell[subfield.id];
-          // overwrite subField setvalue
-          subfield.onChange = function () {
-            var v = subfield.getValue();
-            var mainRefField = subfield.mainMultiplexField;
-            var curId = mainRefField.singleSelectValue();
-            //var curDataLs = mainRefField.detailData;
-            var curVal = {};
-            curVal[mainRefField.id] = curId;
-            //append subfields
-            curVal[subfield.id] = v;
-            var returnVal = {
-              id: curId,
-              value: curVal
-            };
-
-            field._changeMultiFieldValue(returnVal, null);
-            var curDataLs = mainRefField.detailData;
-            if (curDataLs !== null) {
-              curId = mainRefField.singleSelectValue(); 
-              curDataLs = curDataLs.map(function(curData) {
-                if (curData[mainRefField.id] === curId) {
-                  curData[subfield.id] = v;
-                }
-                return curData;
-              });
-            }
-            mainRefField.detailData = curDataLs;
-          };
-
-        });
-
-        field.getValue = function(){
-          var v = field.input.select2('data');
-          if (v.length) {
-            return v.map(function (i) {
-              return i.id;
-            });
-          }
-          return null;
-        };
-
-        return field;
-      }
-    }
-  }
-
-})(jQuery, fabric);
-
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.addWarningMsg = function () {
-    // For those check boxes associated with every field in the tab
-    return {
-      fieldWarningMsg: function (field, text, include) {
-        var that = this;
-        var imgId = "fieldWarning" + field.id;
-        var img = $("<span>").html(that._assets.warningImg).attr("id", imgId).addClass("plate-field-warning-image");
-        //field.root.find(".plate-setup-tab-name").append('<img id="theImg" src="theImg.png" />')
-        if (include) {
-          if (field.root.find("#" + imgId).length <= 0){
-            field.root.find(".plate-setup-tab-name").text(" " + field.name);
-            field.root.find(".plate-setup-tab-name").prepend(img);
-
-            var popText = $("<div/>").addClass("pop-out-text");
-            popText.text(text);
-            field.root.find(".plate-setup-tab-name").append(popText);
-
-            $("#" + imgId).hover(function (e) {
-              popText[0].style.display = 'flex';
-            }, function () {
-              popText.hide();
-            });
-          }
-
-
-        } else {
-          if (field.root.find("#" + imgId).length > 0) {
-            field.root.find(".plate-setup-tab-name").text(field.name);
-            $("#" + imgId).remove();
-          }
-        }
-      },
-
-      removeWarningMsg: function (field, text, include) {
-        var that = this;
-        var imgId = "fieldWarning" + field.id;
-        var img = $("<span>").html(that._assets.warningImg).attr("id", imgId).addClass("plate-field-warning-image");
-        //field.root.find(".plate-setup-tab-name").append('<img id="theImg" src="theImg.png" />')
-        if (include) {
-          field.root.find(".plate-setup-tab-name").append(img);
-
-          var popText = $("<div/>").addClass("pop-out-text");
-          popText.text(text);
-          field.root.find(".plate-setup-tab-name").append(popText);
-
-          $("#" + imgId).hover(function (e) {
-            popText[0].style.display = 'inline-block';
-          }, function () {
-            popText.hide();
-          });
-
-        } else {
-          $("#" + imgId).remove();
-          if (field.root.find("#" + imgId).length > 0) {
-            //field.root.find(".plate-setup-tab-name").remove(img);
-            $("#" + imgId).remove();
-          }
-        }
-      },
-
-      applyFieldWarning: function(wells) {
-        var that = this;
-        var req = 0;
-        var fill = 0;
-        var fieldData = {};
-        that.fieldList.forEach(function(field){
-          fieldData[field.id] = [];
-        });
-        wells.forEach(function(well){
-          if (!that.engine.wellEmpty(well)){
-            for (var fieldId in fieldData) {
-              if (fieldId in well) {
-                fieldData[fieldId].push(well[fieldId]);
-              } else {
-                fieldData[fieldId].push(null);
-              }
-            }
-          }
-        });
-        for (var i = 0; i < that.fieldList.length; i++) {
-          var field = that.fieldList[i];
-          if (field.applyMultiplexSubFieldColor){
-            field.applyMultiplexSubFieldColor(fieldData[field.id]);
-          } else {
-            if (field.required) {
-              var include = false;
-              fieldData[field.id].forEach(function(val){
-                // for multiselect
-                if (val instanceof Array) {
-                  if (val.length === 0) {
-                    include = true;
-                  }
-                } else {
-                  if (val === null) {
-                    include = true;
-                  }
-                }
-              });
-              //field.root.find(".plate-setup-tab-name").css("background", color);
-              that.fieldWarningMsg(field, "required field", include);
-            }
-          }
-        }
-      }
-    }
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.bottomTable = function() {
-    // for bottom table
-    return {
-      _bottomScreen: function() {
-        this.bottomContainer = this._createElement("<div></div>").addClass("plate-setup-bottom-container");
-        this.bottomTableContainer = this._createElement("<div></div>").addClass("plate-setup-bottom-table-container");
-        this.bottomTable = this._createElement("<table></table>").addClass("plate-setup-bottom-table");
-        this.bottomTableContainer.append(this.bottomTable);
-        this.bottomContainer.append(this.bottomTableContainer);
-        this.container.append(this.bottomContainer);
-      },
-
-      addBottomTableHeadings: function() {
-
-        this.bottomRow = this._createElement("<tr></tr>");
-
-        var singleField = this._createElement("<th></th>")
-          .text("Group");
-        this.bottomRow.prepend(singleField);
-        // Now we append all the captions at the place.
-        this.bottomTable.empty();
-        this.bottomTable.append(this.bottomRow);
-
-        this.rowCounter = 1;
-
-        for (var i = 0; i < this.globalSelectedAttributes.length; i++) {
-          var attr = this.globalSelectedAttributes[i];
-          var field = this.fieldMap[attr];
-          var singleField = this._createElement("<th></th>").text(field.name);
-          this.bottomRow.append(singleField);
-          this.rowCounter = this.rowCounter + 1;
-        }
-
-        this.adjustFieldWidth(this.bottomRow);
-      },
-
-      tileAttrText: function(tile, attr) {
-        var well = this.engine.derivative[tile.index];
-        var field = this.fieldMap[attr];
-        return field.getText(well[attr]);
-      },
-
-      addBottomTableRow: function(color, singleStack) {
-        var that = this;
-        var modelTile = this.allTiles[singleStack[0]];
-        var row = this._createElement("<tr></tr>");
-        var plateIdDiv = this._createElement("<td></td>").addClass("plate-setup-bottom-id");
-        var numberText = this._createElement("<button/>");
-        numberText.addClass("plate-setup-color-text");
-        numberText.text(color);
-        plateIdDiv.append(numberText);
-
-        numberText.click(function(evt){
-          var addressToSelect = singleStack.map(function(addressIdx){
-            return that.indexToAddress(addressIdx)
-          });
-          if (evt.ctrlKey) {
-            that.getSelectedAddress().forEach(function(val){
-              if (addressToSelect.indexOf(val) < 0){
-                addressToSelect.push(val);
-              }
-            })
-          }
-          that.setSelectedWell(addressToSelect);
-          that._trigger("selectedWells", null, {selectedAddress: that.getSelectedAddress()});
-        });
-
-        if (color > 0) {
-          color = ((color - 1) % (this.colorPairs.length - 1)) + 1;
-        }
-        var colorStops = this.colorPairs[color];
-
-        plateIdDiv.css("background", "linear-gradient(to right, " + colorStops[0] + " , " + colorStops[1] + ")");
-
-        row.append(plateIdDiv);
-
-        for (var i = 0; i < this.globalSelectedAttributes.length; i++) {
-          var attr = this.globalSelectedAttributes[i];
-          var text = this.tileAttrText(modelTile, attr);
-          var dataDiv = this._createElement("<td></td>").text(text);
-          row.append(dataDiv);
-        }
-        this.bottomTable.append(row);
-        this.adjustFieldWidth(row);
-      },
-
-      bottomForFirstTime: function() {
-        this.addBottomTableHeadings();
-        // This is executed for the very first time.. !
-        var row = this._createElement("<tr></tr>");
-
-        var colorStops = this.colorPairs[0];
-        var plateIdDiv = this._createElement("<td></td>");
-        plateIdDiv.css("background", "-webkit-linear-gradient(left, " + colorStops[0] + " , " + colorStops[1] + ")");
-        row.append(plateIdDiv);
-        this.bottomTable.append(row);
-        this.createExportButton();
-      },
-
-      adjustFieldWidth: function(row) {
-
-        var length = this.rowCounter;
-        if ((length) * 150 > 1024) {
-          row.css("width", (length) * 152 + "px");
-        }
-      },
-
-      downloadCSV: function(csv, filename) {
-        var csvFile;
-        var downloadLink;
-
-        // CSV file
-        csvFile = new Blob([csv], {
-          type: "text/csv"
-        });
-
-        // Download link
-        downloadLink = document.createElement("a");
-
-        // File name
-        downloadLink.download = filename;
-
-        // Create a link to the file
-        downloadLink.href = window.URL.createObjectURL(csvFile);
-
-        // Hide download link
-        downloadLink.style.display = "none";
-
-        // Add the link to DOM
-        document.body.appendChild(downloadLink);
-
-        // Click download link
-        downloadLink.click();
-      },
-
-      exportData: function(format) {
-        var data = [];
-        var rows = document.querySelectorAll("table tr");
-
-        var colorLocMap = {};
-        var colorLocIdxMap = this.engine.stackUpWithColor;
-        var dim = this.getDimensions();
-        var that = this;
-        for (var colorIdx in colorLocIdxMap) {
-          colorLocMap[colorIdx] = colorLocIdxMap[colorIdx].map(function (locIdx) {
-            return that.indexToAddress(locIdx, dim);
-          })
-        }
-
-        for (var i = 0; i < rows.length; i++) {
-          var row = [],
-            cols = rows[i].querySelectorAll("td, th");
-
-          for (var j = 0; j < cols.length; j++) {
-            var v = "";
-            if (cols[j].innerText) {
-              if (format === "csv") {
-                v = '"' + cols[j].innerText.replace(/"/g, '""') + '"';
-              } else {
-                v = cols[j].innerText;
-              }
-            }
-            row.push(v);
-
-            // add location column
-            if (i === 0 && j === 0) {
-              if (format === "csv") {
-                row.push('"Location"');
-              } else if (format === 'clipboard') {
-                row.push("Location");
-              }
-
-            }
-            if (i !== 0 && j === 0) {
-              var loc = '';
-              if (colorLocMap[parseInt(cols[j].innerText)]) {
-                if (format === "csv") {
-                  loc = '"' + colorLocMap[parseInt(cols[j].innerText)].join(",") + '"';
-                } else if (format === 'clipboard') {
-                  loc = colorLocMap[parseInt(cols[j].innerText)].join(",");
-                }
-              }
-              row.push(loc);
-            }
-          }
-
-          if (format === "csv") {
-            data.push(row.join(","));
-          } else if (format === 'clipboard') {
-            data.push(row.join("\t"));
-            //data.push(row);   // for text type
-          }
-
-        }
-        if (format === "csv") {
-          // Download CSV file
-          this.downloadCSV(data.join("\n"), 'table.csv');
-        } else if (format === 'clipboard') {
-          //return formatTableToString(data);   // for text type
-          return data.join("\n");
-        }
-      },
-
-      createExportButton: function() {
-        var that = this;
-        var overlayContainer = $("<div>").addClass("plate-setup-bottom-control-container");
-
-        var descriptionDiv = $("<div>").addClass("plate-setup-overlay-text-container");
-        descriptionDiv.text("Color groups");
-        overlayContainer.append(descriptionDiv);
-
-        var buttonContainer = $("<div>").addClass("plate-setup-overlay-bottom-button-container");
-
-        // create export csv option
-        var exportButton = $("<button/>").addClass("plate-setup-button");
-        exportButton.text("Export CSV");
-        buttonContainer.append(exportButton);
-
-        exportButton.click(function() {
-          that.exportData('csv');
-          exportButton.text("Exported");
-          exportButton[0].classList.remove("plate-setup-button");
-          exportButton.addClass("plate-setup-clicked-button");
-          setTimeout(resetExportText, 3000);
-        });
-
-        function resetExportText() {
-          exportButton.text("Export CSV");
-          exportButton[0].classList.remove("plate-setup-clicked-button");
-          exportButton.addClass("plate-setup-button");
-        }
-
-        // creat clipboard option, CLipboard is an external js file located in vendor/asset/javascripts
-        var clipboardButton = $("<button/>").addClass("plate-setup-button");
-        clipboardButton.text("Copy To Clipboard");
-        buttonContainer.append(clipboardButton);
-
-        var clipboard = new ClipboardJS(clipboardButton.get(0), {
-          text: function() {
-            return that.exportData("clipboard");
-          }
-        });
-
-        clipboard.on('success', function(e) {
-          clipboardButton.text("Copied as tab-delimited format");
-          clipboardButton[0].classList.remove("plate-setup-button");
-          clipboardButton.addClass("plate-setup-clicked-button");
-          setTimeout(resetClipboardText, 3000);
-        });
-
-        function resetClipboardText() {
-          clipboardButton.text("Copy To Clipboard");
-          clipboardButton[0].classList.remove("plate-setup-clicked-button");
-          clipboardButton.addClass("plate-setup-button");
-        }
-
-        clipboard.on('error', function(e) {
-          clipboardButton.text("Failed to copy table to clipboard: browser may be incompatible");
-          setTimeout(resetClipboardText, 3000);
-        });
-
-        overlayContainer.append(buttonContainer);
-        $(".plate-setup-bottom-container").prepend(overlayContainer);
-      }
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.canvas = function() {
-    //
-    return {
-
-      allSelectedObjects: null, // Contains all the selected objets, when click and drag.
-
-      allPreviouslySelectedObjects: null,
-
-      colorPointer: 0,
-
-      goldenRatio: 0.618033988749895,
-
-      _createCanvas: function() {
-        this.normalCanvas = this._createElement("<canvas>").attr("id", "DNAcanvas");
-        $(this.canvasContainer).append(this.normalCanvas);
-      },
-
-      _initiateFabricCanvas: function() {
-        var w = this.canvasContainer.width(); 
-        var h = this.canvasContainer.height(); 
-
-        this._setCanvasArea(w, h);
-
-        this.mainFabricCanvas = new fabric.Canvas('DNAcanvas', {
-            backgroundColor: '#f5f5f5',
-            selection: false,
-            stateful: false,
-            hoverCursor: "pointer",
-            renderOnAddRemove: false,
-          })
-          .setWidth(w)
-          .setHeight(h);
-      },
-
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.checkBox = function() {
-    // For those check boxes associated with every field in the tab
-    return {
-
-      globalSelectedAttributes: [],
-
-      _addCheckBox: function(field) {
-        var checkImage = $("<span>").html(this._assets.dontImg).addClass("plate-setup-tab-check-box bg-light")
-          .data("clicked", false);
-        checkImage.data("linkedFieldId", field.id);
-        field.root.find(".plate-setup-tab-field-left-side").empty().append(checkImage);
-        this._applyCheckboxHandler(checkImage); // Adding handler for change the image when clicked
-        field.checkbox = checkImage;
-      },
-
-      _applyCheckboxHandler: function(checkBoxImage) {
-        // We add checkbox handler here, thing is it s not checkbox , its an image and we change
-        // source
-        var that = this;
-        checkBoxImage.click(function(evt, machineClick) {
-          var checkBox = $(this);
-
-          var changes = {};
-          changes[checkBox.data("linkedFieldId")] = !checkBox.data("clicked");
-
-          that.changeCheckboxes(changes);
-        });
-      },
-
-      changeSubFieldsCheckboxes: function(field, changes) {
-        var that = this;
-        var subFieldToInclude = [];
-
-        field.subFieldList.forEach(function(subField) {
-          var checkImage = subField.checkbox;
-          var fieldId = checkImage.data("linkedFieldId");
-          var clicked = checkImage.data("clicked");
-          if (fieldId in changes) {
-            clicked = Boolean(changes[fieldId]);
-          }
-          checkImage.data("clicked", clicked);
-          if (clicked) {
-            checkImage.html(that._assets.doImg);
-            subFieldToInclude.push(subField.id);
-          } else {
-            checkImage.html(that._assets.dontImg);
-          }
-        });
-        return subFieldToInclude;
-      },
-
-      changeCheckboxes: function(changes) {
-        var gsa = [];
-        var multiplexCheckedSubField = {};
-        for (var i = 0; i < this.fieldList.length; i++) {
-          var field = this.fieldList[i];
-          if (field.checkbox) {
-            if (field.subFieldList) {
-              multiplexCheckedSubField[field.id] = this.changeSubFieldsCheckboxes(field, changes);
-            }
-
-            var checkImage = field.checkbox;
-            var fieldId = checkImage.data("linkedFieldId");
-            var clicked = checkImage.data("clicked");
-            if (fieldId in changes) {
-              clicked = Boolean(changes[fieldId]);
-            }
-            checkImage.data("clicked", clicked);
-            if (clicked) {
-              gsa.push(fieldId);
-              checkImage.html(this._assets.doImg);
-            } else {
-              checkImage.html(this._assets.dontImg);
-            }
-          }
-        }
-        this.globalSelectedMultiplexSubfield = multiplexCheckedSubField;
-        this.globalSelectedAttributes = gsa;
-        this._clearPresetSelection();
-        this._colorMixer();
-      },
-
-      setSubFieldCheckboxes: function(field, fieldIds) {
-        var that = this;
-        var subFieldToInclude = [];
-        field.subFieldList.forEach(function(subField) {
-          var checkImage = subField.checkbox;
-          var fieldId = checkImage.data("linkedFieldId");
-          var clicked = fieldIds.indexOf(fieldId) >= 0;
-          checkImage.data("clicked", clicked);
-          if (clicked) {
-            checkImage.html(that._assets.doImg);
-            subFieldToInclude.push(subField.id);
-          } else {
-            checkImage.html(that._assets.dontImg);
-          }
-        });
-        return subFieldToInclude;
-      },
-
-      setCheckboxes: function(fieldIds) {
-        fieldIds = fieldIds || [];
-        var gsa = [];
-        var multiplexCheckedSubField = {};
-
-        for (var i = 0; i < this.fieldList.length; i++) {
-          var field = this.fieldList[i];
-          if (field.checkbox) {
-            // special handling for multiplex field
-            if (field.subFieldList) {
-              multiplexCheckedSubField[field.id] = this.setSubFieldCheckboxes(field, fieldIds);
-            }
-
-            var checkImage = field.checkbox;
-            var fieldId = checkImage.data("linkedFieldId");
-            var clicked = fieldIds.indexOf(fieldId) >= 0;
-            checkImage.data("clicked", clicked);
-            if (clicked) {
-              gsa.push(fieldId);
-              checkImage.html(this._assets.doImg);
-            } else {
-
-              checkImage.html(this._assets.dontImg);
-            }
-          }
-        }
-        this.globalSelectedMultiplexSubfield = multiplexCheckedSubField;
-        this.globalSelectedAttributes = gsa;
-        this._clearPresetSelection();
-        this._colorMixer();
-      }
-
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.colorManager = function() {
-
-    return {
-        // See these are color pairs for the gradient.
-      colorPairs: [
-        ["#e6e6e6", "#808080"],
-        ["#66e8ff", "#0082c8"],
-        ["#ff7fb1", "#e6194b"],
-        ["#a2ffb1", "#3cb44b"],
-        ["#f784ff", "#911eb4"],
-        ["#ffe897", "#f58231"],
-        ["#6666ff", "#0000FF"],
-        ["#ffff7f", "#ffe119"],
-        ["#acffff", "#46f0f0"],
-        ["#ff98ff", "#f032e6"],
-        ["#ffffa2", "#d2f53c"],
-        ["#ffffff", "#fabebe"],
-        ["#66e6e6", "#008080"],
-        ["#ffffff", "#e6beff"],
-        ["#ffd48e", "#aa6e28"],
-        ["#e66666", "#800000"],
-        ["#ffffff", "#aaffc3"],
-        ["#e6e666", "#808000"],
-        ["#ffffff", "#ffd8b1"],
-        ["#66a9ef", "#004389"],
-        ["#ff6672", "#a7000c"],
-        ["#66db72", "#00750c"],
-        ["#b866db", "#520075"],
-        ["#ffa966", "#b64300"],
-        ["#ffff66", "#c0a200"],
-        ["#6dffff", "#07b1b1"],
-        ["#ff66ff", "#b100a7"],
-        ["#f9ff66", "#93b600"],
-        ["#ffe5e5", "#bb7f7f"],
-        ["#66a7a7", "#004141"],
-        ["#ffe5ff", "#a77fc0"],
-        ["#d19566", "#6b2f00"],
-        ["#ffffef", "#c0bb89"],
-        ["#d1ffea", "#6bc084"],
-        ["#a7a766", "#414100"],
-        ["#ffffd8", "#c09972"],
-        ["#a5ffff", "#3fc1ff"],
-        ["#ffbef0", "#ff588a"],
-        ["#e1fff0", "#7bf38a"],
-        ["#ffc3ff", "#d05df3"],
-        ["#ffffd6", "#ffc170"],
-        ["#a5a5ff", "#3f3fff"],
-        ["#ffffbe", "#ffff58"],
-        ["#ebffff", "#85ffff"],
-        ["#ffd7ff", "#ff71ff"],
-        ["#a5ffff", "#3fbfbf"],
-        ["#ffffcd", "#e9ad67"],
-        ["#ffa5a5", "#bf3f3f"],
-        ["#ffffa5", "#bfbf3f"]
-      ]
-    }
-  }
-
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.createCanvasElements = function() {
-    // this class manages creating all the elements within canvas
-    return {
-
-      scaleFactor: 1, 
-
-      baseSizes: {
-        spacing: 48, 
-        tile_radius: 22, 
-        center_radius_complete: 10, 
-        center_radius_incomplete: 14, 
-        label_size: 14, 
-        label_spacing: 24, 
-        text_size: 13,
-        stroke: 0.5, 
-        gap: 2
-      }, 
-
-      _setCanvasArea: function(w, h) {
-        this.scaleFactor = Math.min(
-           h / (this.dimensions.rows * this.baseSizes.spacing + this.baseSizes.label_spacing), 
-           w / (this.dimensions.cols * this.baseSizes.spacing + this.baseSizes.label_spacing));
-
-        var sizes = {}
-        for (var prop in this.baseSizes) {
-          sizes[prop] = this.baseSizes[prop] * this.scaleFactor; 
-        }
-        this.sizes = sizes; 
-      }, 
-
-      _canvas: function() {
-        // Those 1,2,3 s and A,B,C s
-        this._fixRowAndColumn();
-
-        // All those circles in the canvas.
-        this._putCircles();
-      },
-
-      _fixRowAndColumn: function() {
-        var cols = this.dimensions.cols;
-        var rows = this.dimensions.rows;
-
-        var spacing = this.sizes.spacing;
-        var d1 = this.sizes.label_spacing / 2;
-        var d2 = this.sizes.label_spacing + this.sizes.spacing / 2; 
-        var fontSize = this.sizes.label_size; 
-
-        // For column
-        var top = d1; 
-        var left = d2;  
-        for (var i = 1; i <= cols; i++) {
-          var tempFabricText = new fabric.IText(i.toString(), {
-            fill: 'black',
-            originX: 'center',
-            originY: 'center',
-            fontSize: fontSize,
-            top: top,
-            left: left,
-            fontFamily: '"Roboto", Arial, sans-serif',
-            selectable: false,
-            fontWeight: "400"
-          });
-          left += spacing; 
-
-          this.mainFabricCanvas.add(tempFabricText);
-        }
-
-        // for row
-        top = d2; 
-        left = d1; 
-        for (var i = 1; i <= rows; i++) {
-          var tempFabricText = new fabric.IText(this.rowIndex[i-1], {
-            fill: 'black',
-            originX: 'center',
-            originY: 'center',
-            fontSize: fontSize,
-            top: top,
-            left: left,
-            fontFamily: '"Roboto", Arial, sans-serif',
-            selectable: false,
-            fontWeight: "400"
-          });
-          top += spacing; 
-
-          this.mainFabricCanvas.add(tempFabricText);
-        }
-      },
-
-      _putCircles: function() {
-        var cols = this.dimensions.cols;
-        var rows = this.dimensions.rows;
-
-        var tileCounter = 0;
-        for (var row = 0; row < rows; row++) {
-          for (var col = 0; col < cols; col++) {
-            var index = this.allTiles.length; 
-            var tile = this._createTile(row, col); 
-            tile.index = tileCounter++; 
-            this.allTiles.push(tile);
-            this.mainFabricCanvas.add(tile.background);
-            this.mainFabricCanvas.add(tile.highlight);
-            this.mainFabricCanvas.add(tile.circle);
-            this.mainFabricCanvas.add(tile.circleCenter);
-            this.mainFabricCanvas.add(tile.circleText);
-          }
-        }
-
-        this._addLargeRectangleOverlay();
-        this._fabricEvents();
-      },
-
-      _createTile: function (row, col) {
-        var tile = {}; 
-
-        tile.visible = false; 
-        tile.colorIndex = null; 
-        tile.row = row; 
-        tile.col = col; 
-        tile.address = this.rowIndex[row] + (col + 1); 
-
-        var top = (row + 1) * this.sizes.spacing;
-        var left = (col + 1) * this.sizes.spacing; 
-
-        tile.background = new fabric.Circle({
-          top: top,
-          left: left,
-          radius: this.sizes.tile_radius,
-          originX: 'center',
-          originY: 'center',
-          hasControls: false,
-          hasBorders: false,
-          lockMovementX: true,
-          lockMovementY: true,
-          evented: false,
-        });
-
-        tile.background.setGradient("fill", {
-          type: "radial",
-          x1: this.sizes.tile_radius, 
-          x2: this.sizes.tile_radius, 
-          y1: this.sizes.tile_radius + this.sizes.gap,
-          y2: this.sizes.tile_radius + this.sizes.gap,
-          r1: this.sizes.tile_radius - this.sizes.gap,
-          r2: this.sizes.tile_radius,
-          colorStops: {
-            0: 'rgba(0,0,0,0.1)',
-            1: 'rgba(0,0,0,0.2)'
-          }
-        });
-
-        tile.highlight = new fabric.Rect({
-          originX: 'center',
-          originY: 'center',
-          top: top,
-          left: left,
-          width: this.sizes.spacing,
-          height: this.sizes.spacing,
-          fill: "rgba(0,0,0,0.4)",
-          evented: false,
-          visible: false
-        });
-
-        tile.circle = new fabric.Circle({
-          originX: 'center',
-          originY: 'center',
-          top: top,
-          left: left,
-          radius: this.sizes.tile_radius,
-          stroke: 'gray',
-          strokeWidth: this.sizes.stroke,
-          evented: false, 
-          visible: false
-        });
-
-        tile.circleCenter = new fabric.Circle({
-          originX: 'center',
-          originY: 'center',
-          top: top,
-          left: left,
-          radius: this.sizes.center_radius_incomplete,
-          fill: "white",
-          stroke: 'gray',
-          strokeWidth: this.sizes.stroke,
-          evented: false,
-          visible: false
-        });
-
-        tile.circleText = new fabric.IText("", {
-          originX: 'center',
-          originY: 'center',
-          top: top,
-          left: left,
-          fill: 'black',
-          fontFamily: '"Roboto", Arial, sans-serif',
-          fontSize: this.sizes.text_size,
-          lockScalingX: true,
-          lockScalingY: true,
-          evented: false,
-          visible: false
-        });
-
-        return tile; 
-      }, 
-
-      setTileComplete: function (tile, complete) {
-        if (complete) {
-          tile.circleCenter.radius = this.sizes.center_radius_complete;
-          tile.circleText.fill = "black";
-          tile.circleText.fontWeight = 'normal';
-        } else {
-          tile.circleCenter.radius = this.sizes.center_radius_incomplete;
-          tile.circleText.fill = "red";
-          tile.circleText.fontWeight = 'bold';
-        }
-      }, 
-
-      setTileVisible: function (tile, visible) {
-        tile.visible = visible;
-        tile.circle.visible = tile.visible;
-        tile.circleCenter.visible = tile.visible;
-        tile.circleText.visible = tile.visible;
-      },
-
-      setTileColor: function(tile, color, stackPointer) {
-        this.setTileVisible(tile, true);
-        tile.colorIndex = parseInt(color); 
-        tile.circleText.text = String(tile.colorIndex);
-
-        if (color > 0) {
-          color = ((color - 1) % (this.colorPairs.length -1)) + 1;
-        }
-        var colorStops = this.colorPairs[color];
-
-        tile.circle.setGradient("fill", {
-          y2: 2 * this.sizes.tile_radius,
-          colorStops: colorStops
-        });
-      },
-
-      _addLargeRectangleOverlay: function() {
-
-        this.overLay = new fabric.Rect({
-          width: 632,
-          height: 482,
-          left: 0,
-          top: 0,
-          opacity: 0.0,
-          originX: 'left',
-          originY: 'top',
-          lockMovementY: true,
-          lockMovementX: true,
-          selectable: false
-        });
-
-        this.mainFabricCanvas.add(this.overLay);
-      }
-    };
-  }
-})(jQuery, fabric);
-
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.createField = function() {
-    // It create those fields in the tab , there is 4 types of them.
-    return {
-
-      _createField: function(field) {
-        switch (field.data.type) {
-          case "text":
-            this._createTextField(field);
-            break;
-
-          case "numeric":
-            this._createNumericField(field);
-            break;
-
-          case "select":
-            this._createSelectField(field);
-            break;
-
-          case "multiselect":
-            this._createMultiSelectField(field);
-            break;
-
-          case "boolean":
-            this._createBooleanField(field);
-            break;
-
-          case "multiplex":
-            this._createMultiplexField(field);
-            break;
-        }
-      },
-
-      _createTextField: function(field) {
-        var id = field.id;
-        var that = this;
-        var input = this._createElement("<input>").attr("id", id)
-          .addClass("plate-setup-tab-input");
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        that.defaultWell[id] = null;
-
-        field.parseValue = function(v) {
-          if (v) {
-            v = String(v);
-          } else {
-            v = null;
-          }
-          return v;
-        };
-
-        field.getValue = function() {
-          var v = input.val().trim();
-          if (v == "") {
-            v = null;
-          }
-          return v;
-        };
-
-        field.setValue = function(v) {
-          input.val(v);
-        };
-
-        field.getText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          return v;
-        };
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-        };
-
-        field.parseText = field.parseValue;
-
-        input.on("input", function(e, generated) {
-          field.onChange();
-        });
-
-        field.input = input;
-      },
-
-      _createOpts: function(config) {
-        var opts = {
-          allowClear: true,
-          placeholder: "select",
-          minimumResultsForSearch: 10
-        };
-
-        if (config.options) {
-          opts.data = config.options;
-        } else if (config.query) {
-          var query = config.query;
-          if (config.delay) {
-            query = this._debounce(config.delay, query);
-          }
-          opts.query = query;
-        } else {
-          throw "Must specify data or query";
-        }
-        return opts;
-      },
-
-      _createSelectField: function(field) {
-        var id = field.id;
-        var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
-          .addClass("plate-setup-tab-select-field");
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        that.defaultWell[id] = null;
-
-        var opts = that._createOpts(field.data);
-        var optMap = {};
-        opts.data.forEach(function(opt) {
-          optMap[opt.id] = opt;
-        });
-
-        input.select2(opts);
-
-        field.parseValue = function(value) {
-          var v = value;
-
-          if (v == "") {
-            v = null;
-          }
-          if (v == null) {
-            return null;
-          }
-          if (v in optMap) {
-            return optMap[v].id;
-          } else {
-            throw "Invalid value " + value + " for select field " + id;
-          }
-        };
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-        };
-
-        field.getValue = function() {
-          var v = input.select2('data');
-          return v ? v.id : null;
-        };
-
-        field.setValue = function(v) {
-          if (v) {
-            v = optMap[v];
-          }
-          input.select2('data', v);
-        };
-
-        field.setOpts = function(v) {
-          input.select2('data', {});
-          opts.data = v || [];
-          input.select2(opts);
-        };
-
-        field.getText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          return optMap[v].text;
-        };
-
-        field.parseText = function(value) {
-          var v = value;
-
-          if (v == "") {
-            v = null;
-          }
-          if (v == null) {
-            return null;
-          }
-          if (v in optMap) {
-            return optMap[v].text;
-          } else {
-            throw "Invalid text value " + value + " for select field " + id;
-          }
-        };
-
-        input.on("change", function(e, generated) {
-          field.onChange();
-        });
-
-        field.input = input;
-      },
-
-      _createMultiSelectField: function(field) {
-        var id = field.id;
-        var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
-          .addClass("plate-setup-tab-multiselect-field");
-        input.attr("multiple", "multiple");
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        that.defaultWell[id] = null;
-
-        var separator = ",";
-        var opts = that._createOpts(field.data);
-        opts.multiple = true;
-        var optMap = {};
-        opts.data.forEach(function(opt) {
-          optMap[opt.id] = opt;
-        });
-        input.select2(opts);
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-        };
-
-        field.parseValue = function(value) {
-          var v = value;
-          if (v && v.length) {
-            v = v.map(function(opt) {
-              if (opt in optMap) {
-                return optMap[opt].id;
-              } else {
-                throw "Invalid value " + opt + " for multiselect field " + id;
-              }
-            });
-          } else {
-            v = null;
-          }
-          return v;
-        };
-
-        field.setOpts = function(v) {
-          var allOpts = field.data.options;
-          var selectedVal = [];
-          for (var id in allOpts) {
-            var curOpts = allOpts[id];
-            if (v.indexOf(curOpts["id"]) >= 0) {
-              selectedVal.push(curOpts);
-            }
-          }
-
-          opts.data = selectedVal;
-          input.select2(opts);
-        };
-
-        field.getValue = function() {
-          var v = input.select2('data');
-          if (v.length) {
-            return v.map(function(i) {
-              return i.id;
-            });
-          }
-          return null;
-        };
-
-        field.setValue = function(v) {
-          v = v || [];
-          v = v.map(function(i) {
-            return optMap[i];
-          });
-          input.select2('data', v);
-        };
-
-        field.getText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          if (v.length > 0) {
-            return v.map(function(v) {
-              return optMap[v].text
-            }).join("; ");
-          }
-          return "";
-        };
-
-        field.multiOnChange = function (added, removed) {
-          if (added) {
-            added = added.id.toString();
-          }
-          if (removed) {
-            removed = removed.id.toString();
-          }
-          var data = {
-          };
-          data[field.id] = {
-            multi: true,
-            added: added,
-            removed: removed
-          };
-
-          that._addAllData(data);
-        };
-
-        field.parseText = function(value){
-          var v = value;
-          if (v && v.length) {
-            v = v.map(function(opt) {
-              if (opt in optMap) {
-                return optMap[opt].text;
-              } else {
-                throw "Invalid text value " + opt + " for multiselect field " + id;
-              }
-            });
-          } else {
-            v = null;
-          }
-          return v;
-        };
-
-        input.on("change", function(e, generated) {
-          var added = e.added;
-          var removed = e.removed;
-          //field.onChange();
-          field.multiOnChange(added, removed);
-        });
-
-        field.input = input;
-
-        that._createDeleteButton(field);
-      },
-
-      _createNumericField: function(field) {
-        var id = field.id;
-        var data = field.data;
-        var that = this;
-        var input = this._createElement("<input>").addClass("plate-setup-tab-input")
-          .attr("placeholder", data.placeholder || "").attr("id", id);
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        that.defaultWell[id] = null;
-
-        // Adding unit
-        var units = data.units || [];
-        var defaultUnit = data.defaultUnit || null;
-        var unitInput = null;
-        if (defaultUnit) {
-          if (units.length) {
-            if (units.indexOf(defaultUnit) < 0) {
-              defaultUnit = units[0];
-            }
-          } else {
-            units = [defaultUnit];
-          }
-        } else {
-          if (units.length) {
-            defaultUnit = units[0];
-          }
-        }
-
-        if (units.length) {
-          field.units = units;
-          field.hasUnits = true;
-          field.defaultUnit = defaultUnit;
-          if (units.length == 1) {
-            var unitText = $("<div></div>").addClass("plate-setup-tab-unit");
-            unitText.text(defaultUnit);
-            field.root.find(".plate-setup-tab-field-container").append(unitText);
-          } else {
-            unitInput = this._createElement("<input/>").attr("id", id)
-              .addClass("plate-setup-tab-label-select-field");
-
-            field.root.find(".plate-setup-tab-field-container").append(unitInput);
-
-            var selected = null;
-            var unitData = units.map(function(unit) {
-              var o = {
-                id: unit,
-                text: unit
-              };
-              if (unit == defaultUnit) {
-                selected = o;
-              }
-              return o;
-            });
-
-            var opts = {
-              data: unitData,
-              allowClear: false,
-              minimumResultsForSearch: 10
-            };
-
-            unitInput.select2(opts);
-            unitInput.select2("data", selected);
-          }
-        }
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-          if (unitInput) {
-            unitInput.prop("disabled", bool);
-          }
-        };
-
-        field.setUnitOpts = function(opts) {
-          field.units = opts || null;
-          field.defaultUnit = null;
-
-          var newUnits = [];
-          var selected = null;
-          if (field.units && field.units.length) {
-            field.defaultUnit = field.units[0];
-            newUnits = field.units.map(function(curUnit) {
-              var cleanUnit = {
-                id: curUnit,
-                text: curUnit
-              };
-              if (curUnit == field.defaultUnit) {
-                selected = cleanUnit;
-              }
-              return cleanUnit;
-            });
-          }
-
-          var newOpts = {
-            data: newUnits,
-            allowClear: false,
-            minimumResultsForSearch: 10
-          };
-          unitInput.select2(newOpts);
-          unitInput.select2("data", selected);
-        };
-
-        field.parseValue = function(value) {
-          var v;
-          if ($.isPlainObject(value)) {
-            if (field.hasUnits) {
-              v = field.parseRegularValue(value.value);
-              if (v === null) {
-                return null;
-              }
-              return {
-                value: v,
-                unit: field.parseUnit(value.unit)
-              };
-            } else {
-              throw "Value must be plain numeric for numeric field " + id;
-            }
-          } else {
-            if (field.hasUnits) {
-              v = field.parseRegularValue(value);
-              if (v === null) {
-                return null;
-              }
-              return {
-                value: v,
-                unit: field.defaultUnit
-              };
-            } else {
-              return field.parseRegularValue(value);
-            }
-          }
-        };
-
-        field.getValue = function() {
-          var v = field.getRegularValue();
-
-          if ((v === null) || isNaN(v)) {
-            return null;
-          } else if (field.hasUnits) {
-            var returnVal = {
-              value: v,
-              unit: field.getUnit()
-            };
-
-            if (field.data.hasMultiplexUnit) {
-              // include unitTypeId and UnitId to returnVal
-              for (var unitTypeKey in field.data.unitMap) {
-                var unitTypeUnits = field.data.unitMap[unitTypeKey];
-                unitTypeUnits.forEach(function(unit) {
-                  if (unit.text === returnVal.unit) {
-                    returnVal['unitTypeId'] = unitTypeKey;
-                    returnVal['unitId'] = unit.id;
-                  }
-                })
-              }
-            }
-            return returnVal;
-          } else {
-            return v;
-          }
-        };
-
-        field.setValue = function(value) {
-          if (field.hasUnits) {
-            if ($.isPlainObject(value)) {
-              field.setUnit(value.unit || field.defaultUnit);
-              field.setRegularValue(value.value);
-
-            } else {
-              field.setRegularValue(value);
-              field.setUnit(field.defaultUnit)
-            }
-          } else {
-            field.setRegularValue(value);
-          }
-        };
-
-        field.parseRegularValue = function(value) {
-          if (value == null) {
-            return null;
-          }
-          var v = String(value).trim();
-          if (v === "") {
-            return null;
-          }
-          v = Number(value);
-          if (isNaN(v)) {
-            throw "Invalid value " + value + " for numeric field " + id;
-          }
-          return v;
-        };
-
-        field.getRegularValue = function() {
-          var v = input.val().trim();
-          if (v == "") {
-            v = null;
-          } else {
-            v = Number(v);
-          }
-          return v;
-        };
-
-        field.setRegularValue = function(value) {
-          input.val(value);
-        };
-
-        field.parseUnit = function(unit) {
-          if (unit == null || unit === "") {
-            return field.defaultUnit;
-          }
-          for (var i = 0; i < units.length; i++) {
-            if (unit.toLowerCase() == units[i].toLowerCase()) {
-              return units[i];
-            }
-          }
-          throw "Invalid unit " + unit + " for field " + id;
-        };
-
-        field.getUnit = function() {
-          if (unitInput) {
-            return unitInput.val();
-          } else {
-            return field.defaultUnit;
-          }
-        };
-
-        field.setUnit = function(unit) {
-          if (unitInput) {
-            unit = unit || field.defaultUnit;
-            if (unit != null) {
-              unit = {
-                id: unit,
-                text: unit
-              };
-            }
-            unitInput.select2("data", unit);
-          }
-        };
-
-        // val now contains unit
-        field.getText = function(val) {
-          if (typeof(val) === 'object' && val) {
-            var v = val.value;
-            var u = val.unit;
-            if (v == null) {
-              return "";
-            }
-            v = v.toString();
-            if (!u) {
-              u = defaultUnit;
-            }
-            if (u) {
-              v = v + " " + u;
-            }
-            return v;
-          } else {
-            return field.getRegularText(val);
-          }
-        };
-
-        field.getRegularText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          v = v.toString();
-          return v;
-        };
-
-        field.parseText = function(v){
-          var textVal = field.parseValue(v);
-          if (textVal && typeof(textVal) === "object"){
-            return textVal.value + textVal.unit;
-          } else if (textVal) {
-            return textVal
-          } else {
-            return null;
-          }
-        };
-
-        input.on("input", function() {
-          var v = field.getRegularValue();
-          if (isNaN(v)) {
-            //flag field as invalid
-            input.addClass("invalid");
-          } else {
-            input.removeClass("invalid");
-          }
-          field.onChange();
-        });
-        if (unitInput) {
-          unitInput.on("change", function() {
-            field.onChange();
-          });
-        }
-
-        field.input = input;
-        field.unitInput = unitInput;
-      },
-
-      _createBooleanField: function(field) {
-        var id = field.id;
-        var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
-          .addClass("plate-setup-tab-select-field");
-        that.defaultWell[id] = null;
-
-        field.root.find(".plate-setup-tab-field-container").append(input);
-        var tval = {
-          id: "true",
-          text: "true"
-        };
-        var fval = {
-          id: "false",
-          text: "false"
-        };
-        var opts = {
-          data: [tval, fval],
-          placeholder: "select",
-          allowClear: true,
-          minimumResultsForSearch: -1,
-          initSelection: function(element, callback) {
-            var v = element.val();
-            callback({
-              id: v,
-              text: v
-            });
-          }
-        };
-
-        input.select2(opts);
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-        };
-
-        field.parseValue = function(value) {
-          if (value == null) {
-            return null;
-          }
-          var v = String(value).trim().toLowerCase();
-          if (v == "true") {
-            v = true;
-          } else if (v == "false") {
-            v = false;
-          } else if (v == "") {
-            v = null;
-          } else {
-            throw "Invalid value " + value + " for boolean field " + id;
-          }
-          return v;
-        };
-
-        field.getValue = function() {
-          var v = input.val();
-          switch (v) {
-            case "true":
-              return true;
-            case "false":
-              return false;
-            default:
-              return null;
-          }
-        };
-
-        field.setValue = function(v) {
-          if (v == true || v == "true") {
-            v = tval;
-          } else if (v == false || v == "false") {
-            v = fval;
-          } else {
-            v = null;
-          }
-          input.select2('data', v);
-        };
-
-        field.getText = function(v) {
-          if (v == null) {
-            return "";
-          }
-          return v.toString();
-        };
-
-        field.parseText = field.parseValue;
-
-        input.on("change", function(e) {
-          field.onChange();
-        });
-
-        field.input = input;
-      },
-
-      _createMultiplexField: function(field) {
-        var that = this;
-        // make correct multiplex data
-        this._createMultiSelectField(field);
-        // overwrite default well for multiplex field
-        that.defaultWell[field.id] = [];
-
-        // single select
-        var nameContainer1 = that._createElement("<div></div>").addClass("plate-setup-tab-name-singleSelect").text("Select to edit");
-        var fieldContainer1 = that._createElement("<div></div>").addClass("plate-setup-tab-field-container-singleSelect");
-        field.root.find(".plate-setup-tab-field-right-side").append(nameContainer1, fieldContainer1);
-
-        field.singleSelect = this._createElement("<input/>").attr("id", field.id + "SingleSelect")
-          .addClass("plate-setup-tab-multiplex-single-select-field");
-
-        field.singleSelect.appendTo(fieldContainer1);
-
-        field.singleSelectValue = function () {
-          var v = field.singleSelect.select2("data");
-          if (v != null) {
-            v = v.id;
-          }
-          return v;
-        };
-
-        var setSingleSelectOptions = function (v, selected_v) {
-          var opts = {
-            allowClear: false,
-            placeholder: "select",
-            minimumResultsForSearch: 10,
-            data: v || []
-          }
-          if (!selected_v) {
-            if (opts.data.length) {
-              selected_v = opts.data[0];
-            } else {
-              selected_v = null;
-            }
-          }
-          field.singleSelect.select2('data', []);
-          field.singleSelect.select2(opts);
-          field.singleSelect.select2('data', selected_v);
-          field.singleSelect.prop("disabled", opts.data.length == 0);
-        };
-
-        var singleSelectChange = function () {
-          var v = field.singleSelectValue();
-
-          field.updateSubFieldUnitOpts(v);
-
-          var curData = field.detailData || [];
-          var curSubField = null;
-          curData.forEach(function(val) {
-            if (val[field.id] === v) {
-              curSubField = val;
-            }
-          });
-
-          if (curSubField) {
-            // setvalue for subfield
-            field.subFieldList.forEach(function(subField) {
-              subField.disabled(false);
-              subField.setValue(curSubField[subField.id]);
-            });
-          } else {
-            field.subFieldList.forEach(function(subField) {
-              subField.disabled(true);
-              subField.setValue(null);
-            });
-          }
-          that.readOnlyHandler();
-        };
-
-        setSingleSelectOptions([]);
-
-        field.singleSelect.on("change", singleSelectChange);
-
-        field._changeMultiFieldValue = function(added, removed) {
-          var newSubFieldValue = {};
-          for (var subFieldName in field.data.multiplexFields) {
-            var subFieldId = field.data.multiplexFields[subFieldName].id;
-            newSubFieldValue[subFieldId] = null;
-          }
-
-          var val;
-          if (added) {
-            if (added.value) {
-              val = added.value;
-            } else {
-              newSubFieldValue[field.id] = added.id;
-              val = newSubFieldValue;
-            }
-            added = {
-              id: added.id,
-              value: val
-            };
-          }
-
-          if (removed) {
-            if (removed.value){
-              val = removed.value;
-            } else {
-              newSubFieldValue[field.id] = removed.id;
-              val = newSubFieldValue;
-            }
-            removed = {
-              id: removed.id,
-              value: val
-            };
-          }
-
-          var data = {};
-          data[field.id] = {
-            multi: true,
-            added: added,
-            removed: removed
-          };
-          that._addAllData(data);
-        };
-
-        var multiselectSetValue = field.setValue;
-
-        // overwrite multiplex set value
-        field.setValue = function(v) {
-          // used to keep track of initially loaded multiplex data
-          field.detailData = v;
-          var multiselectValues = null;
-          if (v && v.length) {
-            multiselectValues = v.map(function(val) {
-              return val[field.id]
-            });
-          }
-
-          multiselectSetValue(multiselectValues);
-          var newOptions = field.input.select2('data') || [];
-          setSingleSelectOptions(newOptions);
-          singleSelectChange();
-        };
-
-        field.disabled = function(bool) {
-          field.input.prop("disabled", bool);
-          field.subFieldList.forEach(function(subField) {
-            subField.disabled(bool);
-          });
-          if (bool) {
-            nameContainer1.text("Select to inspect");
-          } else {
-            nameContainer1.text("Select to edit");
-          }
-        };
-
-        field.parseValue = function(value) {
-          var v = value;
-          if (v && v.length) {
-            v = v.map(function(opt) {
-              var valMap = {};
-              valMap[field.id] = opt[field.id];
-              for (var subFieldId in opt) {
-                field.subFieldList.forEach(function(subField) {
-                  if (subField.id === subFieldId) {
-                    valMap[subField.id] = subField.parseValue(opt[subFieldId]);
-                  }
-                });
-              }
-              return valMap;
-            });
-          } else {
-            v = null;
-          }
-          return v;
-        };
-
-        field.updateSubFieldUnitOpts = function(val) {
-          var curOpts;
-          field.data.options.forEach(function(opt) {
-            if (opt.id === val) {
-              curOpts = opt;
-            }
-          });
-          field.subFieldList.forEach(function(subField) {
-            if (subField.data.hasMultiplexUnit) {
-              if (curOpts && curOpts.hasOwnProperty("unitOptions")) {
-								subField.setUnitOpts(curOpts.unitOptions[subField.id]);
-              } else {
-                subField.setUnitOpts(null);
-              }
-            }
-          })
-        };
-
-        field.multiOnChange = function(added, removed) {
-          field._changeMultiFieldValue(added, removed);
-          var v = field.getValue();
-          var curData = field.detailData;
-          var curIds = [];
-          var curOpt = null;
-          //reshape data for saveback
-          if (curData) {
-            curIds = curData.map(function(val) {
-              return val[field.id]
-            });
-          }
-
-          var newMultiplexVal = [];
-          var selectList = [];
-          if (v) {
-            v.forEach(function(selectedVal) {
-              if (curData) {
-                curData.forEach(function(val) {
-                  if (val[field.id] === selectedVal) {
-                    newMultiplexVal.push(val)
-                  }
-                });
-              }
-              // cases when adding new data
-              if (curIds.indexOf(selectedVal) < 0) {
-                var newVal = {};
-                newVal[field.id] = selectedVal;
-
-                field.updateSubFieldUnitOpts(selectedVal);
-                field.subFieldList.forEach(function(subfield) {
-                  // special handling for subfield which has multiplexUnit
-                  if (subfield.hasUnits) {
-                    if (subfield.data.hasMultiplexUnit) {
-                      subfield.disabled(false);
-                      field.data.options.forEach(function(opt) {
-                        if (opt.id === selectedVal) {
-                          var val = {
-                            value: null,
-                            unit: subfield.units[0]
-                          };
-                          newVal[subfield.id] = subfield.parseValue(val);
-                        }
-                      });
-                    } else {
-                      if (subfield.data.units) {
-                        if (subfield.data.units.length > 1){
-                          subfield.disabled(false);
-                        }
-                      }
-                      var val = {
-                        value: null,
-                        unit: subfield.defaultUnit
-                      };
-                      newVal[subfield.id] = subfield.parseValue(val);
-                    }
-                  }
-                   else {
-                    newVal[subfield.id] = subfield.parseValue(null);
-                  }
-                });
-                newMultiplexVal.push(newVal);
-              }
-            });
-
-            // make data for single select options
-            v.forEach(function(selectId) {
-              field.data.options.forEach(function(opt) {
-                if (opt.id === selectId) {
-                  selectList.push(opt);
-                }
-              });
-            });
-            // set the newest selected to be the current obj
-            curOpt = selectList[v.length - 1];
-          }
-
-          field.detailData = newMultiplexVal;
-          setSingleSelectOptions(selectList, curOpt);
-          singleSelectChange();
-        };
-
-        field.getText = function(v) {
-          if (v === null) {
-            return "";
-          }
-          // get subfields that is selected from the checkbox
-          if (field.id in that.globalSelectedMultiplexSubfield) {
-            var checkedSubfields = that.globalSelectedMultiplexSubfield[field.id];
-            var returnVal = [];
-            for (var valIdx in v) {
-              var subV = v[valIdx];
-              var subText = [];
-              for (var optId in field.data.options) {
-                var opt = field.data.options[optId];
-                if (opt.id === subV[field.id]) {
-                  subText.push(opt.text);
-                }
-              }
-              field.subFieldList.forEach(function(subField) {
-                if (checkedSubfields.indexOf(subField.id) >= 0) {
-                  var x = subField.getText(subV[subField.id]);
-                  subText.push(subField.name + ": " + x);
-                }
-              });
-              returnVal.push("{" + subText.join(", ") + "}");
-            }
-            return returnVal.join(";");
-          }
-        };
-
-        field.parseText = function(v) {
-          if (v === null) {
-            return "";
-          } else {
-            var returnVal = [];
-            for (var valIdx in v) {
-              var subV = v[valIdx];
-              var subText = [];
-              for (var optId in field.data.options) {
-                var opt = field.data.options[optId];
-                if (opt.id === subV[field.id]) {
-                  subText.push(opt.text);
-                }
-              }
-              field.subFieldList.forEach(function(subField) {
-                var x = subField.getText(subV[subField.id]);
-                if (x) {
-                  subText.push(x);
-                }
-              });
-              returnVal.push(subText);
-            }
-            return returnVal;
-          }
-        };
-
-        field.checkMultiplexCompletion = function(valList) {
-          var valCount = 0;
-          var completionPct = 0;
-          var include = false;
-          function getSubfieldStatus (vals) {
-            var req = 0;
-            var fill = 0;
-            for (var subFieldId in field.subFieldList) {
-              var subField = field.subFieldList[subFieldId];
-              var curVal = vals[subField.id];
-              if (subField.required) {
-                include = true;
-                req++;
-                if (typeof(curVal) === 'object' && curVal) {
-                  if (curVal.value) {
-                    fill++;
-                  }
-                } else if (curVal) {
-                  fill++;
-                }
-              }
-            }
-            return fill/req;
-          }
-
-          // for cases has value in multiplex field
-          if (valList) {
-            if (valList.length > 0){
-              for (var idx in valList) {
-                valCount++;
-                var vals = valList[idx];
-                completionPct += getSubfieldStatus(vals);
-              }
-            } else if (field.required) {
-              include = true;
-              valCount = 1;
-            }
-          }  else if (field.required) {
-            include = true;
-            valCount = 1;
-          }
-
-          return {
-            include: include,
-            completionPct: completionPct/valCount
-          };
-        };
-
-        // valList contains all of the vals for selected val
-        field.applyMultiplexSubFieldColor = function(valList){
-          function updateSubFieldWarningMap (vals) {
-            for (var subFieldId in field.subFieldList) {
-              var subField = field.subFieldList[subFieldId];
-              // loop through each well's multiplexval list
-              if (vals === null){
-                if (field.required && subField.required){
-                  subFieldWarningMap[subField.id].warningStatus.push(true);
-                }
-              } else if (typeof(vals) === "object") {
-                if (vals.length === 0) {
-                  if (field.required && subField.required){
-                    subFieldWarningMap[subField.id].warningStatus.push(true);
-                  }
-                } else {
-                  for (var multiplexIdx in vals) {
-                    var curVal = vals[multiplexIdx][subField.id];
-                    if (subField.required) {
-                      if (typeof(curVal) === 'object' && curVal) {
-                        if (!curVal.value) {
-                          subFieldWarningMap[subField.id].warningStatus.push(true);
-                        } else {
-                          subFieldWarningMap[subField.id].warningStatus.push(false);
-                        }
-                      } else if (!curVal) {
-                        subFieldWarningMap[subField.id].warningStatus.push(true);
-                      } else {
-                        subFieldWarningMap[subField.id].warningStatus.push(false);
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-
-          var subFieldWarningMap = {};
-          field.subFieldList.forEach(function(subField){
-            if (subField.required) {
-              subFieldWarningMap[subField.id] = {
-                field: subField,
-                warningStatus: []
-              };
-            }
-          });
-
-          valList.forEach(function(multiplexVals) {
-            updateSubFieldWarningMap(multiplexVals);
-          });
-          // turn off main field when all subfield are filled
-
-          var requiredSubField = [];
-          var mainFieldStatus = [];
-          for (var subFieldId in subFieldWarningMap){
-            var subField = subFieldWarningMap[subFieldId].field;
-            if (subFieldWarningMap[subFieldId].warningStatus.indexOf(true) >= 0) {
-              var text =  subField.name + " is a required subfield for " + field.name + ", please make sure all " + field.name + " have " + subField.name;
-              if (field.required){
-                that.fieldWarningMsg(subField, text, true);
-                mainFieldStatus.push(true);
-              } else {
-                that.fieldWarningMsg(subField, text, true);
-                mainFieldStatus.push(true);
-              }
-            } else {
-              that.fieldWarningMsg(subField, "none", false);
-              mainFieldStatus.push(false);
-            }
-          }
-          var mainFieldWarning = false;
-          if (mainFieldStatus.indexOf(true) < 0) {
-            mainFieldWarning = false;
-          } else {
-            mainFieldWarning = true;
-          }
-          var warningText;
-          if (field.required) {
-            warningText = field.name + " is a required field, please also fix missing required subfield(s) below";
-          } else {
-            warningText = field.name + " is not a required field, please fix missing required subfield(s) below or remove selected " + field.name;
-          }
-          that.fieldWarningMsg(field, warningText, mainFieldWarning);
-        };
-
-        field.parseMainFieldVal = function(val) {
-          var optMap = field.data.options;
-          for (var idx = 0; idx < optMap.length; idx++){
-            var curOpt = optMap[idx];
-            if (curOpt.id === val){
-              return curOpt.text
-            }
-          }
-        };
-      },
-
-      _deleteDialog: function (field) {
-        var that = this;
-
-        var valMap = field.allSelectedMultipleVal;
-        var valToRemove;
-        if (valMap) {
-          valToRemove = Object.keys(valMap);
-        } else {
-          valToRemove = [];
-        }
-
-
-        var dialogDiv = $("<div/>").addClass("delete-dialog modal");
-        $('body').append(dialogDiv);
-
-        function killDialog() {
-          dialogDiv.hide();
-          dialogDiv.remove();
-        }
-
-        var dialogContent = $("<div/>").addClass("modal-content").appendTo(dialogDiv);
-        var tableArea = $("<div/>").appendTo(dialogContent);
-        var buttonRow = $("<div/>").addClass("dialog-buttons").css("justify-content", "flex-end").appendTo(dialogContent);
-
-        if (valToRemove.length > 0){
-          // apply CSS property for table
-          $("<p/>").text(field.name + " in selected wells: choose items to delete and click the delete button below").appendTo(tableArea);
-
-          var table = that._deleteDialogTable(field, valMap);
-          table.appendTo(tableArea);
-          table.addClass("plate-popout-table");
-          table.find('td').addClass("plate-popout-td");
-          table.find('th').addClass("plate-popout-th");
-          table.find('tr').addClass("plate-popout-tr");
-          if (!that.readOnly) {
-            var deleteCheckedButton = $("<button class='multiple-field-manage-delete-button'>Delete Checked Items</button>");
-            buttonRow.append(deleteCheckedButton);
-            deleteCheckedButton.click(function() {
-              table.find("input:checked").each(function () {
-                var val = this.value;
-                field.multiOnChange(null, {id: val});
-              });
-              // refresh selected fields after updating the multiplex field value
-              that.decideSelectedFields();
-              killDialog();
-            });
-          }
-
-        } else {
-          $("<p/>").text("No " + field.name + " in the selected wells").appendTo(tableArea);
-        }
-
-        var cancelButton = $("<button>Cancel</button>");
-        buttonRow.append(cancelButton);
-        cancelButton.click(killDialog);
-
-        dialogDiv.show();
-
-        window.onclick = function(event) {
-          if (event.target == dialogDiv[0]) {
-            killDialog();
-          }
-        }
-      },
-
-      _deleteDialogTable: function (field, valMap) {
-        var that = this;
-        var colName = [field.name, "Counts"]; //Added because it was missing... no idea what the original should have been
-        if (!that.readOnly) {
-          colName.push("Delete");
-        }
-        var table = $('<table/>');
-        var thead = $('<thead/>').appendTo(table);
-        var tr = $('<tr/>').appendTo(thead);
-
-        tr.append(colName.map(function (text) {
-          return $('<th/>').text(text);
-        }));
-
-        var tbody = $("<tbody/>").appendTo(table);
-
-        field.data.options.forEach(function (opt) {
-          if (opt.id in valMap) {
-            var tr = $('<tr/>').appendTo(tbody);
-            var checkbox = $("<input type='checkbox'>").prop("value", opt.id);
-            $("<td/>").text(opt.text).appendTo(tr);
-            $("<td/>").text(valMap[opt.id]).appendTo(tr);
-            if (!that.readOnly) {
-              $("<td/>").append(checkbox).appendTo(tr);
-            }
-          }
-        });
-
-        return table;
-      },
-
-      _createDeleteButton: function (field) {
-        var that = this;
-        var deleteButton = $("<button/>").addClass("plate-setup-remove-all-button");
-        deleteButton.id = field.id + "Delete";
-        deleteButton.text("Manage " + field.name + "...");
-        var buttonContainer = that._createElement("<div></div>").addClass("plate-setup-remove-all-button-container");
-        buttonContainer.append(deleteButton);
-
-        field.deleteButton = deleteButton;
-        field.root.find(".plate-setup-tab-field-right-side").append(buttonContainer);
-
-        deleteButton.click(function () {
-          that._deleteDialog(field);
-        });
-      }
-
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.engine = function(THIS) {
-    // Methods which look after data changes and stack up accordingly
-    // Remember THIS points to plateLayOutWidget and 'this' points to engine
-    // Use THIS to refer parent this.
-    return {
-      engine: {
-
-        derivative: {},
-        stackUpWithColor: {},
-        stackPointer: 2,
-
-        wellEmpty: function (well) {
-          for (var prop in well) {
-            var curVal = well[prop];
-            if (curVal !== null && curVal !== undefined) {
-              if (Array.isArray(curVal)) {
-                if (curVal.length > 0) {
-                  return false;
-                }
-              } else {
-                return false;
-              }
-            }
-          }
-          return true;
-        },
-
-        searchAndStack: function() {
-          // This method search and stack the change we made.
-          this.stackUpWithColor = {};
-          this.stackPointer = 1;
-          var derivativeJson = {};
-          for (var idx in this.derivative) {
-            var data = this.derivative[idx];
-            var wellData = {};
-            for (var i = 0; i < THIS.globalSelectedAttributes.length; i++) {
-              var attr = THIS.globalSelectedAttributes[i]; 
-
-              if (attr in THIS.globalSelectedMultiplexSubfield){
-                var selectedSubFields = THIS.globalSelectedMultiplexSubfield[attr];
-                var newMultiplexVal = [];
-                for (var multiplexIdx in data[attr]){
-                  var curMultiplexVals = data[attr][multiplexIdx];
-                  var newVal = {};
-                  newVal[attr] = curMultiplexVals[attr];
-                  selectedSubFields.forEach(function (subFieldId) {
-                    newVal[subFieldId] = curMultiplexVals[subFieldId];
-                  });
-                  newMultiplexVal.push(newVal);
-                }
-                wellData[attr] = newMultiplexVal;
-              } else {
-                if (data[attr] != null) {
-                  wellData[attr] = data[attr];
-                }
-              }
-            }
-            if ($.isEmptyObject(wellData)) {
-              derivativeJson[idx] = null; 
-            } else {
-              derivativeJson[idx] = JSON.stringify(wellData);
-            }
-          }
-
-          while (!$.isEmptyObject(derivativeJson)) {
-            var keys = Object.keys(derivativeJson).map(function (k) {return parseFloat(k, 10);});
-            keys.sort(function (a, b) {return a-b;}); 
-
-            var refDerivativeIndex = keys[0];
-            var referenceDerivative = derivativeJson[refDerivativeIndex];
-            var arr = [];
-
-            if (!referenceDerivative) {
-              // if no checked box has value, push it to first spot
-              if (this.stackUpWithColor[0]) {
-                this.stackUpWithColor[0].push(refDerivativeIndex);
-              } else {
-                this.stackUpWithColor[0] = [refDerivativeIndex];
-              }
-
-              delete derivativeJson[refDerivativeIndex];
-            } else {
-              // if checked boxes have values
-              for (var i = 0; i < keys.length; i++) {
-                var idx = keys[i]; 
-                if (referenceDerivative == derivativeJson[idx]) {
-                  arr.push(idx);
-                  this.stackUpWithColor[this.stackPointer] = arr;
-                  delete derivativeJson[idx];
-                }
-              }
-              if (arr.length > 0)
-                this.stackPointer++;
-            }
-          }
-        },
-
-        applyColors: function() {
-
-          var wholeNoTiles = 0;
-          var wholePercentage = 0;
-
-          THIS.addBottomTableHeadings();
-
-          for (var i = 0; i < THIS.allTiles.length; i++) {
-            var tile = THIS.allTiles[i];
-            THIS.setTileVisible(tile, false);
-          }
-
-          for (var color = 0; color < this.stackPointer; color++) {
-            var arr = this.stackUpWithColor[color];
-            if (arr) {
-              THIS.addBottomTableRow(color, arr);
-
-              for (var tileIndex in arr) {
-                wholeNoTiles++;
-                var index = this.stackUpWithColor[color][tileIndex]; 
-                var tile = THIS.allTiles[index];
-                var well = this.derivative[index];
-                THIS.setTileColor(tile, color, this.stackPointer); 
-                // Checks if all the required fields are filled
-                var completion = this.checkCompletion(well, tile);
-                THIS.setTileComplete(tile, completion == 1); 
-                wholePercentage = wholePercentage + completion;
-              }
-            }
-          }
-
-          wholePercentage = Math.floor(100 * wholePercentage / wholeNoTiles);
-
-          if (isNaN(wholePercentage)) {
-            THIS.overLayTextContainer.text("Completion Percentage: 0%");
-          } else {
-            THIS.overLayTextContainer.text("Completion Percentage: " + wholePercentage + "%");
-          }
-        },
-
-        checkCompletion: function(wellData, tile) {
-          var req = 0; 
-          var fill = 0;
-          for (var i = 0; i < THIS.fieldList.length; i++) {
-            var field = THIS.fieldList[i];
-            if (field.checkMultiplexCompletion){
-              // also apply color
-              var multiplexStatus = field.checkMultiplexCompletion(wellData[field.id]);
-              if (multiplexStatus.include) {
-                fill += multiplexStatus.completionPct;
-                req++;
-              }
-            } else {
-              if (field.required) {
-                req++;
-                if (wellData[field.id] !== null) {
-                  fill++;
-                }
-              }
-            }
-          }
-          if (req === fill) {
-            return 1; 
-          }
-          return fill / req;
-        },
-      }
-    }
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.fabricEvents = function() {
-    // This object contains Menu items and how it works;
-    return {
-      colorToIndex: {},
-      startCoords: {
-        x: 0,
-        y: 0
-      },
-      focalWell: {
-        row: 0,
-        col: 0
-      },
-      selectedAreas: [],
-
-      _clickCoords: function(evt) {
-        //Get XY Coords for a given event. 
-        var rect = evt.e.target.getBoundingClientRect();
-        return {
-          x: evt.e.clientX - rect.left,
-          y: evt.e.clientY - rect.top
-        };
-      },
-
-      _fabricEvents: function() {
-        // Set up event handling. 
-        var that = this;
-
-        $(that.target).on("getPlates", function(evt, data) {
-          // This method should be compatable to redo/undo.
-          that.getPlates(JSON.parse(data));
-        });
-
-        that.mainFabricCanvas.on("mouse:down", function(evt) {
-          // Start selecting new area
-          that.selecting = true;
-          var coords = that._clickCoords(evt);
-
-          var areas = that.selectedAreas.slice();
-          var focalWell = that.focalWell;
-          var startCoords = that._wellToCoords(focalWell, true);
-          var rect = that._coordsToRect(startCoords, coords);
-
-          if (evt.e.ctrlKey) {
-            //adding new area
-            startCoords = coords;
-            rect = that._coordsToRect(startCoords, coords);
-            focalWell = that._coordsToWell(startCoords);
-            if (evt.e.shiftKey) {
-              //replacing existing areas
-              areas = [that._rectToArea(rect)];
-            } else {
-              areas.push(that._rectToArea(rect));
-            }
-          } else {
-            if (evt.e.shiftKey) {
-              //Altering last area
-              areas[areas.length - 1] = that._rectToArea(rect);
-            } else {
-              //Creating new area
-              startCoords = coords;
-              rect = that._coordsToRect(startCoords, coords);
-              focalWell = that._coordsToWell(startCoords);
-              areas = [that._rectToArea(rect)];
-            }
-          }
-
-          that.startCoords = startCoords;
-          that.setSelection(areas, focalWell);
-          that.mainFabricCanvas.renderAll();
-        });
-
-        that.mainFabricCanvas.on("mouse:move", function(evt) {
-          if (that.selecting) {
-            // continue selecting new area
-            var areas = that.selectedAreas.slice();
-            var endCoords = that._clickCoords(evt);
-            var rect = that._coordsToRect(that.startCoords, endCoords);
-            var area = that._rectToArea(rect);
-            if (area) {
-              areas[areas.length - 1] = area;
-            }
-
-            that.setSelection(areas, that.focalWell);
-            that.mainFabricCanvas.renderAll();
-          }
-
-        });
-
-        that.mainFabricCanvas.on("mouse:up", function(evt) {
-          // finish selecting new area
-          that.selecting = false;
-          var areas = that.selectedAreas.slice();
-          var endCoords = that._clickCoords(evt);
-          var rect = that._coordsToRect(that.startCoords, endCoords);
-          var area = that._rectToArea(rect);
-          if (area) {
-            areas[areas.length - 1] = area;
-          }
-
-          that.setSelection(areas, that.focalWell);
-          that.decideSelectedFields();
-          that.mainFabricCanvas.renderAll();
-          that._trigger("selectedWells", null, {selectedAddress: that.getSelectedAddress()});
-        });
-      },
-
-      setSelection: function(areas, focalWell) {
-        this.selectedAreas = areas;
-        this.focalWell = focalWell;
-        this.allSelectedObjects = this._areasToTiles(areas);
-        this._setSelectedTiles();
-        this._setFocalWellRect(this.focalWell);
-        document.activeElement.blur();
-      },
-
-      _setFocalWellRect: function(well) {
-        var flag;
-        // check if not allow to add or delete existing wells
-        if (this.disableAddDeleteWell) {
-          var address = this.locToAddress({
-            r: well.row,
-            c: well.col
-          });
-          if  (this.addressAllowToEdit.indexOf(address) < 0) {
-            flag = false;
-            this.setFieldsDisabled(true);
-          } else {
-            flag = true;
-            this.setFieldsDisabled(false);
-          }
-        } else if (well) {
-          flag = true;
-        }
-
-        if (flag) {
-          var rect = this._areaToRect(this._wellToArea(well));
-          var strokeWidth = 2;
-          if (this.focalWellRect) {
-            //update focalWellRect
-            this.focalWellRect.top = rect.top;
-            this.focalWellRect.left = rect.left;
-            this.focalWellRect.width = rect.width - strokeWidth;
-            this.focalWellRect.height = rect.height - strokeWidth;
-          } else {
-            //create focalWellRect
-            this.focalWellRect = new fabric.Rect({
-              width: rect.width - strokeWidth,
-              height: rect.height - strokeWidth,
-              left: rect.left,
-              top: rect.top,
-              fill: null,
-              strokeWidth: strokeWidth,
-              stroke: "black",
-              selectable: false
-            });
-            this.mainFabricCanvas.add(this.focalWellRect);
-          }
-        } else {
-          //clear focalWellRect
-          this.mainFabricCanvas.remove(this.focalWellRect);
-          this.focalWellRect = null;
-        }
-      },
-
-      _setSelectedTiles: function() {
-        // Update selected tile display only
-        var selectedTiles = this.allSelectedObjects;
-        this.allTiles.forEach(function(tile) {
-          var selected = selectedTiles.indexOf(tile) >= 0;
-          tile.highlight.visible = selected;
-        })
-      },
-
-      _getSelectedWells: function () {
-        var that = this; 
-        return this.allSelectedObjects.map(function (tile) {
-          var well = that.engine.derivative[tile.index];
-          if (!well) {
-            well = that.defaultWell; 
-          }
-          return well; 
-        }); 
-      },
-
-      _getCommonFields: function (wells) {
-        if (wells.length) {
-          var referenceWell = wells[0];
-          var referenceFields = $.extend(true, {}, referenceWell);
-          for (var i = 1; i < wells.length; i++) {
-            var fields = wells[i];
-            for (var field in referenceFields) {
-              if (Array.isArray(referenceFields[field])) {
-                var refArr = referenceFields[field]; 
-                var agrArr = []; 
-                for (var j = 0; j < refArr.length; j++) {
-                  var v = refArr[j];
-                  if (v && typeof(v) === "object") {
-                    if (this.containsObject(v, fields[field])) {
-                      agrArr.push(v);
-                    }
-                  } else {
-                    if ($.inArray(v, fields[field]) >= 0) {
-                      agrArr.push(v);
-                    }
-                  }
-                }
-                referenceFields[field] = agrArr; 
-              } else {
-                if (fields[field] && typeof(fields[field]) ==="object" && referenceFields[field] && typeof(referenceFields[field]) ==="object"){
-                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){
-                    delete referenceFields[field];
-                  }
-                } else if (referenceFields[field] != fields[field]) {
-                  delete referenceFields[field];
-                }
-              }
-            }
-          }
-          return referenceFields
-        } else {
-          return {};
-        }
-      },
-
-      containsObject: function(obj, list) {
-        var equality = [];
-        if (list) {
-          list.forEach(function(val) {
-            //evaluate val and obj
-            var evaluate = [];
-            Object.keys(val).forEach(function(listKey){
-              if (Object.keys(obj).indexOf(listKey) >= 0){
-                var curVal = val[listKey];
-                if (typeof(curVal) === 'object' && curVal) {
-                  if (obj[listKey]){
-                    evaluate.push((curVal.unit === obj[listKey].unit) && (curVal.value === obj[listKey].value));
-                  } else {
-                    // when obj[listKey] is null but curVal is not
-                    evaluate.push(false);
-                  }
-                } else {
-                  evaluate.push(curVal === obj[listKey]);
-                }
-              }
-            });
-            equality.push(evaluate.indexOf(false) < 0);
-          });
-          return equality.indexOf(true) >= 0;
-        } else {
-          return false;
-        }
-      },
-
-      _getCommonWell: function (wells) {
-        if (wells.length) {
-          var referenceWell = wells[0];
-          var referenceFields = $.extend(true, {}, referenceWell);
-          for (var i = 1; i < wells.length; i++) {
-            var well = wells[i];
-            var fields = well;
-            for (var field in referenceFields) {
-              if (Array.isArray(referenceFields[field])) {
-                var refArr = referenceFields[field]; 
-                var agrArr = []; 
-                for (var j = 0; j < refArr.length; j++) {
-                  var v = refArr[j];
-                  // for multiplex field
-                  if (typeof(refArr[j]) ==="object"){
-                    if (this.containsObject(v, fields[field])) {
-                      agrArr.push(v);
-                    }
-                  } else {
-                    if ($.inArray(v, fields[field]) >= 0) {
-                      agrArr.push(v);
-                    }
-                  }
-                }
-                referenceFields[field] = agrArr; 
-              } else {
-                if (fields[field] && typeof(fields[field]) ==="object" && referenceFields[field] && typeof(referenceFields[field]) ==="object"){
-                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){
-                    referenceFields[field] = null;
-                  }
-                } else if (referenceFields[field] != fields[field]) {
-                  referenceFields[field] = null;
-                }
-
-              }
-            }
-          }
-          return referenceFields;
-        } else {
-          return this.defaultWell; 
-        }
-      }, 
-
-      _getAllMultipleVal: function (wells) {
-        var multipleFieldList = this.multipleFieldList;
-
-        multipleFieldList.forEach(function(multiplexField) {
-          if(wells.length) {
-            var curMultipleVal = {};
-            wells.forEach(function (wellData) {
-              var id = multiplexField.id;
-              if (wellData[id]){
-                if (wellData[id].length > 0) {
-                  wellData[id].forEach(function (multipleVal) {
-                    if (typeof(multipleVal) === 'object') {
-                      if (multipleVal[id] in curMultipleVal) {
-                        curMultipleVal[multipleVal[id]] ++;
-                      } else {
-                        curMultipleVal[multipleVal[id]] = 1;
-                      }
-                    } else {
-                      if (multipleVal in curMultipleVal) {
-                        curMultipleVal[multipleVal] ++;
-
-                      } else {
-                        curMultipleVal[multipleVal] = 1;
-                      }
-                    }
-                  })
-                }
-              }
-            });
-            multiplexField.allSelectedMultipleVal = curMultipleVal;
-          } else {
-            multiplexField.allSelectedMultipleVal = null
-          }
-        });
-      },
-
-      decideSelectedFields: function() {
-        var wells = this._getSelectedWells();
-        this._getAllMultipleVal(wells);
-        this.applyFieldWarning(wells);
-        var well = this._getCommonWell(wells); 
-        this._addDataToTabFields(well);
-      },
-
-      // get well value differences for each well in wellsHash
-      getDifferentWellsVals: function(wellsHash) {
-        var wells = [];
-        for (var wellId in wellsHash){
-          wells.push(wellsHash[wellId]);
-        }
-        var differentWellsVals = {};
-        if (wells.length > 1){
-          var commonWell = this._getCommonWell(wells);
-          var allFieldVal = {};
-          for (var fieldIdx in wellsHash[0]) {
-            allFieldVal[fieldIdx] = [];
-          }
-          for (var wellIdx in wells){
-            var diffWellVal = {};
-            var curWellData = wells[wellIdx];
-            for (var fieldId in curWellData) {
-              var commonVal = commonWell[fieldId];
-              var curVal = curWellData[fieldId];
-              var newVal = null;
-              if (Array.isArray(curVal)) {
-                // get uncommonVal
-                newVal = [];
-                for (var idx = 0; idx < curVal.length; idx ++){
-                  var curMultiVal = curVal[idx];
-                  // multiplex field
-                  if (curMultiVal && typeof(curMultiVal === "object")){
-                    if (!this.containsObject(curMultiVal, commonVal)) {
-                      newVal.push(curMultiVal);
-                      if (!this.containsObject(curMultiVal, allFieldVal[fieldId])) {
-                        allFieldVal[fieldId].push(curMultiVal);
-                      }
-                    }
-                  } else {
-                    if (commonVal.indexOf(curMultiVal) >= 0) {
-                      newVal.push(curMultiVal);
-                      if (!allFieldVal[fieldId].indexOf(curMultiVal) >= 0) {
-                        allFieldVal[fieldId].push(curMultiVal);
-                      }
-                    }
-                  }
-                }
-              } else if (curVal && typeof(curVal) === "object"){
-                if (commonVal && typeof(commonVal) ==="object"){
-                  if (!((curVal.value === commonVal.value) || (curVal.unit === commonVal.unit))){
-                    newVal = curVal;
-                    if (!this.containsObject(curVal, allFieldVal[fieldId])) {
-                      allFieldVal[fieldId].push(curVal);
-                    }
-                  }
-                } else {
-                  newVal = curVal;
-                  if (!this.containsObject(curVal, allFieldVal[fieldId])) {
-                    allFieldVal[fieldId].push(curVal);
-                  }
-                }
-              } else if (curVal !== commonVal) {
-                newVal = curVal;
-                if (!allFieldVal[fieldId].indexOf(curVal) >= 0) {
-                  allFieldVal[fieldId].push(curVal);
-                }
-              }
-              diffWellVal[fieldId] = newVal;
-            }
-
-
-            differentWellsVals[wellIdx] = diffWellVal;
-          }
-
-          // clean up step for fields that are empty
-          for (var fieldId in allFieldVal) {
-            if (allFieldVal[fieldId].length === 0) {
-              for (var wellIdx in differentWellsVals){
-                delete differentWellsVals[wellIdx][fieldId];
-              }
-            }
-          }
-
-          return differentWellsVals;
-        } else if (wellsHash[0]) {
-          var well = {};
-          for (var fieldId in wellsHash[0]) {
-            var curVal = wellsHash[0][fieldId];
-            if (Array.isArray(curVal)){
-              if (curVal.length > 0) {
-                well[fieldId] = curVal
-              }
-            } else if (curVal){
-              well[fieldId] = curVal;
-            }
-          }
-          return {
-            0: well
-          };
-        }
-      },
-
-      // get all wells that has data
-      getWellSetAddressWithData: function(){
-        var address = [];
-        var derivative = this.engine.derivative;
-        for (var id in derivative){
-          address.push(this.indexToAddress(id));
-        }
-        return address;
-      }
-
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-plateLayOutWidget.assets = function () {
-    return {
-        _assets: {
-            doImg: '&#10003;',
-            dontImg: '',
-            warningImg: '&#9888;'
-        }
-    };
-};
-
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.interface = function() {
-    // interface holds all the methods to put the interface in place
-    return {
-
-      _createInterface: function() {
-
-        var divIdentifier = '<div></div>';
-        this.container = this._createElement(divIdentifier).addClass("plate-setup-wrapper");
-        this.topSection = this._createElement(divIdentifier).addClass("plate-setup-top-section");
-
-        this.topLeft = this._createElement(divIdentifier).addClass("plate-setup-top-left");
-        this.topRight = this._createElement(divIdentifier).addClass("plate-setup-top-right");
-
-        this.overLayContainer = this._createElement(divIdentifier).addClass("plate-setup-overlay-container");
-        this.canvasContainer = this._createElement(divIdentifier).addClass("plate-setup-canvas-container");
-
-        this._createOverLay();
-        $(this.topLeft).append(this.overLayContainer);
-
-        this._createCanvas();
-        $(this.topLeft).append(this.canvasContainer);
-
-
-        $(this.topSection).append(this.topLeft);
-        $(this.topSection).append(this.topRight);
-
-        $(this.container).append(this.topSection);
-        $(this.element).append(this.container);
-
-        this._initiateFabricCanvas();
-
-        this._createTabAtRight();
-        this._createTabs();
-
-        this._placePresetTabs();
-        // Bottom of the screen
-        this._bottomScreen();
-        // Canvas
-        this._canvas();
-
-        this.bottomForFirstTime();
-
-        var that = this;
-        this._setShortcuts();
-        $(document.body).keyup(function(e) {
-          that._handleShortcuts(e);
-        });
-
-        this._configureUndoRedoArray();
-      },
-
-      _createElement: function(element) {
-        return $(element);
-      },
-
-      _setShortcuts: function () {
-        var that = this; 
-        window.addEventListener("cut", function (e) {
-          if (document.activeElement == document.body) {
-            that.copyCriteria();
-            that.clearCriteria();
-            e.preventDefault();
-          }
-        });
-        window.addEventListener("copy", function (e) {
-          if (document.activeElement == document.body) {
-            that.copyCriteria();
-            e.preventDefault();
-          }
-        });
-        window.addEventListener("paste", function (e) {
-          if (document.activeElement == document.body) {
-            that.pasteCriteria();
-            e.preventDefault();
-          }
-        });
-      },
-
-      _handleShortcuts: function(e) {
-        if (document.activeElement === document.body) {
-          if (e.keyCode == 46) {
-            this.clearCriteria();
-            e.preventDefault();
-          } else if (e.ctrlKey || e.metaKey) {
-            if (e.keyCode == 90) {
-              if (e.shiftKey) {
-                this.redo();
-              } else {
-                this.undo();
-              }
-              e.preventDefault();
-            } else if (e.keyCode == 89) {
-              this.redo();
-              e.preventDefault();
-            }
-          }
-        }
-      },
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.loadPlate = function(THIS) {
-    // Methods which look after data changes and stack up accordingly
-    // Remember THIS points to plateLayOutWidget and 'this' points to engine
-    return {
-
-      getPlates: function (data) {
-        //sanitize input
-        var derivative = {}; 
-        for (var index in data.derivative) {
-          var well = data.derivative[index]; 
-          derivative[index] = this.sanitizeWell(well); 
-        }
-
-        var checkboxes = data.checkboxes || []; 
-        var selection = this.sanitizeAreas(data.selectedAreas, data.focalWell); 
-
-        var sanitized = {
-          "derivative": derivative,
-          "checkboxes": checkboxes,
-          "selectedAreas": selection.selectedAreas,
-          "focalWell": selection.focalWell
-        }; 
-
-        this.setData(sanitized);
-      }, 
-
-      sanitizeAreas: function (selectedAreas, focalWell) {
-        var that = this; 
-        var rows = this.dimensions.rows;
-        var cols = this.dimensions.cols;
-
-        if (!selectedAreas) {
-          selectedAreas = [];
-        }
-        if (selectedAreas.length) {
-          selectedAreas = selectedAreas.map(function (area) {
-            return {
-              minCol: that._coordIndex(Math.min(area.minCol, area.maxCol), cols), 
-              minRow: that._coordIndex(Math.min(area.minRow, area.maxRow), rows), 
-              maxCol: that._coordIndex(Math.max(area.minCol, area.maxCol), cols), 
-              maxRow: that._coordIndex(Math.max(area.minRow, area.maxRow), rows)
-            }; 
-          }); 
-          var area = selectedAreas[selectedAreas.length - 1];
-          if (focalWell && !this._wellInArea(focalWell, area)) {
-            focalWell = null;
-          }
-          if (!focalWell) {
-            focalWell = {
-              row: area.minRow,
-              col: area.minCol
-            };
-          }
-        } else {
-          if (!focalWell) {
-            focalWell = {
-              row: 0,
-              col: 0
-            };
-          }
-          selectedAreas = [this._wellToArea(focalWell)];
-        }
-        return {
-          selectedAreas: selectedAreas, 
-          focalWell: focalWell
-        };
-      }, 
-
-      sanitizeWell: function (well) {
-        var newWell = {};
-        for (var i = 0; i < this.fieldList.length; i++) {
-          var field = this.fieldList[i];
-          newWell[field.id] = field.parseValue(well[field.id]);
-        }
-        return newWell; 
-      }, 
-
-      setData: function(data) {
-        this.engine.derivative = $.extend(true, {}, data.derivative);
-        this.setCheckboxes(data.checkboxes);
-        this.setSelection(data.selectedAreas, data.focalWell);
-        this._colorMixer();
-        this.decideSelectedFields();
-        this.mainFabricCanvas.renderAll();
-      },
-
-    }
-  }
-})(jQuery, fabric);
-var GET_PLATES = 'getPlates';
-var IS_READ_ONLY = 'isReadOnly';
-var IS_DISABLE_ADD_DELETE_WELL = 'isDisableAddDeleteWell';
-var GET_SELECTED_OBJECT = 'getSelectedObject';
-var SETSELECTEDWELL = 'setSelectedWell';
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.overlay = function() {
-    // overlay holds all the methods to put the part just above the canvas which contains all those
-    // 'completion percentage' annd 'copy Criteria' button etc ...
-    return {
-
-      _createOverLay: function() {
-
-        var that = this;
-        this.overLayTextContainer = this._createElement("<div></div>").addClass("plate-setup-overlay-text-container");
-        this.overLayTextContainer.text("Completion Percentage:");
-        this.overLayContainer.append(this.overLayTextContainer);
-        this.overLayButtonContainer = this._createElement("<div></div>").addClass("plate-setup-overlay-button-container");
-        this.overLayContainer.append(this.overLayButtonContainer);
-
-        this.clearCriteriaButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.clearCriteriaButton.text("Clear");
-        this.overLayButtonContainer.append(this.clearCriteriaButton);
-
-        this.clearCriteriaButton.click(function(evt) {
-          that.clearCriteria();
-        });
-
-        this.copyCriteriaButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.copyCriteriaButton.text("Copy");
-        this.overLayButtonContainer.append(this.copyCriteriaButton);
-
-        this.copyCriteriaButton.click(function(evt) {
-          that.copyCriteria();
-        });
-
-        this.pasteCriteriaButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.pasteCriteriaButton.text("Paste");
-        this.overLayButtonContainer.append(this.pasteCriteriaButton);
-
-        this.pasteCriteriaButton.click(function(evt) {
-          that.pasteCriteria();
-        });
-
-        this.undoButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.undoButton.text("Undo");
-        this.overLayButtonContainer.append(this.undoButton);
-
-        this.undoButton.click(function(evt) {
-          that.undo();
-        });
-
-        this.redoButton = this._createElement("<button />").addClass("plate-setup-button");
-        this.redoButton.text("Redo");
-        this.overLayButtonContainer.append(this.redoButton);
-
-        this.redoButton.click(function(evt) {
-          that.redo();
-        });
-
-      },
-
-      clearCriteria: function() {
-        if (this.allSelectedObjects) {
-          var noOfSelectedObjects = this.allSelectedObjects.length;
-          var hasWellUpdate = false;
-          for (var objectIndex = 0; objectIndex < noOfSelectedObjects; objectIndex++) {
-            var tile = this.allSelectedObjects[objectIndex];
-            if (tile.index in this.engine.derivative) {
-              // handling for clearing well when not allowed to add or delete wells
-              if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {
-                var well = JSON.parse(JSON.stringify(this.defaultWell));
-                var defaultValue = this.emptyWellWithDefaultVal;
-                for (var key in defaultValue){
-                  if (key in well) {
-                    well[key] = defaultValue[key];
-                    this._applyFieldData(key, defaultValue[key]);
-                  } else {
-                    console.log("Well does not contain key: " + key + ", please contact support");
-                  }
-                }
-                this.engine.derivative[tile.index] = well;
-              } else {
-                delete this.engine.derivative[tile.index];
-              }
-              hasWellUpdate = true;
-            }
-          }
-          if (hasWellUpdate){
-            this.derivativeChange();
-          }
-
-          this._colorMixer();
-          this.decideSelectedFields();
-        } else {
-          alert("Please select any well");
-        }
-      },
-
-      copyCriteria: function() {
-        if (this.allSelectedObjects) {
-          var wells = this._getSelectedWells(); 
-          this.commonWell = this._getCommonFields(wells); 
-        } else {
-          alert("Please select any well.");
-        }
-      },
-
-      pasteCriteria: function() {
-        if (this.commonWell) {
-          this._addAllData(this.commonWell);
-          this.decideSelectedFields();
-          this.mainFabricCanvas.renderAll();
-        }
-      }
-    };
-  }
-})(jQuery, fabric);
-$.widget("DNA.plateLayOut", {
-
-  plateLayOutWidget: {},
-
-  options: {
-    value: 0
-  },
-
-  allTiles: [], // All tiles containes all thise circles in the canvas
-
-  addressToLoc: function (layoutAddress) {
-    var m = /^([A-Z]+)(\d+)$/.exec(layoutAddress.trim().toUpperCase())
-    if (m) {
-      var row_v = m[1]; 
-      var col = parseInt(m[2])-1;
-      var row; 
-      for (var i = 0; i < row_v.length; i++) {
-        var c = row_v.charCodeAt(i) - 65; 
-        if (i) {
-            row += 1;
-            row *= 26; 
-            row += c ; 
-        } else {
-            row = c;
-        }
-      }
-      return {
-        r: row, 
-        c: col
-      };
-    } else {
-      throw layoutAddress + " not a proper layout address"; 
-    }
-  },
-
-  locToIndex: function (loc, dimensions) {
-    if (!dimensions) {
-      dimensions = this.dimensions;
-    }
-    if (loc.r < 0) {
-      t
-    }
-    if (!(loc.r >= 0 && loc.r < dimensions.rows)) {
-      throw "Row index " + (loc.r + 1) + " invalid"; 
-    }
-    if (!(loc.c >= 0 && loc.c < dimensions.cols)) {
-      throw "Column index " + (loc.c + 1) + " invalid"; 
-    }
-    return loc.r*dimensions.cols + loc.c; 
-  },
-
-  addressToIndex: function (layoutAddress, dimensions) {
-    var loc = this.addressToLoc(layoutAddress); 
-    return this.locToIndex(loc, dimensions); 
-  }, 
-
-  _rowKey: function (i) {
-    var c1 = i % 26;
-    var c2 = (i - c1) / 26;
-    var code = String.fromCharCode(65 + c1);
-    if (c2 > 0) {
-      code = String.fromCharCode(64 + c2) + code;
-    }
-    return code;
-  }, 
-
-  indexToLoc: function (index, dimensions) {
-    if (!dimensions) {
-      dimensions = this.dimensions;
-    }
-
-    if (index >= dimensions.rows * dimensions.cols) {
-      throw "Index too high: " + index.toString(10); 
-    }
-    var loc = {}; 
-    loc.c = index % dimensions.cols;
-    loc.r = (index - loc.c) / dimensions.cols;
-
-    return loc; 
-  },
-
-  locToAddress: function (loc) {
-    return this._rowKey(loc.r) + (loc.c + 1).toString(10);
-  },
-
-  indexToAddress: function (index, dimensions) {
-    var loc = this.indexToLoc(index, dimensions); 
-    return this.locToAddress(loc); 
-  },
-
-  getDimensions: function () {
-    return $.extend(true, {}, this.dimensions);
-  },
-
-  _create: function() {
-    var rows = parseInt(this.options.numRows || 8);
-    var cols = parseInt(this.options.numCols || 12);
-    this.dimensions = {
-      rows: rows,
-      cols: cols
-    };
-    this.rowIndex = [];
-    for (var i = 0; i < rows; i++) {
-      this.rowIndex.push(this._rowKey(i));
-    }
-
-    this.target = (this.element[0].id) ? "#" + this.element[0].id : "." + this.element[0].className;
-
-    // Import classes from other files.. Here we import it using extend and add it to this
-    // object. internally we add to widget.DNA.getPlates.prototype.
-    // Helpers are methods which return other methods and objects.
-    // add Objects to plateLayOutWidget and it will be added to this object.
-    // set read only well
-    if (this.options.readOnly){
-      this.isReadOnly(true);
-    }
-
-    for (var component in plateLayOutWidget) {
-      // Incase some properties has to initialize with data from options hash,
-      // we provide it sending this object.
-      $.extend(this, new plateLayOutWidget[component](this));
-    }
-
-    this.imgSrc = this.options.imgSrc || "assets";
-
-    this._createInterface();
-
-    this._trigger("created", null, this);
-
-    return this;
-  },
-
-  _init: function() {
-    // This is invoked when the user use the plugin after _create is called.
-    // The point is _create is invoked for the very first time and for all other
-    // times _init is used.
-  },
-
-  addData: function() {
-    alert("wow this is good");
-  },
-
-  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
-  getTextDerivative: function(wellsData) {
-    var textDerivative = {};
-    var fieldMap = this.fieldMap;
-    for (var idx in wellsData){
-      var textValWell = {};
-      var textFieldIdWell = {};
-      var curWellData = wellsData[idx];
-      for (var fieldId in curWellData){
-        if (fieldId in this.fieldMap){
-          var field = this.fieldMap[fieldId];
-          var textVal = field.parseText(curWellData[fieldId]);
-          textFieldIdWell[field.name] = textVal;
-          textValWell[fieldId] = textVal;
-        } else {
-          // do not convert if not a field (ex: layout_address)
-          textFieldIdWell[fieldId] = curWellData[fieldId];
-          textValWell[fieldId] = curWellData[fieldId];
-        }
-      }
-      textDerivative[idx] = {
-        textVal: textValWell,
-        textFieldVal: textFieldIdWell
-      };
-    }
-
-    return textDerivative;
-  },
-
-  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
-  getWellsDifferences: function(wellsData) {
-    return this.getDifferentWellsVals(wellsData);
-  },
-
-  setFieldsDisabled: function(flag){
-    this.fieldList.forEach(function(field){
-      field.disabled(flag);
-    });
-  },
-
-  isReadOnly: function(flag){
-    if (flag){
-      this.readOnly = true;
-    } else {
-      this.readOnly = false;
-    }
-    this.readOnlyHandler();
-  },
-
-  readOnlyHandler: function(){
-    if (this.readOnly){
-      this.overLayButtonContainer.css("display", "none");
-      $('.multiple-field-manage-delete-button').css("display", "none");
-      this.setFieldsDisabled(true);
-    } else {
-      this.overLayButtonContainer.css("display", "flex");
-      $('.multiple-field-manage-delete-button').css("display", "none");
-      if (!this.disableAddDeleteWell) {
-        this.setFieldsDisabled(false);
-      }
-    }
-  },
-
-  disableAddDeleteWell: null,
-  // column_with_default_val will be used to determine empty wells, format: {field_name: default_val}
-  isDisableAddDeleteWell: function(flag, column_with_default_val){
-    if (flag){
-      this.disableAddDeleteWell = true;
-      this.addressAllowToEdit = this.getWellSetAddressWithData();
-      // configure undo redo action
-      this.actionPointer = 0;
-      this.undoRedoArray = [];
-      this.undoRedoArray.push(this.createObject());
-      if (column_with_default_val) {
-        this.emptyWellWithDefaultVal = column_with_default_val;
-      }
-    } else {
-      this.disableAddDeleteWell = false;
-      this.setFieldsDisabled(false);
-      this.emptyWellWithDefaultVal = null;
-    }
-    this._fabricEvents();
-  },
-
-  getSelectedObject: function() {
-    var selectedAddress = [];
-    for (var i = 0; i < this.allSelectedObjects.length; i++){
-      selectedAddress.push(this.allSelectedObjects[i].address);
-    }
-    var selectedObjects = {};
-    var derivative = this.engine.derivative;
-    for (var loc in derivative){
-      var address = this.indexToAddress(loc);
-      if (selectedAddress.indexOf(address) >= 0) {
-        selectedObjects[address] = derivative[loc];
-      }
-    }
-    return selectedObjects;
-  },
-
-  getSelectedIndex: function() {
-    return this.allSelectedObjects.map(function(selectedObj){
-        return that.addressToIndex(selectedObj.address)
-    });
-  },
-
-  getSelectedAddress: function() {
-    return this.allSelectedObjects.map(function(selectedObj){
-      return selectedObj.address;
-    });
-  },
-
-  setSelectedWell: function(addressList) {
-    var areas = [];
-    var minRow = 999;
-    var locMap = {};
-    for (var id = 0; id < addressList.length; id++){
-      var wellIdx = this.addressToIndex(addressList[id]);
-      var loc = this.indexToLoc(wellIdx);
-      areas.push({
-        minCol: loc.c,
-        minRow: loc.r,
-        maxCol: loc.c,
-        maxRow: loc.r
-      });
-      if (loc.r <= minRow) {
-        minRow = loc.r;
-        if (loc.r in locMap) {
-          locMap[loc.r].push(loc.c);
-        } else {
-          locMap[loc.r] = [loc.c];
-        }
-      }
-    }
-    var focalWell = {
-      row: minRow,
-      col: Math.min.apply(null, locMap[minRow])
-    };
-
-    this.setSelection(areas, focalWell);
-    this.decideSelectedFields();
-    this.mainFabricCanvas.renderAll();
-  }
-
-});
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.preset = function(me) {
-    // All the preset action goes here
-    return {
-
-      presets: [],
-
-      _placePresetTabs: function() {
-        var presets = this.options.attributes.presets;
-
-        if (presets && presets.length) {
-          this.wellAttrContainer = this._createElement("<div></div>").addClass("plate-setup-well-attr-container")
-            .text("Checkbox presets");
-          this.tabContainer.append(this.wellAttrContainer);
-
-          this.presetTabContainer = this._createElement("<div></div>").addClass("plate-setup-preset-container");
-          this.tabContainer.append(this.presetTabContainer);
-
-          for (var i = 0; i < presets.length; i++) {
-            var preset = presets[i];
-            var divText = this._createElement("<div></div>").addClass("plate-setup-prest-tab-div")
-              .text(preset.title);
-
-            var presetButton = this._createElement("<div></div>").addClass("plate-setup-prest-tab")
-              .data("preset", preset.fields).append(divText);
-            this.presetTabContainer.append(presetButton);
-
-            var that = this;
-            presetButton.click(function() {
-              var preset = $(this);
-              that._selectPreset(preset);
-            });
-            this.presets.push(presetButton);
-          }
-        }
-      },
-
-      _clearPresetSelection: function() {
-        for (var j = 0; j < this.presets.length; j++) {
-          var p = this.presets[j]; 
-          p.removeClass("plate-setup-prest-tab-selected")
-            .addClass("plate-setup-prest-tab"); 
-        }
-      },
-
-      _selectPreset: function (preset) {
-        this.setCheckboxes(preset.data("preset")); 
-        preset.removeClass("plate-setup-prest-tab")
-          .addClass("plate-setup-prest-tab-selected");
-      },
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.tabs = function() {
-    // Tabs crete and manage tabs at the right side of the canvas.
-    return {
-
-      allTabs: [],
-
-      defaultWell: {},
-
-      allDataTabs: [], // To hold all the tab contents. this contains all the tabs and its elements and elements
-      // Settings as a whole. its very usefull, when we have units for a specific field.
-      // it goes like tabs-> individual field-> units and checkbox
-
-      _createTabAtRight: function() {
-        this.tabContainer = this._createElement("<div></div>").addClass("plate-setup-tab-container");
-        $(this.topRight).append(this.tabContainer);
-      },
-
-      _createTabs: function() {
-        // this could be done using z-index. just imagine few cards stacked up.
-        // Check if options has tab data.
-        // Originally we will be pulling tab data from developer.
-        // Now we are building upon dummy data.
-        this.tabHead = this._createElement("<div></div>").addClass("plate-setup-tab-head");
-        $(this.tabContainer).append(this.tabHead);
-
-        var tabData = this.options.attributes.tabs;
-        var that = this;
-
-        tabData.forEach(function (tab, tabIndex) {
-          that.allTabs[tabIndex] = that._createElement("<div></div>").addClass("plate-setup-tab");
-          $(that.allTabs[tabIndex]).data("index", tabIndex)
-            .text(tab.name);
-
-          $(that.allTabs[tabIndex]).click(function() {
-            that._tabClickHandler(this);
-          });
-
-          $(that.tabHead).append(that.allTabs[tabIndex]);
-        }); 
-
-        this.tabDataContainer = this._createElement("<div></div>").addClass("plate-setup-tab-data-container");
-        $(this.tabContainer).append(this.tabDataContainer);
-
-        this._addDataTabs(tabData);
-
-        $(this.allTabs[0]).click();
-
-        this._addTabData();
-      },
-
-      _tabClickHandler: function(clickedTab) {
-
-        if (this.selectedTab) {
-          $(this.selectedTab).removeClass("plate-setup-tab-selected")
-            .addClass("plate-setup-tab");
-
-          var previouslyClickedTabIndex = $(this.selectedTab).data("index");
-          $(this.allDataTabs[previouslyClickedTabIndex]).css("z-index", 0);
-          this.readOnlyHandler();
-        }
-
-        $(clickedTab).addClass("plate-setup-tab-selected");
-
-        this.selectedTab = clickedTab;
-
-        var clickedTabIndex = $(clickedTab).data("index");
-        $(this.allDataTabs[clickedTabIndex]).css("z-index", 1000);
-      },
-
-      _addDataTabs: function(tabs) {
-
-        var tabIndex = 0;
-
-        for (var tabData in tabs) {
-          this.allDataTabs[tabIndex++] = this._createElement("<div></div>").addClass("plate-setup-data-div")
-            .css("z-index", 0);
-          $(this.tabDataContainer).append(this.allDataTabs[tabIndex - 1]);
-        }
-      }
-    };
-  }
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.undoRedoManager = function(THIS) {
-
-    return {
-
-      undoRedoArray: [],
-
-      actionPointer: null,
-
-      addToUndoRedo: function(data) {
-
-        if (this.actionPointer != null) {
-          var i = this.actionPointer + 1; 
-          if (i < this.undoRedoArray.length) {
-            this.undoRedoArray.splice(i, this.undoRedoArray.length - i);
-          }
-        }
-        this.actionPointer = null;
-        this.undoRedoArray.push($.extend(true, {}, data));
-      },
-
-      _configureUndoRedoArray: function() {
-
-        var data = {
-          checkboxes: [],
-          derivative: {},
-          selectedAreas: [{
-            minRow: 0,
-            minCol: 0,
-            maxRow: 0,
-            maxCol: 0
-          }],
-          focalWell: {
-            row: 0,
-            col: 0
-          }
-        };
-
-        this.undoRedoArray = []; 
-        this.actionPointer = null; 
-        this.undoRedoArray.push($.extend({}, data));
-      },
-
-      undo: function() {
-        console.log("undo");
-        return this.shiftUndoRedo(-1); 
-      },
-
-      redo: function() {
-        console.log("redo");
-        return this.shiftUndoRedo(1); 
-      }, 
-
-      shiftUndoRedo: function (pointerDiff) {
-        var pointer = this.actionPointer;
-        if (pointer == null) {
-          pointer = this.undoRedoArray.length - 1; 
-        }
-        pointer += pointerDiff; 
-        return this.setUndoRedo(pointer); 
-      }, 
-
-      setUndoRedo: function (pointer) {
-        if (pointer < 0) {
-          return false; 
-        }
-        if (pointer >= this.undoRedoArray.length) {
-          return false; 
-        }
-        this.undoRedoActive = true; 
-        this.setData(this.undoRedoArray[pointer]);
-        this.actionPointer = pointer; 
-        this.undoRedoActive = false;
-        this.derivativeChange();
-        return true;
-      }
-    }
-  };
-
-})(jQuery, fabric);
-var plateLayOutWidget = plateLayOutWidget || {};
-
-(function($, fabric) {
-
-  plateLayOutWidget.wellArea = function(fabric) {
-
-    return {
-
-      _areasToTiles: function(areas) {
-        //Convert areas to tiles
-        var cols = this.dimensions.cols;
-        var that = this;
-        return areas.reduce(function(tiles, area) {
-          if (area) {
-            for (var r = area.minRow; r <= area.maxRow; r++) {
-              for (var c = area.minCol; c <= area.maxCol; c++) {
-                var tile = that.allTiles[c + cols * r];
-                if (tiles.indexOf(tile) < 0) {
-                  if (that.disableAddDeleteWell){
-                    if(that.addressAllowToEdit.indexOf(tile.address) >= 0){
-                      tiles.push(tile);
-                    }
-                  } else {
-                    tiles.push(tile);
-                  }
-                }
-              }
-            }
-          }
-          return tiles;
-        }, []);
-      },
-
-      _encodeArea: function(area) {
-        //Encode area as string
-        if ((area.minRow == area.maxRow) && (area.minCol == area.maxCol)) {
-          return this.rowIndex[area.minRow] + area.minCol.toString(10);
-        } else {
-          return this.rowIndex[area.minRow] + area.minCol.toString(10) + ":" + this.rowIndex[area.maxRow] + area.maxCol.toString(10);
-        }
-      },
-
-      _encodeAreas: function(areas) {
-        //Encode an array of areas as a string
-        var that = this;
-        return areas.map(function(area) {
-          return that._encodeArea(area);
-        }).join(",");
-      },
-
-      _decodeWell: function(wellAddress) {
-        var that = this;
-        var adRx = new RegExp("^\\s*(" + that.rowIndex.join("|") + ")(\\d+)\\s*$")
-        var rcRx = /^\s*R(\d+)C(\d+)\s*$/i;
-
-        var match;
-        match = wellAddress.match(adRx);
-        if (match) {
-          var row = that.rowIndex.indexOf(match[1]);
-          if (row >= 0) {
-            return {
-              row: row,
-              col: parseInt(match[2]) - 1
-            };
-          }
-        }
-        match = wellAddress.match(rcRx);
-        if (match) {
-          return {
-            row: parseInt(match[1]) - 1,
-            col: parseInt(match[2]) - 1
-          };
-        }
-
-        throw "Invalid well address: " + wellAddress;
-      },
-
-      _decodeArea: function(areaAddress) {
-        //Decode single area as string
-        var that = this;
-        var wells = areaAddress.split(":").map(function(wellAddress) {
-          return that._decodeWell(wellAddress);
-        })
-        if (wells.length == 1) {
-          return {
-            minRow: wells[0].row,
-            minCol: wells[0].col,
-            maxRow: wells[0].row,
-            maxCol: wells[0].col
-          }
-        } else if (wells.length == 2) {
-          var minRow = Math.min(wells[0].row, wells[1].row)
-          return {
-            minRow: Math.min(wells[0].row, wells[1].row),
-            minCol: Math.min(wells[0].col, wells[1].col),
-            maxRow: Math.max(wells[0].row, wells[1].row),
-            maxCol: Math.max(wells[0].col, wells[1].col)
-          }
-        } else {
-          throw "Invalid address: " + areaAddress;
-        }
-      },
-
-      _decodeAreas: function(areasAddress) {
-        //Decode single area as string
-        var that = this;
-        return areasAddress.split(",").map(function(areaAddress) {
-          return that._decodeArea(areaAddress);
-        });
-      },
-
-      _wellToArea: function(well) {
-        //Convert a well to an area
-        return {
-          minCol: well.col,
-          minRow: well.row,
-          maxCol: well.col,
-          maxRow: well.row
-        }
-      },
-
-      _wellInArea: function(well, area) {
-        //Determine if a well lies within an area
-        return well.row >= area.minRow && well.row <= area.maxRow && well.col >= area.minCol && well.col <= area.maxCol;
-      },
-
-      _coordsToRect: function(startCoords, endCoords) {
-        //Convert two XY coords to a bounding box
-        var left = Math.min(startCoords.x, endCoords.x);
-        var top = Math.min(startCoords.y, endCoords.y);
-        var height = Math.abs(endCoords.y - startCoords.y);
-        var width = Math.abs(endCoords.x - startCoords.x);
-        return {
-          top: top,
-          left: left,
-          height: height,
-          width: width
-        };
-      },
-
-      _coordIndex: function(v, count) {
-        var i;
-        if (v < 0) {
-          i = 0;
-        } else if (v >= count) {
-          i = count - 1;
-        } else {
-          i = Math.floor(v);
-        }
-        return i;
-      },
-
-      _coordsToWell: function(coord) {
-        //Convert a coordinate to a well
-        var cols = this.dimensions.cols;
-        var rows = this.dimensions.rows;
-
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
-
-        var x = (coord.x - m) / w;
-        var y = (coord.y - m) / w;
-
-        var row = this._coordIndex(y, rows);
-        var col = this._coordIndex(x, cols);
-
-        return {
-          row: row,
-          col: col,
-        };
-      },
-
-      _wellToCoords: function(well, center) {
-        //Convert a well to a coordinate
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
-        var x = well.col * w + m;
-        var y = well.row * w + m;
-        if (center) {
-          var hw = w/2;
-          x = x + hw;
-          y = y + hw;
-        }
-
-        return {
-          x: x,
-          y: y
-        };
-      },
-
-      _areaToRect: function(area) {
-        //Convert area to rectangle
-        var rows = area.maxRow - area.minRow + 1;
-        var cols = area.maxCol - area.minCol + 1;
-
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
-
-        return {
-          top: area.minRow * w + m,
-          left: area.minCol * w + m,
-          height: rows * w,
-          width: cols * w
-        }
-      },
-
-      _rectToArea: function(rect) {
-        //Convert a rectangular region to an area
-        var rows = this.dimensions.rows;
-        var cols = this.dimensions.cols;
-
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
-
-        var left = (rect.left - m) / w;
-        var top = (rect.top - m) / w;
-        var height = rect.height / w;
-        var width = rect.width / w;
-        var right = left + width;
-        var bottom = top + height;
-
-        //select whole row
-        if (right < 0) {
-          right = cols;
-        }
-        if (left >= cols) {
-          left = 0;
-        }
-        //select whole col
-        if (bottom < 0) {
-          bottom = rows;
-        }
-        if (top <= 0) {
-          top = 0;
-        }
-
-        return {
-          minCol: this._coordIndex(left, cols),
-          minRow: this._coordIndex(top, rows),
-          maxCol: this._coordIndex(right, cols),
-          maxRow: this._coordIndex(bottom, rows)
-        };
-      }
-
-    }
-  }
-})(jQuery, fabric);
\ No newline at end of file
diff --git a/dist/js/plate-map.min.js b/dist/js/plate-map.min.js
deleted file mode 100755
index e20d70f..0000000
--- a/dist/js/plate-map.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-var plateLayOutWidget=plateLayOutWidget||{};!function(u,e){plateLayOutWidget.addDataOnChange=function(){return{_addAllData:function(e){if(this.allSelectedObjects)for(var t=this.allSelectedObjects.length,i=[],a=0;a<t;a++){var n,l=this.allSelectedObjects[a];l.index in this.engine.derivative?n=this.engine.derivative[l.index]:(n=u.extend(!0,{},this.defaultWell),this.engine.derivative[l.index]=n);var s=this.processWellData(e,n,t,i);if(i=s.wells,n=s.well,this.engine.wellEmpty(n))if(this.emptyWellWithDefaultVal&&this.disableAddDeleteWell){var r=JSON.parse(JSON.stringify(n)),o=this.emptyWellWithDefaultVal;for(var d in o)d in r&&(r[d]=o[d],this._applyFieldData(d,o[d]));this.engine.derivative[l.index]=r}else delete this.engine.derivative[l.index]}this._getAllMultipleVal(i),this.applyFieldWarning(i),this._colorMixer(),this.derivativeChange()},processWellData:function(e,t,i,a){for(var n in a||(a=[]),e){var l;if(void 0!==e[n]&&null!==e[n])if(e[n].multi){var s=e[n],r=t[n],o=this._getMultiData(r,s,n,i);l=JSON.parse(JSON.stringify(o))}else l=JSON.parse(JSON.stringify(e[n]));else l=JSON.parse(JSON.stringify(e[n]));t[n]=l,a.push(t)}return{well:t,wells:a}},_getMultiData:function(e,t,i,a){var n=t.added,l=t.removed;if(n)if(e)if(n.value){var s=!0;for(var r in e){e[r][i].toString()===n.id.toString()&&(s=!1,e=e.map(function(e){if(e[i].toString()===n.id.toString())for(var t in e)t in n.value&&t!==i&&(1===a?e[t]=n.value[t]:n.value[t]&&(e[t]=n.value[t]));return e}))}s&&e.push(n.value)}else e.indexOf(n)<0&&e.push(n);else e=[],n.value?e.push(n.value):n&&e.push(n);var o,d=function(e,t){var i=[];for(var a in e)parseInt(a)!==parseInt(t)&&i.push(e[a]);return i};if(l)if(l.value){for(var r in e){e[r][i].toString()===l.id.toString()&&(o=r)}e=d(e,o)}else e&&0<=(o=e.indexOf(l))&&(e=d(e,o));return e&&0==e.length&&(e=null),e},_colorMixer:function(){if(!this.undoRedoActive){var e=this.createObject();this.addToUndoRedo(e)}this.engine.searchAndStack(),this.engine.applyColors(),this.mainFabricCanvas.renderAll()},derivativeChange:function(){this._trigger("updateWells",null,this.createObject())},createObject:function(){return{derivative:u.extend(!0,{},this.engine.derivative),checkboxes:this.globalSelectedAttributes.slice(),selectedAreas:this.selectedAreas.slice(),focalWell:this.focalWell,requiredField:this.requiredField}}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};jQuery,fabric,plateLayOutWidget.addDataToFields=function(){return{_addDataToTabFields:function(e){for(var t in e)this._applyFieldData(t,e[t])},_applyFieldData:function(e,t){this.fieldMap[e].setValue(t)}}};plateLayOutWidget=plateLayOutWidget||{};!function(u,e){plateLayOutWidget.addTabData=function(){return{fieldList:[],fieldMap:{},autoId:1,_addTabData:function(){var e=this.options.attributes.tabs,r=this;this.requiredField=[];var o=[];e.forEach(function(e,t){if(e.fields){var i=e.fields,a=[];for(var n in i){var l,s=i[n];s.id||(s.id="Auto"+r.autoId++,console.log("Field autoassigned id "+s.id)),s.type||(s.type="text",console.log("Field "+s.id+" autoassigned type "+s.type)),"multiplex"===s.type?(l=r._makeMultiplexField(s,t,a),o.push(l)):(l=r._makeRegularField(s,t,a,!0),"multiselect"===s.type&&o.push(l))}r.allDataTabs[t].fields=a}else console.log("unknown format in field initialization")}),r.multipleFieldList=o},_makeSubField:function(e,t,i){var a=this;e.id||(e.id="Auto"+a.autoId++,console.log("Field autoassigned id "+e.id)),e.type||(e.type="text",console.log("Field "+e.id+" autoassigned type "+e.type));var n=a._createElement("<div></div>").addClass("plate-setup-tab-default-field"),l=a._createElement("<div></div>").addClass("plate-setup-tab-field-left-side"),s=a._createElement("<div></div>").addClass("plate-setup-tab-field-right-side"),r=a._createElement("<div></div>").addClass("plate-setup-tab-name").text(e.name),o=a._createElement("<div></div>").addClass("plate-setup-tab-field-container");u(s).append(r),u(s).append(o),u(n).append(l),u(n).append(s),u(a.allDataTabs[t]).append(n);var d={id:e.id,name:e.name,root:n,data:e,required:e.required||!1};return i.push(d),a.fieldMap[e.id]=d},_makeRegularField:function(e,t,i,a){var n=this,l=n._createElement("<div></div>").addClass("plate-setup-tab-default-field"),s=n._createElement("<div></div>").addClass("plate-setup-tab-field-left-side"),r=n._createElement("<div></div>").addClass("plate-setup-tab-field-right-side "),o=n._createElement("<div></div>").addClass("plate-setup-tab-name").text(e.name),d=n._createElement("<div></div>").addClass("plate-setup-tab-field-container");r.append(o),r.append(d),l.append(s),l.append(r),n.allDataTabs[t].append(l);var u={id:e.id,name:e.name,root:l,data:e,required:e.required};return u.required&&n.requiredField.push(u.id),i.push(u),n.fieldList.push(u),n.fieldMap[u.id]=u,a&&n._addCheckBox(u),n._createField(u),u.onChange=function(){var e=u.getValue(),t={};t[u.id]=e,n._addAllData(t)},u},_makeMultiplexField:function(e,t,i){var a=this,n=a._createElement("<div></div>").addClass("plate-setup-tab-default-field"),l=a._createElement("<div></div>").addClass("plate-setup-tab-field-left-side"),s=a._createElement("<div></div>").addClass("plate-setup-tab-field-right-side "),r=a._createElement("<div></div>").addClass("plate-setup-tab-name").text(e.name),o=a._createElement("<div></div>").addClass("plate-setup-tab-field-container");s.append(r),s.append(o),n.append(l),n.append(s),a.allDataTabs[t].append(n);var d={id:e.id,name:e.name,root:n,data:e,required:e.required};i.push(d),a.fieldList.push(d),a.fieldMap[e.id]=d;var u=[],c=[];for(var f in e.multiplexFields){var h=e.multiplexFields[f],p=a._makeSubField(h,t,i);u.push(p),h.required&&c.push(p.id)}return(d.required||c.length)&&this.requiredField.push({multiplexId:d.id,subFields:c}),d.subFieldList=u,a._createField(d),a._addCheckBox(d),u.forEach(function(s){s.mainMultiplexField=d,i.push(s),a._createField(s),a._addCheckBox(s),delete a.defaultWell[s.id],s.onChange=function(){var t=s.getValue(),i=s.mainMultiplexField,a=i.singleSelectValue(),e={};e[i.id]=a,e[s.id]=t;var n={id:a,value:e};d._changeMultiFieldValue(n,null);var l=i.detailData;null!==l&&(a=i.singleSelectValue(),l=l.map(function(e){return e[i.id]===a&&(e[s.id]=t),e})),i.detailData=l}}),d.getValue=function(){var e=d.input.select2("data");return e.length?e.map(function(e){return e.id}):null},d}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(s,e){plateLayOutWidget.addWarningMsg=function(){return{fieldWarningMsg:function(e,t,i){var a="fieldWarning"+e.id,n=s("<span>").html(this._assets.warningImg).attr("id",a).addClass("plate-field-warning-image");if(i){if(e.root.find("#"+a).length<=0){e.root.find(".plate-setup-tab-name").text(" "+e.name),e.root.find(".plate-setup-tab-name").prepend(n);var l=s("<div/>").addClass("pop-out-text");l.text(t),e.root.find(".plate-setup-tab-name").append(l),s("#"+a).hover(function(e){l[0].style.display="flex"},function(){l.hide()})}}else 0<e.root.find("#"+a).length&&(e.root.find(".plate-setup-tab-name").text(e.name),s("#"+a).remove())},removeWarningMsg:function(e,t,i){var a="fieldWarning"+e.id,n=s("<span>").html(this._assets.warningImg).attr("id",a).addClass("plate-field-warning-image");if(i){e.root.find(".plate-setup-tab-name").append(n);var l=s("<div/>").addClass("pop-out-text");l.text(t),e.root.find(".plate-setup-tab-name").append(l),s("#"+a).hover(function(e){l[0].style.display="inline-block"},function(){l.hide()})}else s("#"+a).remove(),0<e.root.find("#"+a).length&&s("#"+a).remove()},applyFieldWarning:function(e){var i=this,a={};i.fieldList.forEach(function(e){a[e.id]=[]}),e.forEach(function(e){if(!i.engine.wellEmpty(e))for(var t in a)t in e?a[t].push(e[t]):a[t].push(null)});for(var t=0;t<i.fieldList.length;t++){var n=i.fieldList[t];if(n.applyMultiplexSubFieldColor)n.applyMultiplexSubFieldColor(a[n.id]);else if(n.required){var l=!1;a[n.id].forEach(function(e){e instanceof Array?0===e.length&&(l=!0):null===e&&(l=!0)}),i.fieldWarningMsg(n,"required field",l)}}}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(d,e){plateLayOutWidget.bottomTable=function(){return{_bottomScreen:function(){this.bottomContainer=this._createElement("<div></div>").addClass("plate-setup-bottom-container"),this.bottomTableContainer=this._createElement("<div></div>").addClass("plate-setup-bottom-table-container"),this.bottomTable=this._createElement("<table></table>").addClass("plate-setup-bottom-table"),this.bottomTableContainer.append(this.bottomTable),this.bottomContainer.append(this.bottomTableContainer),this.container.append(this.bottomContainer)},addBottomTableHeadings:function(){this.bottomRow=this._createElement("<tr></tr>");var e=this._createElement("<th></th>").text("Group");this.bottomRow.prepend(e),this.bottomTable.empty(),this.bottomTable.append(this.bottomRow),this.rowCounter=1;for(var t=0;t<this.globalSelectedAttributes.length;t++){var i=this.globalSelectedAttributes[t],a=this.fieldMap[i];e=this._createElement("<th></th>").text(a.name);this.bottomRow.append(e),this.rowCounter=this.rowCounter+1}this.adjustFieldWidth(this.bottomRow)},tileAttrText:function(e,t){var i=this.engine.derivative[e.index];return this.fieldMap[t].getText(i[t])},addBottomTableRow:function(e,i){var a=this,t=this.allTiles[i[0]],n=this._createElement("<tr></tr>"),l=this._createElement("<td></td>").addClass("plate-setup-bottom-id"),s=this._createElement("<button/>");s.addClass("plate-setup-color-text"),s.text(e),l.append(s),s.click(function(e){var t=i.map(function(e){return a.indexToAddress(e)});e.ctrlKey&&a.getSelectedAddress().forEach(function(e){t.indexOf(e)<0&&t.push(e)}),a.setSelectedWell(t),a._trigger("selectedWells",null,{selectedAddress:a.getSelectedAddress()})}),0<e&&(e=(e-1)%(this.colorPairs.length-1)+1);var r=this.colorPairs[e];l.css("background","linear-gradient(to right, "+r[0]+" , "+r[1]+")"),n.append(l);for(var o=0;o<this.globalSelectedAttributes.length;o++){var d=this.globalSelectedAttributes[o],u=this.tileAttrText(t,d),c=this._createElement("<td></td>").text(u);n.append(c)}this.bottomTable.append(n),this.adjustFieldWidth(n)},bottomForFirstTime:function(){this.addBottomTableHeadings();var e=this._createElement("<tr></tr>"),t=this.colorPairs[0],i=this._createElement("<td></td>");i.css("background","-webkit-linear-gradient(left, "+t[0]+" , "+t[1]+")"),e.append(i),this.bottomTable.append(e),this.createExportButton()},adjustFieldWidth:function(e){var t=this.rowCounter;1024<150*t&&e.css("width",152*t+"px")},downloadCSV:function(e,t){var i,a;i=new Blob([e],{type:"text/csv"}),(a=document.createElement("a")).download=t,a.href=window.URL.createObjectURL(i),a.style.display="none",document.body.appendChild(a),a.click()},exportData:function(e){var t=[],i=document.querySelectorAll("table tr"),a={},n=this.engine.stackUpWithColor,l=this.getDimensions(),s=this;for(var r in n)a[r]=n[r].map(function(e){return s.indexToAddress(e,l)});for(var o=0;o<i.length;o++){for(var d=[],u=i[o].querySelectorAll("td, th"),c=0;c<u.length;c++){var f="";if(u[c].innerText&&(f="csv"===e?'"'+u[c].innerText.replace(/"/g,'""')+'"':u[c].innerText),d.push(f),0===o&&0===c&&("csv"===e?d.push('"Location"'):"clipboard"===e&&d.push("Location")),0!==o&&0===c){var h="";a[parseInt(u[c].innerText)]&&("csv"===e?h='"'+a[parseInt(u[c].innerText)].join(",")+'"':"clipboard"===e&&(h=a[parseInt(u[c].innerText)].join(","))),d.push(h)}}"csv"===e?t.push(d.join(",")):"clipboard"===e&&t.push(d.join("\t"))}if("csv"===e)this.downloadCSV(t.join("\n"),"table.csv");else if("clipboard"===e)return t.join("\n")},createExportButton:function(){var e=this,t=d("<div>").addClass("plate-setup-bottom-control-container"),i=d("<div>").addClass("plate-setup-overlay-text-container");i.text("Color groups"),t.append(i);var a=d("<div>").addClass("plate-setup-overlay-bottom-button-container"),n=d("<button/>").addClass("plate-setup-button");function l(){n.text("Export CSV"),n[0].classList.remove("plate-setup-clicked-button"),n.addClass("plate-setup-button")}n.text("Export CSV"),a.append(n),n.click(function(){e.exportData("csv"),n.text("Exported"),n[0].classList.remove("plate-setup-button"),n.addClass("plate-setup-clicked-button"),setTimeout(l,3e3)});var s=d("<button/>").addClass("plate-setup-button");s.text("Copy To Clipboard"),a.append(s);var r=new ClipboardJS(s.get(0),{text:function(){return e.exportData("clipboard")}});function o(){s.text("Copy To Clipboard"),s[0].classList.remove("plate-setup-clicked-button"),s.addClass("plate-setup-button")}r.on("success",function(e){s.text("Copied as tab-delimited format"),s[0].classList.remove("plate-setup-button"),s.addClass("plate-setup-clicked-button"),setTimeout(o,3e3)}),r.on("error",function(e){s.text("Failed to copy table to clipboard: browser may be incompatible"),setTimeout(o,3e3)}),t.append(a),d(".plate-setup-bottom-container").prepend(t)}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(e,i){plateLayOutWidget.canvas=function(){return{allSelectedObjects:null,allPreviouslySelectedObjects:null,colorPointer:0,goldenRatio:.618033988749895,_createCanvas:function(){this.normalCanvas=this._createElement("<canvas>").attr("id","DNAcanvas"),e(this.canvasContainer).append(this.normalCanvas)},_initiateFabricCanvas:function(){var e=this.canvasContainer.width(),t=this.canvasContainer.height();this._setCanvasArea(e,t),this.mainFabricCanvas=new i.Canvas("DNAcanvas",{backgroundColor:"#f5f5f5",selection:!1,stateful:!1,hoverCursor:"pointer",renderOnAddRemove:!1}).setWidth(e).setHeight(t)}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(l,e){plateLayOutWidget.checkBox=function(){return{globalSelectedAttributes:[],_addCheckBox:function(e){var t=l("<span>").html(this._assets.dontImg).addClass("plate-setup-tab-check-box bg-light").data("clicked",!1);t.data("linkedFieldId",e.id),e.root.find(".plate-setup-tab-field-left-side").empty().append(t),this._applyCheckboxHandler(t),e.checkbox=t},_applyCheckboxHandler:function(e){var n=this;e.click(function(e,t){var i=l(this),a={};a[i.data("linkedFieldId")]=!i.data("clicked"),n.changeCheckboxes(a)})},changeSubFieldsCheckboxes:function(e,n){var l=this,s=[];return e.subFieldList.forEach(function(e){var t=e.checkbox,i=t.data("linkedFieldId"),a=t.data("clicked");i in n&&(a=Boolean(n[i])),t.data("clicked",a),a?(t.html(l._assets.doImg),s.push(e.id)):t.html(l._assets.dontImg)}),s},changeCheckboxes:function(e){for(var t=[],i={},a=0;a<this.fieldList.length;a++){var n=this.fieldList[a];if(n.checkbox){n.subFieldList&&(i[n.id]=this.changeSubFieldsCheckboxes(n,e));var l=n.checkbox,s=l.data("linkedFieldId"),r=l.data("clicked");s in e&&(r=Boolean(e[s])),l.data("clicked",r),r?(t.push(s),l.html(this._assets.doImg)):l.html(this._assets.dontImg)}}this.globalSelectedMultiplexSubfield=i,this.globalSelectedAttributes=t,this._clearPresetSelection(),this._colorMixer()},setSubFieldCheckboxes:function(e,n){var l=this,s=[];return e.subFieldList.forEach(function(e){var t=e.checkbox,i=t.data("linkedFieldId"),a=0<=n.indexOf(i);t.data("clicked",a),a?(t.html(l._assets.doImg),s.push(e.id)):t.html(l._assets.dontImg)}),s},setCheckboxes:function(e){e=e||[];for(var t=[],i={},a=0;a<this.fieldList.length;a++){var n=this.fieldList[a];if(n.checkbox){n.subFieldList&&(i[n.id]=this.setSubFieldCheckboxes(n,e));var l=n.checkbox,s=l.data("linkedFieldId"),r=0<=e.indexOf(s);l.data("clicked",r),r?(t.push(s),l.html(this._assets.doImg)):l.html(this._assets.dontImg)}}this.globalSelectedMultiplexSubfield=i,this.globalSelectedAttributes=t,this._clearPresetSelection(),this._colorMixer()}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};jQuery,fabric,plateLayOutWidget.colorManager=function(){return{colorPairs:[["#e6e6e6","#808080"],["#66e8ff","#0082c8"],["#ff7fb1","#e6194b"],["#a2ffb1","#3cb44b"],["#f784ff","#911eb4"],["#ffe897","#f58231"],["#6666ff","#0000FF"],["#ffff7f","#ffe119"],["#acffff","#46f0f0"],["#ff98ff","#f032e6"],["#ffffa2","#d2f53c"],["#ffffff","#fabebe"],["#66e6e6","#008080"],["#ffffff","#e6beff"],["#ffd48e","#aa6e28"],["#e66666","#800000"],["#ffffff","#aaffc3"],["#e6e666","#808000"],["#ffffff","#ffd8b1"],["#66a9ef","#004389"],["#ff6672","#a7000c"],["#66db72","#00750c"],["#b866db","#520075"],["#ffa966","#b64300"],["#ffff66","#c0a200"],["#6dffff","#07b1b1"],["#ff66ff","#b100a7"],["#f9ff66","#93b600"],["#ffe5e5","#bb7f7f"],["#66a7a7","#004141"],["#ffe5ff","#a77fc0"],["#d19566","#6b2f00"],["#ffffef","#c0bb89"],["#d1ffea","#6bc084"],["#a7a766","#414100"],["#ffffd8","#c09972"],["#a5ffff","#3fc1ff"],["#ffbef0","#ff588a"],["#e1fff0","#7bf38a"],["#ffc3ff","#d05df3"],["#ffffd6","#ffc170"],["#a5a5ff","#3f3fff"],["#ffffbe","#ffff58"],["#ebffff","#85ffff"],["#ffd7ff","#ff71ff"],["#a5ffff","#3fbfbf"],["#ffffcd","#e9ad67"],["#ffa5a5","#bf3f3f"],["#ffffa5","#bfbf3f"]]}};plateLayOutWidget=plateLayOutWidget||{};!function(e,u){plateLayOutWidget.createCanvasElements=function(){return{scaleFactor:1,baseSizes:{spacing:48,tile_radius:22,center_radius_complete:10,center_radius_incomplete:14,label_size:14,label_spacing:24,text_size:13,stroke:.5,gap:2},_setCanvasArea:function(e,t){this.scaleFactor=Math.min(t/(this.dimensions.rows*this.baseSizes.spacing+this.baseSizes.label_spacing),e/(this.dimensions.cols*this.baseSizes.spacing+this.baseSizes.label_spacing));var i={};for(var a in this.baseSizes)i[a]=this.baseSizes[a]*this.scaleFactor;this.sizes=i},_canvas:function(){this._fixRowAndColumn(),this._putCircles()},_fixRowAndColumn:function(){for(var e=this.dimensions.cols,t=this.dimensions.rows,i=this.sizes.spacing,a=this.sizes.label_spacing/2,n=this.sizes.label_spacing+this.sizes.spacing/2,l=this.sizes.label_size,s=a,r=n,o=1;o<=e;o++){var d=new u.IText(o.toString(),{fill:"black",originX:"center",originY:"center",fontSize:l,top:s,left:r,fontFamily:'"Roboto", Arial, sans-serif',selectable:!1,fontWeight:"400"});r+=i,this.mainFabricCanvas.add(d)}s=n,r=a;for(o=1;o<=t;o++){d=new u.IText(this.rowIndex[o-1],{fill:"black",originX:"center",originY:"center",fontSize:l,top:s,left:r,fontFamily:'"Roboto", Arial, sans-serif',selectable:!1,fontWeight:"400"});s+=i,this.mainFabricCanvas.add(d)}},_putCircles:function(){for(var e=this.dimensions.cols,t=this.dimensions.rows,i=0,a=0;a<t;a++)for(var n=0;n<e;n++){this.allTiles.length;var l=this._createTile(a,n);l.index=i++,this.allTiles.push(l),this.mainFabricCanvas.add(l.background),this.mainFabricCanvas.add(l.highlight),this.mainFabricCanvas.add(l.circle),this.mainFabricCanvas.add(l.circleCenter),this.mainFabricCanvas.add(l.circleText)}this._addLargeRectangleOverlay(),this._fabricEvents()},_createTile:function(e,t){var i={visible:!1,colorIndex:null};i.row=e,i.col=t,i.address=this.rowIndex[e]+(t+1);var a=(e+1)*this.sizes.spacing,n=(t+1)*this.sizes.spacing;return i.background=new u.Circle({top:a,left:n,radius:this.sizes.tile_radius,originX:"center",originY:"center",hasControls:!1,hasBorders:!1,lockMovementX:!0,lockMovementY:!0,evented:!1}),i.background.setGradient("fill",{type:"radial",x1:this.sizes.tile_radius,x2:this.sizes.tile_radius,y1:this.sizes.tile_radius+this.sizes.gap,y2:this.sizes.tile_radius+this.sizes.gap,r1:this.sizes.tile_radius-this.sizes.gap,r2:this.sizes.tile_radius,colorStops:{0:"rgba(0,0,0,0.1)",1:"rgba(0,0,0,0.2)"}}),i.highlight=new u.Rect({originX:"center",originY:"center",top:a,left:n,width:this.sizes.spacing,height:this.sizes.spacing,fill:"rgba(0,0,0,0.4)",evented:!1,visible:!1}),i.circle=new u.Circle({originX:"center",originY:"center",top:a,left:n,radius:this.sizes.tile_radius,stroke:"gray",strokeWidth:this.sizes.stroke,evented:!1,visible:!1}),i.circleCenter=new u.Circle({originX:"center",originY:"center",top:a,left:n,radius:this.sizes.center_radius_incomplete,fill:"white",stroke:"gray",strokeWidth:this.sizes.stroke,evented:!1,visible:!1}),i.circleText=new u.IText("",{originX:"center",originY:"center",top:a,left:n,fill:"black",fontFamily:'"Roboto", Arial, sans-serif',fontSize:this.sizes.text_size,lockScalingX:!0,lockScalingY:!0,evented:!1,visible:!1}),i},setTileComplete:function(e,t){e.circleText.fontWeight=t?(e.circleCenter.radius=this.sizes.center_radius_complete,e.circleText.fill="black","normal"):(e.circleCenter.radius=this.sizes.center_radius_incomplete,e.circleText.fill="red","bold")},setTileVisible:function(e,t){e.visible=t,e.circle.visible=e.visible,e.circleCenter.visible=e.visible,e.circleText.visible=e.visible},setTileColor:function(e,t,i){this.setTileVisible(e,!0),e.colorIndex=parseInt(t),e.circleText.text=String(e.colorIndex),0<t&&(t=(t-1)%(this.colorPairs.length-1)+1);var a=this.colorPairs[t];e.circle.setGradient("fill",{y2:2*this.sizes.tile_radius,colorStops:a})},_addLargeRectangleOverlay:function(){this.overLay=new u.Rect({width:632,height:482,left:0,top:0,opacity:0,originX:"left",originY:"top",lockMovementY:!0,lockMovementX:!0,selectable:!1}),this.mainFabricCanvas.add(this.overLay)}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(f,e){plateLayOutWidget.createField=function(){return{_createField:function(e){switch(e.data.type){case"text":this._createTextField(e);break;case"numeric":this._createNumericField(e);break;case"select":this._createSelectField(e);break;case"multiselect":this._createMultiSelectField(e);break;case"boolean":this._createBooleanField(e);break;case"multiplex":this._createMultiplexField(e)}},_createTextField:function(i){var e=i.id,t=this._createElement("<input>").attr("id",e).addClass("plate-setup-tab-input");i.root.find(".plate-setup-tab-field-container").append(t),this.defaultWell[e]=null,i.parseValue=function(e){return e=e?String(e):null},i.getValue=function(){var e=t.val().trim();return""==e&&(e=null),e},i.setValue=function(e){t.val(e)},i.getText=function(e){return null==e?"":e},i.disabled=function(e){i.input.prop("disabled",e)},i.parseText=i.parseValue,t.on("input",function(e,t){i.onChange()}),i.input=t},_createOpts:function(e){var t={allowClear:!0,placeholder:"select",minimumResultsForSearch:10};if(e.options)t.data=e.options;else{if(!e.query)throw"Must specify data or query";var i=e.query;e.delay&&(i=this._debounce(e.delay,i)),t.query=i}return t},_createSelectField:function(i){var a=i.id,t=this._createElement("<input/>").attr("id",a).addClass("plate-setup-tab-select-field");i.root.find(".plate-setup-tab-field-container").append(t),this.defaultWell[a]=null;var n=this._createOpts(i.data),l={};n.data.forEach(function(e){l[e.id]=e}),t.select2(n),i.parseValue=function(e){var t=e;if(""==t&&(t=null),null==t)return null;if(t in l)return l[t].id;throw"Invalid value "+e+" for select field "+a},i.disabled=function(e){i.input.prop("disabled",e)},i.getValue=function(){var e=t.select2("data");return e?e.id:null},i.setValue=function(e){e&&(e=l[e]),t.select2("data",e)},i.setOpts=function(e){t.select2("data",{}),n.data=e||[],t.select2(n)},i.getText=function(e){return null==e?"":l[e].text},i.parseText=function(e){var t=e;if(""==t&&(t=null),null==t)return null;if(t in l)return l[t].text;throw"Invalid text value "+e+" for select field "+a},t.on("change",function(e,t){i.onChange()}),i.input=t},_createMultiSelectField:function(l){var i=l.id,a=this,s=this._createElement("<input/>").attr("id",i).addClass("plate-setup-tab-multiselect-field");s.attr("multiple","multiple"),l.root.find(".plate-setup-tab-field-container").append(s),a.defaultWell[i]=null;var r=a._createOpts(l.data);r.multiple=!0;var n={};r.data.forEach(function(e){n[e.id]=e}),s.select2(r),l.disabled=function(e){l.input.prop("disabled",e)},l.parseValue=function(e){var t=e;return t=t&&t.length?t.map(function(e){if(e in n)return n[e].id;throw"Invalid value "+e+" for multiselect field "+i}):null},l.setOpts=function(e){var t=l.data.options,i=[];for(var a in t){var n=t[a];0<=e.indexOf(n.id)&&i.push(n)}r.data=i,s.select2(r)},l.getValue=function(){var e=s.select2("data");return e.length?e.map(function(e){return e.id}):null},l.setValue=function(e){e=(e=e||[]).map(function(e){return n[e]}),s.select2("data",e)},l.getText=function(e){return null==e?"":0<e.length?e.map(function(e){return n[e].text}).join("; "):""},l.multiOnChange=function(e,t){e&&(e=e.id.toString()),t&&(t=t.id.toString());var i={};i[l.id]={multi:!0,added:e,removed:t},a._addAllData(i)},l.parseText=function(e){var t=e;return t=t&&t.length?t.map(function(e){if(e in n)return n[e].text;throw"Invalid text value "+e+" for multiselect field "+i}):null},s.on("change",function(e,t){var i=e.added,a=e.removed;l.multiOnChange(i,a)}),l.input=s,a._createDeleteButton(l)},_createNumericField:function(n){var i=n.id,e=n.data,t=this._createElement("<input>").addClass("plate-setup-tab-input").attr("placeholder",e.placeholder||"").attr("id",i);n.root.find(".plate-setup-tab-field-container").append(t),this.defaultWell[i]=null;var a=e.units||[],l=e.defaultUnit||null,s=null;if(l?a.length?a.indexOf(l)<0&&(l=a[0]):a=[l]:a.length&&(l=a[0]),a.length)if(n.units=a,n.hasUnits=!0,n.defaultUnit=l,1==a.length){var r=f("<div></div>").addClass("plate-setup-tab-unit");r.text(l),n.root.find(".plate-setup-tab-field-container").append(r)}else{s=this._createElement("<input/>").attr("id",i).addClass("plate-setup-tab-label-select-field"),n.root.find(".plate-setup-tab-field-container").append(s);var o=null,d={data:a.map(function(e){var t={id:e,text:e};return e==l&&(o=t),t}),allowClear:!1,minimumResultsForSearch:10};s.select2(d),s.select2("data",o)}n.disabled=function(e){n.input.prop("disabled",e),s&&s.prop("disabled",e)},n.setUnitOpts=function(e){n.units=e||null;var t=[],i=n.defaultUnit=null;n.units&&n.units.length&&(n.defaultUnit=n.units[0],t=n.units.map(function(e){var t={id:e,text:e};return e==n.defaultUnit&&(i=t),t}));var a={data:t,allowClear:!1,minimumResultsForSearch:10};s.select2(a),s.select2("data",i)},n.parseValue=function(e){var t;if(f.isPlainObject(e)){if(n.hasUnits)return null===(t=n.parseRegularValue(e.value))?null:{value:t,unit:n.parseUnit(e.unit)};throw"Value must be plain numeric for numeric field "+i}return n.hasUnits?null===(t=n.parseRegularValue(e))?null:{value:t,unit:n.defaultUnit}:n.parseRegularValue(e)},n.getValue=function(){var e=n.getRegularValue();if(null===e||isNaN(e))return null;if(n.hasUnits){var t={value:e,unit:n.getUnit()};if(n.data.hasMultiplexUnit)for(var i in n.data.unitMap){n.data.unitMap[i].forEach(function(e){e.text===t.unit&&(t.unitTypeId=i,t.unitId=e.id)})}return t}return e},n.setValue=function(e){n.hasUnits?f.isPlainObject(e)?(n.setUnit(e.unit||n.defaultUnit),n.setRegularValue(e.value)):(n.setRegularValue(e),n.setUnit(n.defaultUnit)):n.setRegularValue(e)},n.parseRegularValue=function(e){if(null==e)return null;var t=String(e).trim();if(""===t)return null;if(t=Number(e),isNaN(t))throw"Invalid value "+e+" for numeric field "+i;return t},n.getRegularValue=function(){var e=t.val().trim();return e=""==e?null:Number(e)},n.setRegularValue=function(e){t.val(e)},n.parseUnit=function(e){if(null==e||""===e)return n.defaultUnit;for(var t=0;t<a.length;t++)if(e.toLowerCase()==a[t].toLowerCase())return a[t];throw"Invalid unit "+e+" for field "+i},n.getUnit=function(){return s?s.val():n.defaultUnit},n.setUnit=function(e){s&&(null!=(e=e||n.defaultUnit)&&(e={id:e,text:e}),s.select2("data",e))},n.getText=function(e){if("object"==typeof e&&e){var t=e.value,i=e.unit;return null==t?"":(t=t.toString(),i||(i=l),i&&(t=t+" "+i),t)}return n.getRegularText(e)},n.getRegularText=function(e){return null==e?"":e=e.toString()},n.parseText=function(e){var t=n.parseValue(e);return t&&"object"==typeof t?t.value+t.unit:t||null},t.on("input",function(){var e=n.getRegularValue();isNaN(e)?t.addClass("invalid"):t.removeClass("invalid"),n.onChange()}),s&&s.on("change",function(){n.onChange()}),n.input=t,n.unitInput=s},_createBooleanField:function(t){var i=t.id,a=this._createElement("<input/>").attr("id",i).addClass("plate-setup-tab-select-field");this.defaultWell[i]=null,t.root.find(".plate-setup-tab-field-container").append(a);var n={id:"true",text:"true"},l={id:"false",text:"false"},e={data:[n,l],placeholder:"select",allowClear:!0,minimumResultsForSearch:-1,initSelection:function(e,t){var i=e.val();t({id:i,text:i})}};a.select2(e),t.disabled=function(e){t.input.prop("disabled",e)},t.parseValue=function(e){if(null==e)return null;var t=String(e).trim().toLowerCase();if("true"==t)t=!0;else if("false"==t)t=!1;else{if(""!=t)throw"Invalid value "+e+" for boolean field "+i;t=null}return t},t.getValue=function(){switch(a.val()){case"true":return!0;case"false":return!1;default:return null}},t.setValue=function(e){e=1==e||"true"==e?n:0==e||"false"==e?l:null,a.select2("data",e)},t.getText=function(e){return null==e?"":e.toString()},t.parseText=t.parseValue,a.on("change",function(e){t.onChange()}),t.input=a},_createMultiplexField:function(o){var d=this;this._createMultiSelectField(o),d.defaultWell[o.id]=[];var e=d._createElement("<div></div>").addClass("plate-setup-tab-name-singleSelect").text("Select to edit"),t=d._createElement("<div></div>").addClass("plate-setup-tab-field-container-singleSelect");o.root.find(".plate-setup-tab-field-right-side").append(e,t),o.singleSelect=this._createElement("<input/>").attr("id",o.id+"SingleSelect").addClass("plate-setup-tab-multiplex-single-select-field"),o.singleSelect.appendTo(t),o.singleSelectValue=function(){var e=o.singleSelect.select2("data");return null!=e&&(e=e.id),e};var u=function(e,t){var i={allowClear:!1,placeholder:"select",minimumResultsForSearch:10,data:e||[]};t||(t=i.data.length?i.data[0]:null),o.singleSelect.select2("data",[]),o.singleSelect.select2(i),o.singleSelect.select2("data",t),o.singleSelect.prop("disabled",0==i.data.length)},c=function(){var t=o.singleSelectValue();o.updateSubFieldUnitOpts(t);var e=o.detailData||[],i=null;e.forEach(function(e){e[o.id]===t&&(i=e)}),i?o.subFieldList.forEach(function(e){e.disabled(!1),e.setValue(i[e.id])}):o.subFieldList.forEach(function(e){e.disabled(!0),e.setValue(null)}),d.readOnlyHandler()};u([]),o.singleSelect.on("change",c),o._changeMultiFieldValue=function(e,t){var i,a={};for(var n in o.data.multiplexFields){a[o.data.multiplexFields[n].id]=null}e&&(i=e.value?e.value:(a[o.id]=e.id,a),e={id:e.id,value:i}),t&&(i=t.value?t.value:(a[o.id]=t.id,a),t={id:t.id,value:i});var l={};l[o.id]={multi:!0,added:e,removed:t},d._addAllData(l)};var a=o.setValue;o.setValue=function(e){var t=null;(o.detailData=e)&&e.length&&(t=e.map(function(e){return e[o.id]})),a(t);var i=o.input.select2("data")||[];u(i),c()},o.disabled=function(t){o.input.prop("disabled",t),o.subFieldList.forEach(function(e){e.disabled(t)}),t?e.text("Select to inspect"):e.text("Select to edit")},o.parseValue=function(e){var t=e;return t=t&&t.length?t.map(function(t){var i={};for(var a in i[o.id]=t[o.id],t)o.subFieldList.forEach(function(e){e.id===a&&(i[e.id]=e.parseValue(t[a]))});return i}):null},o.updateSubFieldUnitOpts=function(t){var i;o.data.options.forEach(function(e){e.id===t&&(i=e)}),o.subFieldList.forEach(function(e){e.data.hasMultiplexUnit&&(i&&i.hasOwnProperty("unitOptions")?e.setUnitOpts(i.unitOptions[e.id]):e.setUnitOpts(null))})},o.multiOnChange=function(e,t){o._changeMultiFieldValue(e,t);var i=o.getValue(),l=o.detailData,s=[],a=null;l&&(s=l.map(function(e){return e[o.id]}));var r=[],n=[];i&&(i.forEach(function(a){if(l&&l.forEach(function(e){e[o.id]===a&&r.push(e)}),s.indexOf(a)<0){var n={};n[o.id]=a,o.updateSubFieldUnitOpts(a),o.subFieldList.forEach(function(i){if(i.hasUnits)if(i.data.hasMultiplexUnit)i.disabled(!1),o.data.options.forEach(function(e){if(e.id===a){var t={value:null,unit:i.units[0]};n[i.id]=i.parseValue(t)}});else{i.data.units&&1<i.data.units.length&&i.disabled(!1);var e={value:null,unit:i.defaultUnit};n[i.id]=i.parseValue(e)}else n[i.id]=i.parseValue(null)}),r.push(n)}}),i.forEach(function(t){o.data.options.forEach(function(e){e.id===t&&n.push(e)})}),a=n[i.length-1]),o.detailData=r,u(n,a),c()},o.getText=function(e){if(null===e)return"";if(o.id in d.globalSelectedMultiplexSubfield){var i=d.globalSelectedMultiplexSubfield[o.id],t=[];for(var a in e){var n=e[a],l=[];for(var s in o.data.options){var r=o.data.options[s];r.id===n[o.id]&&l.push(r.text)}o.subFieldList.forEach(function(e){if(0<=i.indexOf(e.id)){var t=e.getText(n[e.id]);l.push(e.name+": "+t)}}),t.push("{"+l.join(", ")+"}")}return t.join(";")}},o.parseText=function(e){if(null===e)return"";var t=[];for(var i in e){var a=e[i],n=[];for(var l in o.data.options){var s=o.data.options[l];s.id===a[o.id]&&n.push(s.text)}o.subFieldList.forEach(function(e){var t=e.getText(a[e.id]);t&&n.push(t)}),t.push(n)}return t},o.checkMultiplexCompletion=function(e){var t=0,i=0,s=!1;function a(e){var t=0,i=0;for(var a in o.subFieldList){var n=o.subFieldList[a],l=e[n.id];n.required&&(s=!0,t++,"object"==typeof l&&l?l.value&&i++:l&&i++)}return i/t}if(e)if(0<e.length)for(var n in e){t++,i+=a(e[n])}else o.required&&(s=!0,t=1);else o.required&&(s=!0,t=1);return{include:s,completionPct:i/t}},o.applyMultiplexSubFieldColor=function(e){var l={};o.subFieldList.forEach(function(e){e.required&&(l[e.id]={field:e,warningStatus:[]})}),e.forEach(function(e){!function(e){for(var t in o.subFieldList){var i=o.subFieldList[t];if(null===e)o.required&&i.required&&l[i.id].warningStatus.push(!0);else if("object"==typeof e)if(0===e.length)o.required&&i.required&&l[i.id].warningStatus.push(!0);else for(var a in e){var n=e[a][i.id];i.required&&("object"==typeof n&&n?n.value?l[i.id].warningStatus.push(!1):l[i.id].warningStatus.push(!0):n?l[i.id].warningStatus.push(!1):l[i.id].warningStatus.push(!0))}}}(e)});var t=[];for(var i in l){var a=l[i].field;if(0<=l[i].warningStatus.indexOf(!0)){var n=a.name+" is a required subfield for "+o.name+", please make sure all "+o.name+" have "+a.name;o.required,d.fieldWarningMsg(a,n,!0),t.push(!0)}else d.fieldWarningMsg(a,"none",!1),t.push(!1)}var s,r=!1;r=!(t.indexOf(!0)<0),s=o.required?o.name+" is a required field, please also fix missing required subfield(s) below":o.name+" is not a required field, please fix missing required subfield(s) below or remove selected "+o.name,d.fieldWarningMsg(o,s,r)},o.parseMainFieldVal=function(e){for(var t=o.data.options,i=0;i<t.length;i++){var a=t[i];if(a.id===e)return a.text}}},_deleteDialog:function(t){var e,i=this,a=t.allSelectedMultipleVal;e=a?Object.keys(a):[];var n=f("<div/>").addClass("delete-dialog modal");function l(){n.hide(),n.remove()}f("body").append(n);var s=f("<div/>").addClass("modal-content").appendTo(n),r=f("<div/>").appendTo(s),o=f("<div/>").addClass("dialog-buttons").css("justify-content","flex-end").appendTo(s);if(0<e.length){f("<p/>").text(t.name+" in selected wells: choose items to delete and click the delete button below").appendTo(r);var d=i._deleteDialogTable(t,a);if(d.appendTo(r),d.addClass("plate-popout-table"),d.find("td").addClass("plate-popout-td"),d.find("th").addClass("plate-popout-th"),d.find("tr").addClass("plate-popout-tr"),!i.readOnly){var u=f("<button class='multiple-field-manage-delete-button'>Delete Checked Items</button>");o.append(u),u.click(function(){d.find("input:checked").each(function(){var e=this.value;t.multiOnChange(null,{id:e})}),i.decideSelectedFields(),l()})}}else f("<p/>").text("No "+t.name+" in the selected wells").appendTo(r);var c=f("<button>Cancel</button>");o.append(c),c.click(l),n.show(),window.onclick=function(e){e.target==n[0]&&l()}},_deleteDialogTable:function(e,a){var n=this,t=[e.name,"Counts"];n.readOnly||t.push("Delete");var i=f("<table/>"),l=f("<thead/>").appendTo(i);f("<tr/>").appendTo(l).append(t.map(function(e){return f("<th/>").text(e)}));var s=f("<tbody/>").appendTo(i);return e.data.options.forEach(function(e){if(e.id in a){var t=f("<tr/>").appendTo(s),i=f("<input type='checkbox'>").prop("value",e.id);f("<td/>").text(e.text).appendTo(t),f("<td/>").text(a[e.id]).appendTo(t),n.readOnly||f("<td/>").append(i).appendTo(t)}}),i},_createDeleteButton:function(e){var t=this,i=f("<button/>").addClass("plate-setup-remove-all-button");i.id=e.id+"Delete",i.text("Manage "+e.name+"...");var a=t._createElement("<div></div>").addClass("plate-setup-remove-all-button-container");a.append(i),e.deleteButton=i,e.root.find(".plate-setup-tab-field-right-side").append(a),i.click(function(){t._deleteDialog(e)})}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(b,e){plateLayOutWidget.engine=function(v){return{engine:{derivative:{},stackUpWithColor:{},stackPointer:2,wellEmpty:function(e){for(var t in e){var i=e[t];if(null!=i){if(!Array.isArray(i))return!1;if(0<i.length)return!1}}return!0},searchAndStack:function(){this.stackUpWithColor={},this.stackPointer=1;var e={};for(var t in this.derivative){for(var i=this.derivative[t],a={},n=0;n<v.globalSelectedAttributes.length;n++){var l=v.globalSelectedAttributes[n];if(l in v.globalSelectedMultiplexSubfield){var s=v.globalSelectedMultiplexSubfield[l],r=[];for(var o in i[l]){var d=i[l][o],u={};u[l]=d[l],s.forEach(function(e){u[e]=d[e]}),r.push(u)}a[l]=r}else null!=i[l]&&(a[l]=i[l])}b.isEmptyObject(a)?e[t]=null:e[t]=JSON.stringify(a)}for(;!b.isEmptyObject(e);){var c=Object.keys(e).map(function(e){return parseFloat(e,10)});c.sort(function(e,t){return e-t});var f=c[0],h=e[f],p=[];if(h){for(n=0;n<c.length;n++){h==e[t=c[n]]&&(p.push(t),this.stackUpWithColor[this.stackPointer]=p,delete e[t])}0<p.length&&this.stackPointer++}else this.stackUpWithColor[0]?this.stackUpWithColor[0].push(f):this.stackUpWithColor[0]=[f],delete e[f]}},applyColors:function(){var e=0,t=0;v.addBottomTableHeadings();for(var i=0;i<v.allTiles.length;i++){var a=v.allTiles[i];v.setTileVisible(a,!1)}for(var n=0;n<this.stackPointer;n++){var l=this.stackUpWithColor[n];if(l)for(var s in v.addBottomTableRow(n,l),l){e++;var r=this.stackUpWithColor[n][s],o=(a=v.allTiles[r],this.derivative[r]);v.setTileColor(a,n,this.stackPointer);var d=this.checkCompletion(o,a);v.setTileComplete(a,1==d),t+=d}}t=Math.floor(100*t/e),isNaN(t)?v.overLayTextContainer.text("Completion Percentage: 0%"):v.overLayTextContainer.text("Completion Percentage: "+t+"%")},checkCompletion:function(e,t){for(var i=0,a=0,n=0;n<v.fieldList.length;n++){var l=v.fieldList[n];if(l.checkMultiplexCompletion){var s=l.checkMultiplexCompletion(e[l.id]);s.include&&(a+=s.completionPct,i++)}else l.required&&(i++,null!==e[l.id]&&a++)}return i===a?1:a/i}}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(u,n){plateLayOutWidget.fabricEvents=function(){return{colorToIndex:{},startCoords:{x:0,y:0},focalWell:{row:0,col:0},selectedAreas:[],_clickCoords:function(e){var t=e.e.target.getBoundingClientRect();return{x:e.e.clientX-t.left,y:e.e.clientY-t.top}},_fabricEvents:function(){var s=this;u(s.target).on("getPlates",function(e,t){s.getPlates(JSON.parse(t))}),s.mainFabricCanvas.on("mouse:down",function(e){s.selecting=!0;var t=s._clickCoords(e),i=s.selectedAreas.slice(),a=s.focalWell,n=s._wellToCoords(a,!0),l=s._coordsToRect(n,t);e.e.ctrlKey?(n=t,l=s._coordsToRect(n,t),a=s._coordsToWell(n),e.e.shiftKey?i=[s._rectToArea(l)]:i.push(s._rectToArea(l))):e.e.shiftKey?i[i.length-1]=s._rectToArea(l):(n=t,l=s._coordsToRect(n,t),a=s._coordsToWell(n),i=[s._rectToArea(l)]),s.startCoords=n,s.setSelection(i,a),s.mainFabricCanvas.renderAll()}),s.mainFabricCanvas.on("mouse:move",function(e){if(s.selecting){var t=s.selectedAreas.slice(),i=s._clickCoords(e),a=s._coordsToRect(s.startCoords,i),n=s._rectToArea(a);n&&(t[t.length-1]=n),s.setSelection(t,s.focalWell),s.mainFabricCanvas.renderAll()}}),s.mainFabricCanvas.on("mouse:up",function(e){s.selecting=!1;var t=s.selectedAreas.slice(),i=s._clickCoords(e),a=s._coordsToRect(s.startCoords,i),n=s._rectToArea(a);n&&(t[t.length-1]=n),s.setSelection(t,s.focalWell),s.decideSelectedFields(),s.mainFabricCanvas.renderAll(),s._trigger("selectedWells",null,{selectedAddress:s.getSelectedAddress()})})},setSelection:function(e,t){this.selectedAreas=e,this.focalWell=t,this.allSelectedObjects=this._areasToTiles(e),this._setSelectedTiles(),this._setFocalWellRect(this.focalWell),document.activeElement.blur()},_setFocalWellRect:function(e){var t;if(this.disableAddDeleteWell){var i=this.locToAddress({r:e.row,c:e.col});this.addressAllowToEdit.indexOf(i)<0?(t=!1,this.setFieldsDisabled(!0)):(t=!0,this.setFieldsDisabled(!1))}else e&&(t=!0);if(t){var a=this._areaToRect(this._wellToArea(e));this.focalWellRect?(this.focalWellRect.top=a.top,this.focalWellRect.left=a.left,this.focalWellRect.width=a.width-2,this.focalWellRect.height=a.height-2):(this.focalWellRect=new n.Rect({width:a.width-2,height:a.height-2,left:a.left,top:a.top,fill:null,strokeWidth:2,stroke:"black",selectable:!1}),this.mainFabricCanvas.add(this.focalWellRect))}else this.mainFabricCanvas.remove(this.focalWellRect),this.focalWellRect=null},_setSelectedTiles:function(){var i=this.allSelectedObjects;this.allTiles.forEach(function(e){var t=0<=i.indexOf(e);e.highlight.visible=t})},_getSelectedWells:function(){var i=this;return this.allSelectedObjects.map(function(e){var t=i.engine.derivative[e.index];return t||(t=i.defaultWell),t})},_getCommonFields:function(e){if(e.length){for(var t=e[0],i=u.extend(!0,{},t),a=1;a<e.length;a++){var n=e[a];for(var l in i)if(Array.isArray(i[l])){for(var s=i[l],r=[],o=0;o<s.length;o++){var d=s[o];d&&"object"==typeof d?this.containsObject(d,n[l])&&r.push(d):0<=u.inArray(d,n[l])&&r.push(d)}i[l]=r}else n[l]&&"object"==typeof n[l]&&i[l]&&"object"==typeof i[l]?n[l].value===i[l].value&&n[l].unit===i[l].unit||delete i[l]:i[l]!=n[l]&&delete i[l]}return i}return{}},containsObject:function(n,e){var t=[];return!!e&&(e.forEach(function(i){var a=[];Object.keys(i).forEach(function(e){if(0<=Object.keys(n).indexOf(e)){var t=i[e];"object"==typeof t&&t?n[e]?a.push(t.unit===n[e].unit&&t.value===n[e].value):a.push(!1):a.push(t===n[e])}}),t.push(a.indexOf(!1)<0)}),0<=t.indexOf(!0))},_getCommonWell:function(e){if(e.length){for(var t=e[0],i=u.extend(!0,{},t),a=1;a<e.length;a++){var n=e[a];for(var l in i)if(Array.isArray(i[l])){for(var s=i[l],r=[],o=0;o<s.length;o++){var d=s[o];"object"==typeof s[o]?this.containsObject(d,n[l])&&r.push(d):0<=u.inArray(d,n[l])&&r.push(d)}i[l]=r}else n[l]&&"object"==typeof n[l]&&i[l]&&"object"==typeof i[l]?n[l].value===i[l].value&&n[l].unit===i[l].unit||(i[l]=null):i[l]!=n[l]&&(i[l]=null)}return i}return this.defaultWell},_getAllMultipleVal:function(e){this.multipleFieldList.forEach(function(i){if(e.length){var a={};e.forEach(function(e){var t=i.id;e[t]&&0<e[t].length&&e[t].forEach(function(e){"object"==typeof e?e[t]in a?a[e[t]]++:a[e[t]]=1:e in a?a[e]++:a[e]=1})}),i.allSelectedMultipleVal=a}else i.allSelectedMultipleVal=null})},decideSelectedFields:function(){var e=this._getSelectedWells();this._getAllMultipleVal(e),this.applyFieldWarning(e);var t=this._getCommonWell(e);this._addDataToTabFields(t)},getDifferentWellsVals:function(e){var t=[];for(var i in e)t.push(e[i]);var a={};if(1<t.length){var n=this._getCommonWell(t),l={};for(var s in e[0])l[s]=[];for(var r in t){var o={},d=t[r];for(var u in d){var c=n[u],f=d[u],h=null;if(Array.isArray(f)){h=[];for(var p=0;p<f.length;p++){var v=f[p];v?this.containsObject(v,c)||(h.push(v),this.containsObject(v,l[u])||l[u].push(v)):0<=c.indexOf(v)&&(h.push(v),0<=!l[u].indexOf(v)&&l[u].push(v))}}else f&&"object"==typeof f?c&&"object"==typeof c?f.value!==c.value&&f.unit!==c.unit&&(h=f,this.containsObject(f,l[u])||l[u].push(f)):(h=f,this.containsObject(f,l[u])||l[u].push(f)):f!==c&&(h=f,0<=!l[u].indexOf(f)&&l[u].push(f));o[u]=h}a[r]=o}for(var u in l)if(0===l[u].length)for(var r in a)delete a[r][u];return a}if(e[0]){var b={};for(var u in e[0]){f=e[0][u];Array.isArray(f)?0<f.length&&(b[u]=f):f&&(b[u]=f)}return{0:b}}},getWellSetAddressWithData:function(){var e=[],t=this.engine.derivative;for(var i in t)e.push(this.indexToAddress(i));return e}}}}(jQuery,fabric),(plateLayOutWidget=plateLayOutWidget||{}).assets=function(){return{_assets:{doImg:"&#10003;",dontImg:"",warningImg:"&#9888;"}}};plateLayOutWidget=plateLayOutWidget||{};!function(i,e){plateLayOutWidget.interface=function(){return{_createInterface:function(){var e="<div></div>";this.container=this._createElement(e).addClass("plate-setup-wrapper"),this.topSection=this._createElement(e).addClass("plate-setup-top-section"),this.topLeft=this._createElement(e).addClass("plate-setup-top-left"),this.topRight=this._createElement(e).addClass("plate-setup-top-right"),this.overLayContainer=this._createElement(e).addClass("plate-setup-overlay-container"),this.canvasContainer=this._createElement(e).addClass("plate-setup-canvas-container"),this._createOverLay(),i(this.topLeft).append(this.overLayContainer),this._createCanvas(),i(this.topLeft).append(this.canvasContainer),i(this.topSection).append(this.topLeft),i(this.topSection).append(this.topRight),i(this.container).append(this.topSection),i(this.element).append(this.container),this._initiateFabricCanvas(),this._createTabAtRight(),this._createTabs(),this._placePresetTabs(),this._bottomScreen(),this._canvas(),this.bottomForFirstTime();var t=this;this._setShortcuts(),i(document.body).keyup(function(e){t._handleShortcuts(e)}),this._configureUndoRedoArray()},_createElement:function(e){return i(e)},_setShortcuts:function(){var t=this;window.addEventListener("cut",function(e){document.activeElement==document.body&&(t.copyCriteria(),t.clearCriteria(),e.preventDefault())}),window.addEventListener("copy",function(e){document.activeElement==document.body&&(t.copyCriteria(),e.preventDefault())}),window.addEventListener("paste",function(e){document.activeElement==document.body&&(t.pasteCriteria(),e.preventDefault())})},_handleShortcuts:function(e){document.activeElement===document.body&&(46==e.keyCode?(this.clearCriteria(),e.preventDefault()):(e.ctrlKey||e.metaKey)&&(90==e.keyCode?(e.shiftKey?this.redo():this.undo(),e.preventDefault()):89==e.keyCode&&(this.redo(),e.preventDefault())))}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(t,e){plateLayOutWidget.loadPlate=function(e){return{getPlates:function(e){var t={};for(var i in e.derivative){var a=e.derivative[i];t[i]=this.sanitizeWell(a)}var n=e.checkboxes||[],l=this.sanitizeAreas(e.selectedAreas,e.focalWell),s={derivative:t,checkboxes:n,selectedAreas:l.selectedAreas,focalWell:l.focalWell};this.setData(s)},sanitizeAreas:function(e,t){var i=this,a=this.dimensions.rows,n=this.dimensions.cols;if(e||(e=[]),e.length){var l=(e=e.map(function(e){return{minCol:i._coordIndex(Math.min(e.minCol,e.maxCol),n),minRow:i._coordIndex(Math.min(e.minRow,e.maxRow),a),maxCol:i._coordIndex(Math.max(e.minCol,e.maxCol),n),maxRow:i._coordIndex(Math.max(e.minRow,e.maxRow),a)}}))[e.length-1];t&&!this._wellInArea(t,l)&&(t=null),t||(t={row:l.minRow,col:l.minCol})}else t||(t={row:0,col:0}),e=[this._wellToArea(t)];return{selectedAreas:e,focalWell:t}},sanitizeWell:function(e){for(var t={},i=0;i<this.fieldList.length;i++){var a=this.fieldList[i];t[a.id]=a.parseValue(e[a.id])}return t},setData:function(e){this.engine.derivative=t.extend(!0,{},e.derivative),this.setCheckboxes(e.checkboxes),this.setSelection(e.selectedAreas,e.focalWell),this._colorMixer(),this.decideSelectedFields(),this.mainFabricCanvas.renderAll()}}}}(jQuery,fabric);var GET_PLATES="getPlates",IS_READ_ONLY="isReadOnly",IS_DISABLE_ADD_DELETE_WELL="isDisableAddDeleteWell",GET_SELECTED_OBJECT="getSelectedObject",SETSELECTEDWELL="setSelectedWell";plateLayOutWidget=plateLayOutWidget||{};jQuery,fabric,plateLayOutWidget.overlay=function(){return{_createOverLay:function(){var t=this;this.overLayTextContainer=this._createElement("<div></div>").addClass("plate-setup-overlay-text-container"),this.overLayTextContainer.text("Completion Percentage:"),this.overLayContainer.append(this.overLayTextContainer),this.overLayButtonContainer=this._createElement("<div></div>").addClass("plate-setup-overlay-button-container"),this.overLayContainer.append(this.overLayButtonContainer),this.clearCriteriaButton=this._createElement("<button />").addClass("plate-setup-button"),this.clearCriteriaButton.text("Clear"),this.overLayButtonContainer.append(this.clearCriteriaButton),this.clearCriteriaButton.click(function(e){t.clearCriteria()}),this.copyCriteriaButton=this._createElement("<button />").addClass("plate-setup-button"),this.copyCriteriaButton.text("Copy"),this.overLayButtonContainer.append(this.copyCriteriaButton),this.copyCriteriaButton.click(function(e){t.copyCriteria()}),this.pasteCriteriaButton=this._createElement("<button />").addClass("plate-setup-button"),this.pasteCriteriaButton.text("Paste"),this.overLayButtonContainer.append(this.pasteCriteriaButton),this.pasteCriteriaButton.click(function(e){t.pasteCriteria()}),this.undoButton=this._createElement("<button />").addClass("plate-setup-button"),this.undoButton.text("Undo"),this.overLayButtonContainer.append(this.undoButton),this.undoButton.click(function(e){t.undo()}),this.redoButton=this._createElement("<button />").addClass("plate-setup-button"),this.redoButton.text("Redo"),this.overLayButtonContainer.append(this.redoButton),this.redoButton.click(function(e){t.redo()})},clearCriteria:function(){if(this.allSelectedObjects){for(var e=this.allSelectedObjects.length,t=!1,i=0;i<e;i++){var a=this.allSelectedObjects[i];if(a.index in this.engine.derivative){if(this.emptyWellWithDefaultVal&&this.disableAddDeleteWell){var n=JSON.parse(JSON.stringify(this.defaultWell)),l=this.emptyWellWithDefaultVal;for(var s in l)s in n?(n[s]=l[s],this._applyFieldData(s,l[s])):console.log("Well does not contain key: "+s+", please contact support");this.engine.derivative[a.index]=n}else delete this.engine.derivative[a.index];t=!0}}t&&this.derivativeChange(),this._colorMixer(),this.decideSelectedFields()}else alert("Please select any well")},copyCriteria:function(){if(this.allSelectedObjects){var e=this._getSelectedWells();this.commonWell=this._getCommonFields(e)}else alert("Please select any well.")},pasteCriteria:function(){this.commonWell&&(this._addAllData(this.commonWell),this.decideSelectedFields(),this.mainFabricCanvas.renderAll())}}},$.widget("DNA.plateLayOut",{plateLayOutWidget:{},options:{value:0},allTiles:[],addressToLoc:function(e){var t=/^([A-Z]+)(\d+)$/.exec(e.trim().toUpperCase());if(t){for(var i,a=t[1],n=parseInt(t[2])-1,l=0;l<a.length;l++){var s=a.charCodeAt(l)-65;l?(i+=1,i*=26,i+=s):i=s}return{r:i,c:n}}throw e+" not a proper layout address"},locToIndex:function(e,i){if(i||(i=this.dimensions),e.r<0&&t,!(0<=e.r&&e.r<i.rows))throw"Row index "+(e.r+1)+" invalid";if(!(0<=e.c&&e.c<i.cols))throw"Column index "+(e.c+1)+" invalid";return e.r*i.cols+e.c},addressToIndex:function(e,t){var i=this.addressToLoc(e);return this.locToIndex(i,t)},_rowKey:function(e){var t=e%26,i=(e-t)/26,a=String.fromCharCode(65+t);return 0<i&&(a=String.fromCharCode(64+i)+a),a},indexToLoc:function(e,t){if(t||(t=this.dimensions),e>=t.rows*t.cols)throw"Index too high: "+e.toString(10);var i={};return i.c=e%t.cols,i.r=(e-i.c)/t.cols,i},locToAddress:function(e){return this._rowKey(e.r)+(e.c+1).toString(10)},indexToAddress:function(e,t){var i=this.indexToLoc(e,t);return this.locToAddress(i)},getDimensions:function(){return $.extend(!0,{},this.dimensions)},_create:function(){var e=parseInt(this.options.numRows||8),t=parseInt(this.options.numCols||12);this.dimensions={rows:e,cols:t},this.rowIndex=[];for(var i=0;i<e;i++)this.rowIndex.push(this._rowKey(i));for(var a in this.target=this.element[0].id?"#"+this.element[0].id:"."+this.element[0].className,this.options.readOnly&&this.isReadOnly(!0),plateLayOutWidget)$.extend(this,new plateLayOutWidget[a](this));return this.imgSrc=this.options.imgSrc||"assets",this._createInterface(),this._trigger("created",null,this),this},_init:function(){},addData:function(){alert("wow this is good")},getTextDerivative:function(e){var t={};this.fieldMap;for(var i in e){var a={},n={},l=e[i];for(var s in l)if(s in this.fieldMap){var r=this.fieldMap[s],o=r.parseText(l[s]);n[r.name]=o,a[s]=o}else n[s]=l[s],a[s]=l[s];t[i]={textVal:a,textFieldVal:n}}return t},getWellsDifferences:function(e){return this.getDifferentWellsVals(e)},setFieldsDisabled:function(t){this.fieldList.forEach(function(e){e.disabled(t)})},isReadOnly:function(e){this.readOnly=!!e,this.readOnlyHandler()},readOnlyHandler:function(){this.readOnly?(this.overLayButtonContainer.css("display","none"),$(".multiple-field-manage-delete-button").css("display","none"),this.setFieldsDisabled(!0)):(this.overLayButtonContainer.css("display","flex"),$(".multiple-field-manage-delete-button").css("display","none"),this.disableAddDeleteWell||this.setFieldsDisabled(!1))},disableAddDeleteWell:null,isDisableAddDeleteWell:function(e,t){e?(this.disableAddDeleteWell=!0,this.addressAllowToEdit=this.getWellSetAddressWithData(),this.actionPointer=0,this.undoRedoArray=[],this.undoRedoArray.push(this.createObject()),t&&(this.emptyWellWithDefaultVal=t)):(this.disableAddDeleteWell=!1,this.setFieldsDisabled(!1),this.emptyWellWithDefaultVal=null),this._fabricEvents()},getSelectedObject:function(){for(var e=[],t=0;t<this.allSelectedObjects.length;t++)e.push(this.allSelectedObjects[t].address);var i={},a=this.engine.derivative;for(var n in a){var l=this.indexToAddress(n);0<=e.indexOf(l)&&(i[l]=a[n])}return i},getSelectedIndex:function(){return this.allSelectedObjects.map(function(e){return that.addressToIndex(e.address)})},getSelectedAddress:function(){return this.allSelectedObjects.map(function(e){return e.address})},setSelectedWell:function(e){for(var t=[],i=999,a={},n=0;n<e.length;n++){var l=this.addressToIndex(e[n]),s=this.indexToLoc(l);t.push({minCol:s.c,minRow:s.r,maxCol:s.c,maxRow:s.r}),s.r<=i&&(i=s.r,s.r in a?a[s.r].push(s.c):a[s.r]=[s.c])}var r={row:i,col:Math.min.apply(null,a[i])};this.setSelection(t,r),this.decideSelectedFields(),this.mainFabricCanvas.renderAll()}});plateLayOutWidget=plateLayOutWidget||{};!function(s,e){plateLayOutWidget.preset=function(e){return{presets:[],_placePresetTabs:function(){var e=this.options.attributes.presets;if(e&&e.length){this.wellAttrContainer=this._createElement("<div></div>").addClass("plate-setup-well-attr-container").text("Checkbox presets"),this.tabContainer.append(this.wellAttrContainer),this.presetTabContainer=this._createElement("<div></div>").addClass("plate-setup-preset-container"),this.tabContainer.append(this.presetTabContainer);for(var t=0;t<e.length;t++){var i=e[t],a=this._createElement("<div></div>").addClass("plate-setup-prest-tab-div").text(i.title),n=this._createElement("<div></div>").addClass("plate-setup-prest-tab").data("preset",i.fields).append(a);this.presetTabContainer.append(n);var l=this;n.click(function(){var e=s(this);l._selectPreset(e)}),this.presets.push(n)}}},_clearPresetSelection:function(){for(var e=0;e<this.presets.length;e++){this.presets[e].removeClass("plate-setup-prest-tab-selected").addClass("plate-setup-prest-tab")}},_selectPreset:function(e){this.setCheckboxes(e.data("preset")),e.removeClass("plate-setup-prest-tab").addClass("plate-setup-prest-tab-selected")}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(a,e){plateLayOutWidget.tabs=function(){return{allTabs:[],defaultWell:{},allDataTabs:[],_createTabAtRight:function(){this.tabContainer=this._createElement("<div></div>").addClass("plate-setup-tab-container"),a(this.topRight).append(this.tabContainer)},_createTabs:function(){this.tabHead=this._createElement("<div></div>").addClass("plate-setup-tab-head"),a(this.tabContainer).append(this.tabHead);var e=this.options.attributes.tabs,i=this;e.forEach(function(e,t){i.allTabs[t]=i._createElement("<div></div>").addClass("plate-setup-tab"),a(i.allTabs[t]).data("index",t).text(e.name),a(i.allTabs[t]).click(function(){i._tabClickHandler(this)}),a(i.tabHead).append(i.allTabs[t])}),this.tabDataContainer=this._createElement("<div></div>").addClass("plate-setup-tab-data-container"),a(this.tabContainer).append(this.tabDataContainer),this._addDataTabs(e),a(this.allTabs[0]).click(),this._addTabData()},_tabClickHandler:function(e){if(this.selectedTab){a(this.selectedTab).removeClass("plate-setup-tab-selected").addClass("plate-setup-tab");var t=a(this.selectedTab).data("index");a(this.allDataTabs[t]).css("z-index",0),this.readOnlyHandler()}a(e).addClass("plate-setup-tab-selected"),this.selectedTab=e;var i=a(e).data("index");a(this.allDataTabs[i]).css("z-index",1e3)},_addDataTabs:function(e){var t=0;for(var i in e)this.allDataTabs[t++]=this._createElement("<div></div>").addClass("plate-setup-data-div").css("z-index",0),a(this.tabDataContainer).append(this.allDataTabs[t-1])}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};!function(i,e){plateLayOutWidget.undoRedoManager=function(e){return{undoRedoArray:[],actionPointer:null,addToUndoRedo:function(e){if(null!=this.actionPointer){var t=this.actionPointer+1;t<this.undoRedoArray.length&&this.undoRedoArray.splice(t,this.undoRedoArray.length-t)}this.actionPointer=null,this.undoRedoArray.push(i.extend(!0,{},e))},_configureUndoRedoArray:function(){this.undoRedoArray=[],this.actionPointer=null,this.undoRedoArray.push(i.extend({},{checkboxes:[],derivative:{},selectedAreas:[{minRow:0,minCol:0,maxRow:0,maxCol:0}],focalWell:{row:0,col:0}}))},undo:function(){return console.log("undo"),this.shiftUndoRedo(-1)},redo:function(){return console.log("redo"),this.shiftUndoRedo(1)},shiftUndoRedo:function(e){var t=this.actionPointer;return null==t&&(t=this.undoRedoArray.length-1),t+=e,this.setUndoRedo(t)},setUndoRedo:function(e){return!(e<0)&&(!(e>=this.undoRedoArray.length)&&(this.undoRedoActive=!0,this.setData(this.undoRedoArray[e]),this.actionPointer=e,this.undoRedoActive=!1,this.derivativeChange(),!0))}}}}(jQuery,fabric);plateLayOutWidget=plateLayOutWidget||{};jQuery,fabric,plateLayOutWidget.wellArea=function(e){return{_areasToTiles:function(e){var l=this.dimensions.cols,s=this;return e.reduce(function(e,t){if(t)for(var i=t.minRow;i<=t.maxRow;i++)for(var a=t.minCol;a<=t.maxCol;a++){var n=s.allTiles[a+l*i];e.indexOf(n)<0&&(s.disableAddDeleteWell?0<=s.addressAllowToEdit.indexOf(n.address)&&e.push(n):e.push(n))}return e},[])},_encodeArea:function(e){return e.minRow==e.maxRow&&e.minCol==e.maxCol?this.rowIndex[e.minRow]+e.minCol.toString(10):this.rowIndex[e.minRow]+e.minCol.toString(10)+":"+this.rowIndex[e.maxRow]+e.maxCol.toString(10)},_encodeAreas:function(e){var t=this;return e.map(function(e){return t._encodeArea(e)}).join(",")},_decodeWell:function(e){var t,i=new RegExp("^\\s*("+this.rowIndex.join("|")+")(\\d+)\\s*$");if(t=e.match(i)){var a=this.rowIndex.indexOf(t[1]);if(0<=a)return{row:a,col:parseInt(t[2])-1}}if(t=e.match(/^\s*R(\d+)C(\d+)\s*$/i))return{row:parseInt(t[1])-1,col:parseInt(t[2])-1};throw"Invalid well address: "+e},_decodeArea:function(e){var t=this,i=e.split(":").map(function(e){return t._decodeWell(e)});if(1==i.length)return{minRow:i[0].row,minCol:i[0].col,maxRow:i[0].row,maxCol:i[0].col};if(2!=i.length)throw"Invalid address: "+e;return Math.min(i[0].row,i[1].row),{minRow:Math.min(i[0].row,i[1].row),minCol:Math.min(i[0].col,i[1].col),maxRow:Math.max(i[0].row,i[1].row),maxCol:Math.max(i[0].col,i[1].col)}},_decodeAreas:function(e){var t=this;return e.split(",").map(function(e){return t._decodeArea(e)})},_wellToArea:function(e){return{minCol:e.col,minRow:e.row,maxCol:e.col,maxRow:e.row}},_wellInArea:function(e,t){return e.row>=t.minRow&&e.row<=t.maxRow&&e.col>=t.minCol&&e.col<=t.maxCol},_coordsToRect:function(e,t){var i=Math.min(e.x,t.x);return{top:Math.min(e.y,t.y),left:i,height:Math.abs(t.y-e.y),width:Math.abs(t.x-e.x)}},_coordIndex:function(e,t){return e<0?0:t<=e?t-1:Math.floor(e)},_coordsToWell:function(e){var t=this.dimensions.cols,i=this.dimensions.rows,a=this.sizes.spacing,n=this.sizes.label_spacing,l=(e.x-n)/a,s=(e.y-n)/a;return{row:this._coordIndex(s,i),col:this._coordIndex(l,t)}},_wellToCoords:function(e,t){var i=this.sizes.spacing,a=this.sizes.label_spacing,n=e.col*i+a,l=e.row*i+a;if(t){var s=i/2;n+=s,l+=s}return{x:n,y:l}},_areaToRect:function(e){var t=e.maxRow-e.minRow+1,i=e.maxCol-e.minCol+1,a=this.sizes.spacing,n=this.sizes.label_spacing;return{top:e.minRow*a+n,left:e.minCol*a+n,height:t*a,width:i*a}},_rectToArea:function(e){var t=this.dimensions.rows,i=this.dimensions.cols,a=this.sizes.spacing,n=this.sizes.label_spacing,l=(e.left-n)/a,s=(e.top-n)/a,r=e.height/a,o=l+e.width/a,d=s+r;return o<0&&(o=i),i<=l&&(l=0),d<0&&(d=t),s<=0&&(s=0),{minCol:this._coordIndex(l,i),minRow:this._coordIndex(s,t),maxCol:this._coordIndex(o,i),maxRow:this._coordIndex(d,t)}}}};
-//# sourceMappingURL=plate-map.min.js.map
\ No newline at end of file
diff --git a/dist/js/plate-map.min.js.map b/dist/js/plate-map.min.js.map
deleted file mode 100644
index da1b0dd..0000000
--- a/dist/js/plate-map.min.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["add-data-on-change.js","add-data-to-tabs.js","add-tab-data.js","add-warning-msg.js","bottom-table.js","canvas.js","check-box.js","color-manager.js","create-canvas-elements.js","create-field.js","engine.js","fabric-events.js","image_assets.js","interface.js","load-plate.js","main.js","overlay.js","plate-layout.js","preset.js","tabs.js","undo-redo-manager.js","well-area.js"],"names":["plateLayOutWidget","$","fabric","addDataOnChange","_addAllData","data","this","allSelectedObjects","noOfSelectedObjects","length","wells","objectIndex","well","tile","index","engine","derivative","extend","defaultWell","processedData","processWellData","wellEmpty","emptyWellWithDefaultVal","disableAddDeleteWell","wellCopy","JSON","parse","stringify","defaultValue","key","_applyFieldData","_getAllMultipleVal","applyFieldWarning","_colorMixer","derivativeChange","newData","curWell","wellList","id","v","undefined","multi","curData","preData","newDt","_getMultiData","push","fieldId","addNew","added","removed","value","add","listIdx","toString","map","val","subFieldId","indexOf","removeIndex","removeListIndex","newPreData","idx","parseInt","undoRedoActive","createObject","addToUndoRedo","searchAndStack","applyColors","mainFabricCanvas","renderAll","_trigger","checkboxes","globalSelectedAttributes","slice","selectedAreas","focalWell","requiredField","jQuery","addDataToFields","_addDataToTabFields","values","fieldMap","setValue","addTabData","fieldList","autoId","_addTabData","tabData","options","attributes","tabs","that","multiplexFieldArray","forEach","tab","tabPointer","tabFields","fieldArray","field","field_val","console","log","type","_makeMultiplexField","_makeRegularField","allDataTabs","multipleFieldList","_makeSubField","wrapperDiv","_createElement","addClass","wrapperDivLeftSide","wrapperDivRightSide","nameContainer","text","name","fieldContainer","append","root","required","checkbox","_addCheckBox","_createField","onChange","getValue","subFieldList","requiredSubField","subFieldKey","multiplexFields","subFieldData","subField","multiplexId","subFields","subfield","mainMultiplexField","mainRefField","curId","singleSelectValue","curVal","returnVal","_changeMultiFieldValue","curDataLs","detailData","input","select2","i","addWarningMsg","fieldWarningMsg","include","imgId","img","html","_assets","warningImg","attr","find","prepend","popText","hover","e","style","display","hide","remove","removeWarningMsg","fieldData","applyMultiplexSubFieldColor","Array","bottomTable","_bottomScreen","bottomContainer","bottomTableContainer","container","addBottomTableHeadings","bottomRow","singleField","empty","rowCounter","adjustFieldWidth","tileAttrText","getText","addBottomTableRow","color","singleStack","modelTile","allTiles","row","plateIdDiv","numberText","click","evt","addressToSelect","addressIdx","indexToAddress","ctrlKey","getSelectedAddress","setSelectedWell","selectedAddress","colorPairs","colorStops","css","dataDiv","bottomForFirstTime","createExportButton","downloadCSV","csv","filename","csvFile","downloadLink","Blob","document","createElement","download","href","window","URL","createObjectURL","body","appendChild","exportData","format","rows","querySelectorAll","colorLocMap","colorLocIdxMap","stackUpWithColor","dim","getDimensions","colorIdx","locIdx","cols","j","innerText","replace","loc","join","overlayContainer","descriptionDiv","buttonContainer","exportButton","resetExportText","classList","setTimeout","clipboardButton","clipboard","ClipboardJS","get","resetClipboardText","on","canvas","allPreviouslySelectedObjects","colorPointer","goldenRatio","_createCanvas","normalCanvas","canvasContainer","_initiateFabricCanvas","w","width","h","height","_setCanvasArea","Canvas","backgroundColor","selection","stateful","hoverCursor","renderOnAddRemove","setWidth","setHeight","checkBox","checkImage","dontImg","_applyCheckboxHandler","checkBoxImage","machineClick","changes","changeCheckboxes","changeSubFieldsCheckboxes","subFieldToInclude","clicked","Boolean","doImg","gsa","multiplexCheckedSubField","globalSelectedMultiplexSubfield","_clearPresetSelection","setSubFieldCheckboxes","fieldIds","setCheckboxes","colorManager","createCanvasElements","scaleFactor","baseSizes","spacing","tile_radius","center_radius_complete","center_radius_incomplete","label_size","label_spacing","text_size","stroke","gap","Math","min","dimensions","sizes","prop","_canvas","_fixRowAndColumn","_putCircles","d1","d2","fontSize","top","left","tempFabricText","IText","fill","originX","originY","fontFamily","selectable","fontWeight","rowIndex","tileCounter","col","_createTile","background","highlight","circle","circleCenter","circleText","_addLargeRectangleOverlay","_fabricEvents","visible","colorIndex","address","Circle","radius","hasControls","hasBorders","lockMovementX","lockMovementY","evented","setGradient","x1","x2","y1","y2","r1","r2","0","1","Rect","strokeWidth","lockScalingX","lockScalingY","setTileComplete","complete","setTileVisible","setTileColor","stackPointer","String","overLay","opacity","createField","_createTextField","_createNumericField","_createSelectField","_createMultiSelectField","_createBooleanField","_createMultiplexField","parseValue","trim","disabled","bool","parseText","generated","_createOpts","config","opts","allowClear","placeholder","minimumResultsForSearch","query","delay","_debounce","optMap","opt","setOpts","multiple","allOpts","selectedVal","curOpts","multiOnChange","_createDeleteButton","units","defaultUnit","unitInput","hasUnits","unitText","selected","unit","o","setUnitOpts","newUnits","curUnit","cleanUnit","newOpts","isPlainObject","parseRegularValue","parseUnit","getRegularValue","isNaN","getUnit","hasMultiplexUnit","unitTypeKey","unitMap","setUnit","setRegularValue","Number","toLowerCase","u","getRegularText","textVal","removeClass","tval","fval","initSelection","element","callback","nameContainer1","fieldContainer1","singleSelect","appendTo","setSingleSelectOptions","selected_v","singleSelectChange","updateSubFieldUnitOpts","curSubField","readOnlyHandler","newSubFieldValue","subFieldName","multiselectSetValue","multiselectValues","newOptions","valMap","hasOwnProperty","unitOptions","curIds","curOpt","newMultiplexVal","selectList","newVal","selectId","checkedSubfields","valIdx","subV","subText","optId","x","checkMultiplexCompletion","valList","valCount","completionPct","getSubfieldStatus","vals","req","subFieldWarningMap","warningStatus","multiplexVals","multiplexIdx","updateSubFieldWarningMap","mainFieldStatus","warningText","mainFieldWarning","parseMainFieldVal","_deleteDialog","valToRemove","allSelectedMultipleVal","Object","keys","dialogDiv","killDialog","dialogContent","tableArea","buttonRow","table","_deleteDialogTable","readOnly","deleteCheckedButton","each","decideSelectedFields","cancelButton","show","onclick","event","target","colName","thead","tbody","tr","deleteButton","THIS","isArray","derivativeJson","wellData","selectedSubFields","curMultiplexVals","isEmptyObject","k","parseFloat","sort","a","b","refDerivativeIndex","referenceDerivative","arr","wholeNoTiles","wholePercentage","tileIndex","completion","checkCompletion","floor","overLayTextContainer","multiplexStatus","fabricEvents","colorToIndex","startCoords","y","_clickCoords","rect","getBoundingClientRect","clientX","clientY","getPlates","selecting","coords","areas","_wellToCoords","_coordsToRect","_coordsToWell","shiftKey","_rectToArea","setSelection","endCoords","area","_areasToTiles","_setSelectedTiles","_setFocalWellRect","activeElement","blur","flag","locToAddress","r","c","addressAllowToEdit","setFieldsDisabled","_areaToRect","_wellToArea","focalWellRect","selectedTiles","_getSelectedWells","_getCommonFields","referenceWell","referenceFields","fields","refArr","agrArr","containsObject","inArray","obj","list","equality","evaluate","listKey","_getCommonWell","multiplexField","curMultipleVal","multipleVal","getDifferentWellsVals","wellsHash","wellId","differentWellsVals","commonWell","allFieldVal","fieldIdx","wellIdx","diffWellVal","curWellData","commonVal","curMultiVal","getWellSetAddressWithData","assets","interface","_createInterface","divIdentifier","topSection","topLeft","topRight","overLayContainer","_createOverLay","_createTabAtRight","_createTabs","_placePresetTabs","_setShortcuts","keyup","_handleShortcuts","_configureUndoRedoArray","addEventListener","copyCriteria","clearCriteria","preventDefault","pasteCriteria","keyCode","metaKey","redo","undo","loadPlate","sanitizeWell","sanitizeAreas","sanitized","setData","minCol","_coordIndex","maxCol","minRow","maxRow","max","_wellInArea","newWell","GET_PLATES","IS_READ_ONLY","IS_DISABLE_ADD_DELETE_WELL","GET_SELECTED_OBJECT","SETSELECTEDWELL","overlay","overLayButtonContainer","clearCriteriaButton","copyCriteriaButton","pasteCriteriaButton","undoButton","redoButton","hasWellUpdate","alert","widget","addressToLoc","layoutAddress","m","exec","toUpperCase","row_v","charCodeAt","locToIndex","t","addressToIndex","_rowKey","c1","c2","code","fromCharCode","indexToLoc","_create","numRows","numCols","component","className","isReadOnly","imgSrc","_init","addData","getTextDerivative","wellsData","textDerivative","textValWell","textFieldIdWell","textFieldVal","getWellsDifferences","isDisableAddDeleteWell","column_with_default_val","actionPointer","undoRedoArray","getSelectedObject","selectedObjects","getSelectedIndex","selectedObj","addressList","locMap","apply","preset","me","presets","wellAttrContainer","tabContainer","presetTabContainer","divText","title","presetButton","_selectPreset","allTabs","tabHead","tabIndex","_tabClickHandler","tabDataContainer","_addDataTabs","clickedTab","selectedTab","previouslyClickedTabIndex","clickedTabIndex","undoRedoManager","splice","shiftUndoRedo","pointerDiff","pointer","setUndoRedo","wellArea","reduce","tiles","_encodeArea","_encodeAreas","_decodeWell","wellAddress","match","adRx","RegExp","_decodeArea","areaAddress","split","_decodeAreas","areasAddress","abs","count","coord","center","hw","right","bottom"],"mappings":"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","file":"plate-map.min.js","sourcesContent":["var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.addDataOnChange = function() {\n    // This object is invoked when something in the tab fields change\n    return {\n\n      _addAllData: function(data) {\n        // Method to add data when something changes in the tabs. Its going to be tricky , just starting.\n        if (this.allSelectedObjects) {\n          var noOfSelectedObjects = this.allSelectedObjects.length;\n          var wells = [];\n          for (var objectIndex = 0; objectIndex < noOfSelectedObjects; objectIndex++) {\n            var tile = this.allSelectedObjects[objectIndex];\n            var well;\n            if (tile.index in this.engine.derivative) {\n              well = this.engine.derivative[tile.index];\n            } else {\n              well = $.extend(true, {}, this.defaultWell); \n              this.engine.derivative[tile.index] = well; \n            }\n            var processedData = this.processWellData(data, well, noOfSelectedObjects, wells);\n            wells = processedData.wells;\n            well = processedData.well;\n            var empty = this.engine.wellEmpty(well);\n            if (empty) {\n              if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {\n                var wellCopy = JSON.parse(JSON.stringify(well));\n                var defaultValue = this.emptyWellWithDefaultVal;\n                for (var key in defaultValue){\n                  if (key in wellCopy){\n                    wellCopy[key] = defaultValue[key];\n                    this._applyFieldData(key, defaultValue[key]);\n                  }\n                }\n                this.engine.derivative[tile.index] = wellCopy;\n              } else {\n                delete this.engine.derivative[tile.index];\n              }\n            }\n          }\n        }\n        // update multiplex remove all field\n        this._getAllMultipleVal(wells);\n        this.applyFieldWarning(wells);\n        // create well when default field is sent for the cases when user delete all fields during disabledNewDeleteWell mode\n        this._colorMixer();\n        this.derivativeChange();\n      },\n\n      processWellData: function(newData, curWell, noOfSelectedObjects, wellList) {\n\n        if (!wellList){\n          wellList = [];\n        }\n        for (var id in newData) {\n          var v;\n          if (newData[id] !== undefined && newData[id] !== null ) {\n            if (newData[id].multi){\n              var curData = newData[id];\n              var preData = curWell[id];\n              var newDt = this._getMultiData(preData, curData, id, noOfSelectedObjects);\n              // need to replace newData\n              v = JSON.parse(JSON.stringify(newDt));\n            } else {\n              v = JSON.parse(JSON.stringify(newData[id]));\n            }\n          } else {\n            v = JSON.parse(JSON.stringify(newData[id]));\n          }\n          curWell[id] = v;\n          wellList.push(curWell);\n        }\n\n        return {\n          well: curWell,\n          wells: wellList\n        }\n      },\n\n      _getMultiData: function(preData, curData, fieldId, noOfSelectedObjects) {\n        var addNew = curData.added;\n        var removed = curData.removed;\n        if (addNew) {\n          if (preData){\n            if (addNew.value) {\n              var add = true;\n              for (var listIdx in preData) {\n                var multiplexData = preData[listIdx];\n                // for cases when the add new data exist in well\n                if (multiplexData[fieldId].toString() === addNew.id.toString()) {\n                  add = false;\n                  // update subfield value\n                  preData = preData.map(function(val) {\n                    if (val[fieldId].toString() === addNew.id.toString()) {\n                      for (var subFieldId in val) {\n                        // over write previous data if only one well is selected\n                        if (subFieldId in addNew.value && subFieldId !== fieldId){\n                          if (noOfSelectedObjects === 1) {\n                            val[subFieldId] = addNew.value[subFieldId];\n                          } else if (addNew.value[subFieldId]) {\n                            val[subFieldId] = addNew.value[subFieldId];\n                          }\n                        }\n                      }\n                    }\n                    return val;\n                  })\n                }\n              }\n              if (add) {\n                preData.push(addNew.value);\n              }\n            } else if (preData.indexOf(addNew) < 0) {\n              preData.push(addNew);\n            }\n          } else {\n            preData = [];\n            if (addNew.value) {\n              preData.push(addNew.value);\n            } else if (addNew){\n              preData.push(addNew);\n            }\n          }\n        }\n\n        var removeListIndex = function(preData, removeIndex) {\n          var newPreData = [];\n          for (var idx in preData) {\n            if (parseInt(idx) !== parseInt(removeIndex)){\n              newPreData.push(preData[idx]);\n            }\n          }\n          return newPreData;\n        };\n\n        if (removed) {\n          var removeIndex;\n          // for multiplex field\n          if (removed.value) {\n            for (var listIdx in preData) {\n              var multiplexData = preData[listIdx];\n              if (multiplexData[fieldId].toString() === removed.id.toString()) {\n                removeIndex = listIdx;\n              }\n            }\n            // remove nested element\n            preData = removeListIndex(preData, removeIndex);\n          } else {\n            if (preData){\n              removeIndex = preData.indexOf(removed);\n              if (removeIndex >= 0) {\n                preData = removeListIndex(preData, removeIndex);\n              }\n            }\n          }\n        }\n        if (preData && (preData.length == 0)) {\n          preData = null; \n        }\n        return preData\n      },\n\n      _colorMixer: function() {\n        if (!this.undoRedoActive) {\n            var data = this.createObject();\n            this.addToUndoRedo(data);\n        }\n        this.engine.searchAndStack(); \n        this.engine.applyColors();\n        this.mainFabricCanvas.renderAll();\n      },\n\n      derivativeChange: function(){\n          this._trigger(\"updateWells\", null, this.createObject());\n      },\n\n      createObject: function() {\n        var derivative = $.extend(true, {}, this.engine.derivative); \n        var checkboxes = this.globalSelectedAttributes.slice(); \n        var selectedAreas = this.selectedAreas.slice(); \n        var focalWell = this.focalWell;\n\n        return {\n          \"derivative\": derivative,\n          \"checkboxes\": checkboxes,\n          \"selectedAreas\": selectedAreas,\n          \"focalWell\": focalWell,\n          \"requiredField\": this.requiredField\n        };\n      }\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.addDataToFields = function() {\n\n    return {\n\n      _addDataToTabFields: function(values) {\n        // Configure how data is added to tab fields\n        for (var id in values) {\n          this._applyFieldData(id, values[id]);\n        }\n      },\n\n      _applyFieldData: function(id, v) {\n        this.fieldMap[id].setValue(v); \n      }\n    }\n  }\n})(jQuery, fabric)","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.addTabData = function() {\n\n    return {\n\n      fieldList: [], \n      fieldMap: {},\n      autoId: 1,\n\n      _addTabData: function() {\n          // Here we may need more changes because attributes format likely to change\n          var tabData = this.options.attributes.tabs;\n          var that = this;\n          this.requiredField = [];\n          var multiplexFieldArray = [];\n          tabData.forEach(function (tab, tabPointer) {\n            if (tab[\"fields\"]) {\n              var tabFields = tab[\"fields\"];\n              var fieldArray = [];\n              var fieldArrayIndex = 0;\n              // Now we look for fields in the json\n              for (var field in tabFields) {\n                var data = tabFields[field];\n\n                if (!data.id) {\n                  data.id = \"Auto\" + that.autoId++;\n                  console.log(\"Field autoassigned id \" + data.id);\n                }\n                if (!data.type) {\n                  data.type = \"text\";\n                  console.log(\"Field \" + data.id + \" autoassigned type \" + data.type);\n                }\n\n                var field_val;\n                if (data.type === \"multiplex\") {\n                  field_val = that._makeMultiplexField(data, tabPointer, fieldArray);\n                  multiplexFieldArray.push(field_val);\n                } else {\n                  field_val = that._makeRegularField(data, tabPointer, fieldArray, true);\n                  if (data.type === \"multiselect\") {\n                    multiplexFieldArray.push(field_val);\n                  }\n                };\n              }\n\n              that.allDataTabs[tabPointer][\"fields\"] = fieldArray;\n            } else {\n              console.log(\"unknown format in field initialization\");\n            }\n          });\n          that.multipleFieldList = multiplexFieldArray;\n      },\n\n      _makeSubField: function (data, tabPointer, fieldArray) {\n        var that = this;\n        if (!data.id) {\n          data.id = \"Auto\" + that.autoId++;\n          console.log(\"Field autoassigned id \" + data.id);\n        }\n        if (!data.type) {\n          data.type = \"text\";\n          console.log(\"Field \" + data.id + \" autoassigned type \" + data.type);\n        }\n        var wrapperDiv = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-default-field\");\n        var wrapperDivLeftSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-left-side\");\n        var wrapperDivRightSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-right-side\");\n        var nameContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-name\").text(data.name);\n        var fieldContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-container\");\n\n        $(wrapperDivRightSide).append(nameContainer);\n        $(wrapperDivRightSide).append(fieldContainer);\n        $(wrapperDiv).append(wrapperDivLeftSide);\n        $(wrapperDiv).append(wrapperDivRightSide);\n        $(that.allDataTabs[tabPointer]).append(wrapperDiv);\n\n        var field = {\n          id: data.id,\n          name: data.name,\n          root: wrapperDiv,\n          data: data,\n          required: data.required || false\n        };\n\n        fieldArray.push(field);\n        that.fieldMap[data.id] = field;\n\n        return field;\n      },\n\n      _makeRegularField: function (data, tabPointer, fieldArray, checkbox){\n          var that = this;\n          var wrapperDiv = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-default-field\");\n          var wrapperDivLeftSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-left-side\");\n          var wrapperDivRightSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-right-side \");\n          var nameContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-name\").text(data.name);\n          var fieldContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-container\");\n\n          wrapperDivRightSide.append(nameContainer);\n          wrapperDivRightSide.append(fieldContainer);\n          wrapperDiv.append(wrapperDivLeftSide);\n          wrapperDiv.append(wrapperDivRightSide);\n          that.allDataTabs[tabPointer].append(wrapperDiv);\n\n          var field = {\n            id: data.id,\n            name: data.name,\n            root: wrapperDiv,\n            data: data,\n            required: data.required\n          };\n\n          if (field.required) {\n            that.requiredField.push(field.id);\n          }\n\n          fieldArray.push(field);\n          that.fieldList.push(field);\n          that.fieldMap[field.id] = field;\n\n          // Adding checkbox\n          if (checkbox) {\n            that._addCheckBox(field);\n          }\n          that._createField(field);\n\n          field.onChange = function () {\n            var v = field.getValue();\n            var data = {};\n            data[field.id] = v;\n            that._addAllData(data);\n          };\n          return field;\n      },\n\n      _makeMultiplexField: function (data, tabPointer, fieldArray) {\n        var that = this;\n        var wrapperDiv = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-default-field\");\n        var wrapperDivLeftSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-left-side\");\n        var wrapperDivRightSide = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-right-side \");\n        var nameContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-name\").text(data.name);\n        var fieldContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-container\");\n\n        wrapperDivRightSide.append(nameContainer);\n        wrapperDivRightSide.append(fieldContainer);\n        wrapperDiv.append(wrapperDivLeftSide);\n        wrapperDiv.append(wrapperDivRightSide);\n        that.allDataTabs[tabPointer].append(wrapperDiv);\n\n        var field = {\n          id: data.id,\n          name: data.name,\n          root: wrapperDiv,\n          data: data,\n          required: data.required\n        };\n\n        fieldArray.push(field);\n        that.fieldList.push(field);\n        that.fieldMap[data.id] = field;\n\n        var subFieldList = [];\n        //create subfields\n        var requiredSubField = [];\n        for (var subFieldKey in data.multiplexFields) {\n          var subFieldData = data.multiplexFields[subFieldKey];\n          var subField = that._makeSubField(subFieldData, tabPointer, fieldArray);\n          subFieldList.push(subField);\n\n          // stores required  subField\n          if (subFieldData.required) {\n            requiredSubField.push(subField.id);\n          }\n        }\n\n        //store required field\n        if (field.required || requiredSubField.length) {\n          this.requiredField.push ({\n            multiplexId: field.id,\n            subFields: requiredSubField\n          });\n        }\n\n        field.subFieldList = subFieldList;\n        that._createField(field);\n        that._addCheckBox(field);\n\n        subFieldList.forEach(function (subfield) {\n          subfield.mainMultiplexField = field;\n          fieldArray.push(subfield);\n          that._createField(subfield);\n          that._addCheckBox(subfield);\n          delete that.defaultWell[subfield.id];\n          // overwrite subField setvalue\n          subfield.onChange = function () {\n            var v = subfield.getValue();\n            var mainRefField = subfield.mainMultiplexField;\n            var curId = mainRefField.singleSelectValue();\n            //var curDataLs = mainRefField.detailData;\n            var curVal = {};\n            curVal[mainRefField.id] = curId;\n            //append subfields\n            curVal[subfield.id] = v;\n            var returnVal = {\n              id: curId,\n              value: curVal\n            };\n\n            field._changeMultiFieldValue(returnVal, null);\n            var curDataLs = mainRefField.detailData;\n            if (curDataLs !== null) {\n              curId = mainRefField.singleSelectValue(); \n              curDataLs = curDataLs.map(function(curData) {\n                if (curData[mainRefField.id] === curId) {\n                  curData[subfield.id] = v;\n                }\n                return curData;\n              });\n            }\n            mainRefField.detailData = curDataLs;\n          };\n\n        });\n\n        field.getValue = function(){\n          var v = field.input.select2('data');\n          if (v.length) {\n            return v.map(function (i) {\n              return i.id;\n            });\n          }\n          return null;\n        };\n\n        return field;\n      }\n    }\n  }\n\n})(jQuery, fabric);\n","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.addWarningMsg = function () {\n    // For those check boxes associated with every field in the tab\n    return {\n      fieldWarningMsg: function (field, text, include) {\n        var that = this;\n        var imgId = \"fieldWarning\" + field.id;\n        var img = $(\"<span>\").html(that._assets.warningImg).attr(\"id\", imgId).addClass(\"plate-field-warning-image\");\n        //field.root.find(\".plate-setup-tab-name\").append('<img id=\"theImg\" src=\"theImg.png\" />')\n        if (include) {\n          if (field.root.find(\"#\" + imgId).length <= 0){\n            field.root.find(\".plate-setup-tab-name\").text(\" \" + field.name);\n            field.root.find(\".plate-setup-tab-name\").prepend(img);\n\n            var popText = $(\"<div/>\").addClass(\"pop-out-text\");\n            popText.text(text);\n            field.root.find(\".plate-setup-tab-name\").append(popText);\n\n            $(\"#\" + imgId).hover(function (e) {\n              popText[0].style.display = 'flex';\n            }, function () {\n              popText.hide();\n            });\n          }\n\n\n        } else {\n          if (field.root.find(\"#\" + imgId).length > 0) {\n            field.root.find(\".plate-setup-tab-name\").text(field.name);\n            $(\"#\" + imgId).remove();\n          }\n        }\n      },\n\n      removeWarningMsg: function (field, text, include) {\n        var that = this;\n        var imgId = \"fieldWarning\" + field.id;\n        var img = $(\"<span>\").html(that._assets.warningImg).attr(\"id\", imgId).addClass(\"plate-field-warning-image\");\n        //field.root.find(\".plate-setup-tab-name\").append('<img id=\"theImg\" src=\"theImg.png\" />')\n        if (include) {\n          field.root.find(\".plate-setup-tab-name\").append(img);\n\n          var popText = $(\"<div/>\").addClass(\"pop-out-text\");\n          popText.text(text);\n          field.root.find(\".plate-setup-tab-name\").append(popText);\n\n          $(\"#\" + imgId).hover(function (e) {\n            popText[0].style.display = 'inline-block';\n          }, function () {\n            popText.hide();\n          });\n\n        } else {\n          $(\"#\" + imgId).remove();\n          if (field.root.find(\"#\" + imgId).length > 0) {\n            //field.root.find(\".plate-setup-tab-name\").remove(img);\n            $(\"#\" + imgId).remove();\n          }\n        }\n      },\n\n      applyFieldWarning: function(wells) {\n        var that = this;\n        var req = 0;\n        var fill = 0;\n        var fieldData = {};\n        that.fieldList.forEach(function(field){\n          fieldData[field.id] = [];\n        });\n        wells.forEach(function(well){\n          if (!that.engine.wellEmpty(well)){\n            for (var fieldId in fieldData) {\n              if (fieldId in well) {\n                fieldData[fieldId].push(well[fieldId]);\n              } else {\n                fieldData[fieldId].push(null);\n              }\n            }\n          }\n        });\n        for (var i = 0; i < that.fieldList.length; i++) {\n          var field = that.fieldList[i];\n          if (field.applyMultiplexSubFieldColor){\n            field.applyMultiplexSubFieldColor(fieldData[field.id]);\n          } else {\n            if (field.required) {\n              var include = false;\n              fieldData[field.id].forEach(function(val){\n                // for multiselect\n                if (val instanceof Array) {\n                  if (val.length === 0) {\n                    include = true;\n                  }\n                } else {\n                  if (val === null) {\n                    include = true;\n                  }\n                }\n              });\n              //field.root.find(\".plate-setup-tab-name\").css(\"background\", color);\n              that.fieldWarningMsg(field, \"required field\", include);\n            }\n          }\n        }\n      }\n    }\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.bottomTable = function() {\n    // for bottom table\n    return {\n      _bottomScreen: function() {\n        this.bottomContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-bottom-container\");\n        this.bottomTableContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-bottom-table-container\");\n        this.bottomTable = this._createElement(\"<table></table>\").addClass(\"plate-setup-bottom-table\");\n        this.bottomTableContainer.append(this.bottomTable);\n        this.bottomContainer.append(this.bottomTableContainer);\n        this.container.append(this.bottomContainer);\n      },\n\n      addBottomTableHeadings: function() {\n\n        this.bottomRow = this._createElement(\"<tr></tr>\");\n\n        var singleField = this._createElement(\"<th></th>\")\n          .text(\"Group\");\n        this.bottomRow.prepend(singleField);\n        // Now we append all the captions at the place.\n        this.bottomTable.empty();\n        this.bottomTable.append(this.bottomRow);\n\n        this.rowCounter = 1;\n\n        for (var i = 0; i < this.globalSelectedAttributes.length; i++) {\n          var attr = this.globalSelectedAttributes[i];\n          var field = this.fieldMap[attr];\n          var singleField = this._createElement(\"<th></th>\").text(field.name);\n          this.bottomRow.append(singleField);\n          this.rowCounter = this.rowCounter + 1;\n        }\n\n        this.adjustFieldWidth(this.bottomRow);\n      },\n\n      tileAttrText: function(tile, attr) {\n        var well = this.engine.derivative[tile.index];\n        var field = this.fieldMap[attr];\n        return field.getText(well[attr]);\n      },\n\n      addBottomTableRow: function(color, singleStack) {\n        var that = this;\n        var modelTile = this.allTiles[singleStack[0]];\n        var row = this._createElement(\"<tr></tr>\");\n        var plateIdDiv = this._createElement(\"<td></td>\").addClass(\"plate-setup-bottom-id\");\n        var numberText = this._createElement(\"<button/>\");\n        numberText.addClass(\"plate-setup-color-text\");\n        numberText.text(color);\n        plateIdDiv.append(numberText);\n\n        numberText.click(function(evt){\n          var addressToSelect = singleStack.map(function(addressIdx){\n            return that.indexToAddress(addressIdx)\n          });\n          if (evt.ctrlKey) {\n            that.getSelectedAddress().forEach(function(val){\n              if (addressToSelect.indexOf(val) < 0){\n                addressToSelect.push(val);\n              }\n            })\n          }\n          that.setSelectedWell(addressToSelect);\n          that._trigger(\"selectedWells\", null, {selectedAddress: that.getSelectedAddress()});\n        });\n\n        if (color > 0) {\n          color = ((color - 1) % (this.colorPairs.length - 1)) + 1;\n        }\n        var colorStops = this.colorPairs[color];\n\n        plateIdDiv.css(\"background\", \"linear-gradient(to right, \" + colorStops[0] + \" , \" + colorStops[1] + \")\");\n\n        row.append(plateIdDiv);\n\n        for (var i = 0; i < this.globalSelectedAttributes.length; i++) {\n          var attr = this.globalSelectedAttributes[i];\n          var text = this.tileAttrText(modelTile, attr);\n          var dataDiv = this._createElement(\"<td></td>\").text(text);\n          row.append(dataDiv);\n        }\n        this.bottomTable.append(row);\n        this.adjustFieldWidth(row);\n      },\n\n      bottomForFirstTime: function() {\n        this.addBottomTableHeadings();\n        // This is executed for the very first time.. !\n        var row = this._createElement(\"<tr></tr>\");\n\n        var colorStops = this.colorPairs[0];\n        var plateIdDiv = this._createElement(\"<td></td>\");\n        plateIdDiv.css(\"background\", \"-webkit-linear-gradient(left, \" + colorStops[0] + \" , \" + colorStops[1] + \")\");\n        row.append(plateIdDiv);\n        this.bottomTable.append(row);\n        this.createExportButton();\n      },\n\n      adjustFieldWidth: function(row) {\n\n        var length = this.rowCounter;\n        if ((length) * 150 > 1024) {\n          row.css(\"width\", (length) * 152 + \"px\");\n        }\n      },\n\n      downloadCSV: function(csv, filename) {\n        var csvFile;\n        var downloadLink;\n\n        // CSV file\n        csvFile = new Blob([csv], {\n          type: \"text/csv\"\n        });\n\n        // Download link\n        downloadLink = document.createElement(\"a\");\n\n        // File name\n        downloadLink.download = filename;\n\n        // Create a link to the file\n        downloadLink.href = window.URL.createObjectURL(csvFile);\n\n        // Hide download link\n        downloadLink.style.display = \"none\";\n\n        // Add the link to DOM\n        document.body.appendChild(downloadLink);\n\n        // Click download link\n        downloadLink.click();\n      },\n\n      exportData: function(format) {\n        var data = [];\n        var rows = document.querySelectorAll(\"table tr\");\n\n        var colorLocMap = {};\n        var colorLocIdxMap = this.engine.stackUpWithColor;\n        var dim = this.getDimensions();\n        var that = this;\n        for (var colorIdx in colorLocIdxMap) {\n          colorLocMap[colorIdx] = colorLocIdxMap[colorIdx].map(function (locIdx) {\n            return that.indexToAddress(locIdx, dim);\n          })\n        }\n\n        for (var i = 0; i < rows.length; i++) {\n          var row = [],\n            cols = rows[i].querySelectorAll(\"td, th\");\n\n          for (var j = 0; j < cols.length; j++) {\n            var v = \"\";\n            if (cols[j].innerText) {\n              if (format === \"csv\") {\n                v = '\"' + cols[j].innerText.replace(/\"/g, '\"\"') + '\"';\n              } else {\n                v = cols[j].innerText;\n              }\n            }\n            row.push(v);\n\n            // add location column\n            if (i === 0 && j === 0) {\n              if (format === \"csv\") {\n                row.push('\"Location\"');\n              } else if (format === 'clipboard') {\n                row.push(\"Location\");\n              }\n\n            }\n            if (i !== 0 && j === 0) {\n              var loc = '';\n              if (colorLocMap[parseInt(cols[j].innerText)]) {\n                if (format === \"csv\") {\n                  loc = '\"' + colorLocMap[parseInt(cols[j].innerText)].join(\",\") + '\"';\n                } else if (format === 'clipboard') {\n                  loc = colorLocMap[parseInt(cols[j].innerText)].join(\",\");\n                }\n              }\n              row.push(loc);\n            }\n          }\n\n          if (format === \"csv\") {\n            data.push(row.join(\",\"));\n          } else if (format === 'clipboard') {\n            data.push(row.join(\"\\t\"));\n            //data.push(row);   // for text type\n          }\n\n        }\n        if (format === \"csv\") {\n          // Download CSV file\n          this.downloadCSV(data.join(\"\\n\"), 'table.csv');\n        } else if (format === 'clipboard') {\n          //return formatTableToString(data);   // for text type\n          return data.join(\"\\n\");\n        }\n      },\n\n      createExportButton: function() {\n        var that = this;\n        var overlayContainer = $(\"<div>\").addClass(\"plate-setup-bottom-control-container\");\n\n        var descriptionDiv = $(\"<div>\").addClass(\"plate-setup-overlay-text-container\");\n        descriptionDiv.text(\"Color groups\");\n        overlayContainer.append(descriptionDiv);\n\n        var buttonContainer = $(\"<div>\").addClass(\"plate-setup-overlay-bottom-button-container\");\n\n        // create export csv option\n        var exportButton = $(\"<button/>\").addClass(\"plate-setup-button\");\n        exportButton.text(\"Export CSV\");\n        buttonContainer.append(exportButton);\n\n        exportButton.click(function() {\n          that.exportData('csv');\n          exportButton.text(\"Exported\");\n          exportButton[0].classList.remove(\"plate-setup-button\");\n          exportButton.addClass(\"plate-setup-clicked-button\");\n          setTimeout(resetExportText, 3000);\n        });\n\n        function resetExportText() {\n          exportButton.text(\"Export CSV\");\n          exportButton[0].classList.remove(\"plate-setup-clicked-button\");\n          exportButton.addClass(\"plate-setup-button\");\n        }\n\n        // creat clipboard option, CLipboard is an external js file located in vendor/asset/javascripts\n        var clipboardButton = $(\"<button/>\").addClass(\"plate-setup-button\");\n        clipboardButton.text(\"Copy To Clipboard\");\n        buttonContainer.append(clipboardButton);\n\n        var clipboard = new ClipboardJS(clipboardButton.get(0), {\n          text: function() {\n            return that.exportData(\"clipboard\");\n          }\n        });\n\n        clipboard.on('success', function(e) {\n          clipboardButton.text(\"Copied as tab-delimited format\");\n          clipboardButton[0].classList.remove(\"plate-setup-button\");\n          clipboardButton.addClass(\"plate-setup-clicked-button\");\n          setTimeout(resetClipboardText, 3000);\n        });\n\n        function resetClipboardText() {\n          clipboardButton.text(\"Copy To Clipboard\");\n          clipboardButton[0].classList.remove(\"plate-setup-clicked-button\");\n          clipboardButton.addClass(\"plate-setup-button\");\n        }\n\n        clipboard.on('error', function(e) {\n          clipboardButton.text(\"Failed to copy table to clipboard: browser may be incompatible\");\n          setTimeout(resetClipboardText, 3000);\n        });\n\n        overlayContainer.append(buttonContainer);\n        $(\".plate-setup-bottom-container\").prepend(overlayContainer);\n      }\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.canvas = function() {\n    //\n    return {\n\n      allSelectedObjects: null, // Contains all the selected objets, when click and drag.\n\n      allPreviouslySelectedObjects: null,\n\n      colorPointer: 0,\n\n      goldenRatio: 0.618033988749895,\n\n      _createCanvas: function() {\n        this.normalCanvas = this._createElement(\"<canvas>\").attr(\"id\", \"DNAcanvas\");\n        $(this.canvasContainer).append(this.normalCanvas);\n      },\n\n      _initiateFabricCanvas: function() {\n        var w = this.canvasContainer.width(); \n        var h = this.canvasContainer.height(); \n\n        this._setCanvasArea(w, h);\n\n        this.mainFabricCanvas = new fabric.Canvas('DNAcanvas', {\n            backgroundColor: '#f5f5f5',\n            selection: false,\n            stateful: false,\n            hoverCursor: \"pointer\",\n            renderOnAddRemove: false,\n          })\n          .setWidth(w)\n          .setHeight(h);\n      },\n\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.checkBox = function() {\n    // For those check boxes associated with every field in the tab\n    return {\n\n      globalSelectedAttributes: [],\n\n      _addCheckBox: function(field) {\n        var checkImage = $(\"<span>\").html(this._assets.dontImg).addClass(\"plate-setup-tab-check-box bg-light\")\n          .data(\"clicked\", false);\n        checkImage.data(\"linkedFieldId\", field.id);\n        field.root.find(\".plate-setup-tab-field-left-side\").empty().append(checkImage);\n        this._applyCheckboxHandler(checkImage); // Adding handler for change the image when clicked\n        field.checkbox = checkImage;\n      },\n\n      _applyCheckboxHandler: function(checkBoxImage) {\n        // We add checkbox handler here, thing is it s not checkbox , its an image and we change\n        // source\n        var that = this;\n        checkBoxImage.click(function(evt, machineClick) {\n          var checkBox = $(this);\n\n          var changes = {};\n          changes[checkBox.data(\"linkedFieldId\")] = !checkBox.data(\"clicked\");\n\n          that.changeCheckboxes(changes);\n        });\n      },\n\n      changeSubFieldsCheckboxes: function(field, changes) {\n        var that = this;\n        var subFieldToInclude = [];\n\n        field.subFieldList.forEach(function(subField) {\n          var checkImage = subField.checkbox;\n          var fieldId = checkImage.data(\"linkedFieldId\");\n          var clicked = checkImage.data(\"clicked\");\n          if (fieldId in changes) {\n            clicked = Boolean(changes[fieldId]);\n          }\n          checkImage.data(\"clicked\", clicked);\n          if (clicked) {\n            checkImage.html(that._assets.doImg);\n            subFieldToInclude.push(subField.id);\n          } else {\n            checkImage.html(that._assets.dontImg);\n          }\n        });\n        return subFieldToInclude;\n      },\n\n      changeCheckboxes: function(changes) {\n        var gsa = [];\n        var multiplexCheckedSubField = {};\n        for (var i = 0; i < this.fieldList.length; i++) {\n          var field = this.fieldList[i];\n          if (field.checkbox) {\n            if (field.subFieldList) {\n              multiplexCheckedSubField[field.id] = this.changeSubFieldsCheckboxes(field, changes);\n            }\n\n            var checkImage = field.checkbox;\n            var fieldId = checkImage.data(\"linkedFieldId\");\n            var clicked = checkImage.data(\"clicked\");\n            if (fieldId in changes) {\n              clicked = Boolean(changes[fieldId]);\n            }\n            checkImage.data(\"clicked\", clicked);\n            if (clicked) {\n              gsa.push(fieldId);\n              checkImage.html(this._assets.doImg);\n            } else {\n              checkImage.html(this._assets.dontImg);\n            }\n          }\n        }\n        this.globalSelectedMultiplexSubfield = multiplexCheckedSubField;\n        this.globalSelectedAttributes = gsa;\n        this._clearPresetSelection();\n        this._colorMixer();\n      },\n\n      setSubFieldCheckboxes: function(field, fieldIds) {\n        var that = this;\n        var subFieldToInclude = [];\n        field.subFieldList.forEach(function(subField) {\n          var checkImage = subField.checkbox;\n          var fieldId = checkImage.data(\"linkedFieldId\");\n          var clicked = fieldIds.indexOf(fieldId) >= 0;\n          checkImage.data(\"clicked\", clicked);\n          if (clicked) {\n            checkImage.html(that._assets.doImg);\n            subFieldToInclude.push(subField.id);\n          } else {\n            checkImage.html(that._assets.dontImg);\n          }\n        });\n        return subFieldToInclude;\n      },\n\n      setCheckboxes: function(fieldIds) {\n        fieldIds = fieldIds || [];\n        var gsa = [];\n        var multiplexCheckedSubField = {};\n\n        for (var i = 0; i < this.fieldList.length; i++) {\n          var field = this.fieldList[i];\n          if (field.checkbox) {\n            // special handling for multiplex field\n            if (field.subFieldList) {\n              multiplexCheckedSubField[field.id] = this.setSubFieldCheckboxes(field, fieldIds);\n            }\n\n            var checkImage = field.checkbox;\n            var fieldId = checkImage.data(\"linkedFieldId\");\n            var clicked = fieldIds.indexOf(fieldId) >= 0;\n            checkImage.data(\"clicked\", clicked);\n            if (clicked) {\n              gsa.push(fieldId);\n              checkImage.html(this._assets.doImg);\n            } else {\n\n              checkImage.html(this._assets.dontImg);\n            }\n          }\n        }\n        this.globalSelectedMultiplexSubfield = multiplexCheckedSubField;\n        this.globalSelectedAttributes = gsa;\n        this._clearPresetSelection();\n        this._colorMixer();\n      }\n\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.colorManager = function() {\n\n    return {\n        // See these are color pairs for the gradient.\n      colorPairs: [\n        [\"#e6e6e6\", \"#808080\"],\n        [\"#66e8ff\", \"#0082c8\"],\n        [\"#ff7fb1\", \"#e6194b\"],\n        [\"#a2ffb1\", \"#3cb44b\"],\n        [\"#f784ff\", \"#911eb4\"],\n        [\"#ffe897\", \"#f58231\"],\n        [\"#6666ff\", \"#0000FF\"],\n        [\"#ffff7f\", \"#ffe119\"],\n        [\"#acffff\", \"#46f0f0\"],\n        [\"#ff98ff\", \"#f032e6\"],\n        [\"#ffffa2\", \"#d2f53c\"],\n        [\"#ffffff\", \"#fabebe\"],\n        [\"#66e6e6\", \"#008080\"],\n        [\"#ffffff\", \"#e6beff\"],\n        [\"#ffd48e\", \"#aa6e28\"],\n        [\"#e66666\", \"#800000\"],\n        [\"#ffffff\", \"#aaffc3\"],\n        [\"#e6e666\", \"#808000\"],\n        [\"#ffffff\", \"#ffd8b1\"],\n        [\"#66a9ef\", \"#004389\"],\n        [\"#ff6672\", \"#a7000c\"],\n        [\"#66db72\", \"#00750c\"],\n        [\"#b866db\", \"#520075\"],\n        [\"#ffa966\", \"#b64300\"],\n        [\"#ffff66\", \"#c0a200\"],\n        [\"#6dffff\", \"#07b1b1\"],\n        [\"#ff66ff\", \"#b100a7\"],\n        [\"#f9ff66\", \"#93b600\"],\n        [\"#ffe5e5\", \"#bb7f7f\"],\n        [\"#66a7a7\", \"#004141\"],\n        [\"#ffe5ff\", \"#a77fc0\"],\n        [\"#d19566\", \"#6b2f00\"],\n        [\"#ffffef\", \"#c0bb89\"],\n        [\"#d1ffea\", \"#6bc084\"],\n        [\"#a7a766\", \"#414100\"],\n        [\"#ffffd8\", \"#c09972\"],\n        [\"#a5ffff\", \"#3fc1ff\"],\n        [\"#ffbef0\", \"#ff588a\"],\n        [\"#e1fff0\", \"#7bf38a\"],\n        [\"#ffc3ff\", \"#d05df3\"],\n        [\"#ffffd6\", \"#ffc170\"],\n        [\"#a5a5ff\", \"#3f3fff\"],\n        [\"#ffffbe\", \"#ffff58\"],\n        [\"#ebffff\", \"#85ffff\"],\n        [\"#ffd7ff\", \"#ff71ff\"],\n        [\"#a5ffff\", \"#3fbfbf\"],\n        [\"#ffffcd\", \"#e9ad67\"],\n        [\"#ffa5a5\", \"#bf3f3f\"],\n        [\"#ffffa5\", \"#bfbf3f\"]\n      ]\n    }\n  }\n\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.createCanvasElements = function() {\n    // this class manages creating all the elements within canvas\n    return {\n\n      scaleFactor: 1, \n\n      baseSizes: {\n        spacing: 48, \n        tile_radius: 22, \n        center_radius_complete: 10, \n        center_radius_incomplete: 14, \n        label_size: 14, \n        label_spacing: 24, \n        text_size: 13,\n        stroke: 0.5, \n        gap: 2\n      }, \n\n      _setCanvasArea: function(w, h) {\n        this.scaleFactor = Math.min(\n           h / (this.dimensions.rows * this.baseSizes.spacing + this.baseSizes.label_spacing), \n           w / (this.dimensions.cols * this.baseSizes.spacing + this.baseSizes.label_spacing));\n\n        var sizes = {}\n        for (var prop in this.baseSizes) {\n          sizes[prop] = this.baseSizes[prop] * this.scaleFactor; \n        }\n        this.sizes = sizes; \n      }, \n\n      _canvas: function() {\n        // Those 1,2,3 s and A,B,C s\n        this._fixRowAndColumn();\n\n        // All those circles in the canvas.\n        this._putCircles();\n      },\n\n      _fixRowAndColumn: function() {\n        var cols = this.dimensions.cols;\n        var rows = this.dimensions.rows;\n\n        var spacing = this.sizes.spacing;\n        var d1 = this.sizes.label_spacing / 2;\n        var d2 = this.sizes.label_spacing + this.sizes.spacing / 2; \n        var fontSize = this.sizes.label_size; \n\n        // For column\n        var top = d1; \n        var left = d2;  \n        for (var i = 1; i <= cols; i++) {\n          var tempFabricText = new fabric.IText(i.toString(), {\n            fill: 'black',\n            originX: 'center',\n            originY: 'center',\n            fontSize: fontSize,\n            top: top,\n            left: left,\n            fontFamily: '\"Roboto\", Arial, sans-serif',\n            selectable: false,\n            fontWeight: \"400\"\n          });\n          left += spacing; \n\n          this.mainFabricCanvas.add(tempFabricText);\n        }\n\n        // for row\n        top = d2; \n        left = d1; \n        for (var i = 1; i <= rows; i++) {\n          var tempFabricText = new fabric.IText(this.rowIndex[i-1], {\n            fill: 'black',\n            originX: 'center',\n            originY: 'center',\n            fontSize: fontSize,\n            top: top,\n            left: left,\n            fontFamily: '\"Roboto\", Arial, sans-serif',\n            selectable: false,\n            fontWeight: \"400\"\n          });\n          top += spacing; \n\n          this.mainFabricCanvas.add(tempFabricText);\n        }\n      },\n\n      _putCircles: function() {\n        var cols = this.dimensions.cols;\n        var rows = this.dimensions.rows;\n\n        var tileCounter = 0;\n        for (var row = 0; row < rows; row++) {\n          for (var col = 0; col < cols; col++) {\n            var index = this.allTiles.length; \n            var tile = this._createTile(row, col); \n            tile.index = tileCounter++; \n            this.allTiles.push(tile);\n            this.mainFabricCanvas.add(tile.background);\n            this.mainFabricCanvas.add(tile.highlight);\n            this.mainFabricCanvas.add(tile.circle);\n            this.mainFabricCanvas.add(tile.circleCenter);\n            this.mainFabricCanvas.add(tile.circleText);\n          }\n        }\n\n        this._addLargeRectangleOverlay();\n        this._fabricEvents();\n      },\n\n      _createTile: function (row, col) {\n        var tile = {}; \n\n        tile.visible = false; \n        tile.colorIndex = null; \n        tile.row = row; \n        tile.col = col; \n        tile.address = this.rowIndex[row] + (col + 1); \n\n        var top = (row + 1) * this.sizes.spacing;\n        var left = (col + 1) * this.sizes.spacing; \n\n        tile.background = new fabric.Circle({\n          top: top,\n          left: left,\n          radius: this.sizes.tile_radius,\n          originX: 'center',\n          originY: 'center',\n          hasControls: false,\n          hasBorders: false,\n          lockMovementX: true,\n          lockMovementY: true,\n          evented: false,\n        });\n\n        tile.background.setGradient(\"fill\", {\n          type: \"radial\",\n          x1: this.sizes.tile_radius, \n          x2: this.sizes.tile_radius, \n          y1: this.sizes.tile_radius + this.sizes.gap,\n          y2: this.sizes.tile_radius + this.sizes.gap,\n          r1: this.sizes.tile_radius - this.sizes.gap,\n          r2: this.sizes.tile_radius,\n          colorStops: {\n            0: 'rgba(0,0,0,0.1)',\n            1: 'rgba(0,0,0,0.2)'\n          }\n        });\n\n        tile.highlight = new fabric.Rect({\n          originX: 'center',\n          originY: 'center',\n          top: top,\n          left: left,\n          width: this.sizes.spacing,\n          height: this.sizes.spacing,\n          fill: \"rgba(0,0,0,0.4)\",\n          evented: false,\n          visible: false\n        });\n\n        tile.circle = new fabric.Circle({\n          originX: 'center',\n          originY: 'center',\n          top: top,\n          left: left,\n          radius: this.sizes.tile_radius,\n          stroke: 'gray',\n          strokeWidth: this.sizes.stroke,\n          evented: false, \n          visible: false\n        });\n\n        tile.circleCenter = new fabric.Circle({\n          originX: 'center',\n          originY: 'center',\n          top: top,\n          left: left,\n          radius: this.sizes.center_radius_incomplete,\n          fill: \"white\",\n          stroke: 'gray',\n          strokeWidth: this.sizes.stroke,\n          evented: false,\n          visible: false\n        });\n\n        tile.circleText = new fabric.IText(\"\", {\n          originX: 'center',\n          originY: 'center',\n          top: top,\n          left: left,\n          fill: 'black',\n          fontFamily: '\"Roboto\", Arial, sans-serif',\n          fontSize: this.sizes.text_size,\n          lockScalingX: true,\n          lockScalingY: true,\n          evented: false,\n          visible: false\n        });\n\n        return tile; \n      }, \n\n      setTileComplete: function (tile, complete) {\n        if (complete) {\n          tile.circleCenter.radius = this.sizes.center_radius_complete;\n          tile.circleText.fill = \"black\";\n          tile.circleText.fontWeight = 'normal';\n        } else {\n          tile.circleCenter.radius = this.sizes.center_radius_incomplete;\n          tile.circleText.fill = \"red\";\n          tile.circleText.fontWeight = 'bold';\n        }\n      }, \n\n      setTileVisible: function (tile, visible) {\n        tile.visible = visible;\n        tile.circle.visible = tile.visible;\n        tile.circleCenter.visible = tile.visible;\n        tile.circleText.visible = tile.visible;\n      },\n\n      setTileColor: function(tile, color, stackPointer) {\n        this.setTileVisible(tile, true);\n        tile.colorIndex = parseInt(color); \n        tile.circleText.text = String(tile.colorIndex);\n\n        if (color > 0) {\n          color = ((color - 1) % (this.colorPairs.length -1)) + 1;\n        }\n        var colorStops = this.colorPairs[color];\n\n        tile.circle.setGradient(\"fill\", {\n          y2: 2 * this.sizes.tile_radius,\n          colorStops: colorStops\n        });\n      },\n\n      _addLargeRectangleOverlay: function() {\n\n        this.overLay = new fabric.Rect({\n          width: 632,\n          height: 482,\n          left: 0,\n          top: 0,\n          opacity: 0.0,\n          originX: 'left',\n          originY: 'top',\n          lockMovementY: true,\n          lockMovementX: true,\n          selectable: false\n        });\n\n        this.mainFabricCanvas.add(this.overLay);\n      }\n    };\n  }\n})(jQuery, fabric);\n","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.createField = function() {\n    // It create those fields in the tab , there is 4 types of them.\n    return {\n\n      _createField: function(field) {\n        switch (field.data.type) {\n          case \"text\":\n            this._createTextField(field);\n            break;\n\n          case \"numeric\":\n            this._createNumericField(field);\n            break;\n\n          case \"select\":\n            this._createSelectField(field);\n            break;\n\n          case \"multiselect\":\n            this._createMultiSelectField(field);\n            break;\n\n          case \"boolean\":\n            this._createBooleanField(field);\n            break;\n\n          case \"multiplex\":\n            this._createMultiplexField(field);\n            break;\n        }\n      },\n\n      _createTextField: function(field) {\n        var id = field.id;\n        var that = this;\n        var input = this._createElement(\"<input>\").attr(\"id\", id)\n          .addClass(\"plate-setup-tab-input\");\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        that.defaultWell[id] = null;\n\n        field.parseValue = function(v) {\n          if (v) {\n            v = String(v);\n          } else {\n            v = null;\n          }\n          return v;\n        };\n\n        field.getValue = function() {\n          var v = input.val().trim();\n          if (v == \"\") {\n            v = null;\n          }\n          return v;\n        };\n\n        field.setValue = function(v) {\n          input.val(v);\n        };\n\n        field.getText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          return v;\n        };\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n        };\n\n        field.parseText = field.parseValue;\n\n        input.on(\"input\", function(e, generated) {\n          field.onChange();\n        });\n\n        field.input = input;\n      },\n\n      _createOpts: function(config) {\n        var opts = {\n          allowClear: true,\n          placeholder: \"select\",\n          minimumResultsForSearch: 10\n        };\n\n        if (config.options) {\n          opts.data = config.options;\n        } else if (config.query) {\n          var query = config.query;\n          if (config.delay) {\n            query = this._debounce(config.delay, query);\n          }\n          opts.query = query;\n        } else {\n          throw \"Must specify data or query\";\n        }\n        return opts;\n      },\n\n      _createSelectField: function(field) {\n        var id = field.id;\n        var that = this;\n        var input = this._createElement(\"<input/>\").attr(\"id\", id)\n          .addClass(\"plate-setup-tab-select-field\");\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        that.defaultWell[id] = null;\n\n        var opts = that._createOpts(field.data);\n        var optMap = {};\n        opts.data.forEach(function(opt) {\n          optMap[opt.id] = opt;\n        });\n\n        input.select2(opts);\n\n        field.parseValue = function(value) {\n          var v = value;\n\n          if (v == \"\") {\n            v = null;\n          }\n          if (v == null) {\n            return null;\n          }\n          if (v in optMap) {\n            return optMap[v].id;\n          } else {\n            throw \"Invalid value \" + value + \" for select field \" + id;\n          }\n        };\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n        };\n\n        field.getValue = function() {\n          var v = input.select2('data');\n          return v ? v.id : null;\n        };\n\n        field.setValue = function(v) {\n          if (v) {\n            v = optMap[v];\n          }\n          input.select2('data', v);\n        };\n\n        field.setOpts = function(v) {\n          input.select2('data', {});\n          opts.data = v || [];\n          input.select2(opts);\n        };\n\n        field.getText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          return optMap[v].text;\n        };\n\n        field.parseText = function(value) {\n          var v = value;\n\n          if (v == \"\") {\n            v = null;\n          }\n          if (v == null) {\n            return null;\n          }\n          if (v in optMap) {\n            return optMap[v].text;\n          } else {\n            throw \"Invalid text value \" + value + \" for select field \" + id;\n          }\n        };\n\n        input.on(\"change\", function(e, generated) {\n          field.onChange();\n        });\n\n        field.input = input;\n      },\n\n      _createMultiSelectField: function(field) {\n        var id = field.id;\n        var that = this;\n        var input = this._createElement(\"<input/>\").attr(\"id\", id)\n          .addClass(\"plate-setup-tab-multiselect-field\");\n        input.attr(\"multiple\", \"multiple\");\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        that.defaultWell[id] = null;\n\n        var separator = \",\";\n        var opts = that._createOpts(field.data);\n        opts.multiple = true;\n        var optMap = {};\n        opts.data.forEach(function(opt) {\n          optMap[opt.id] = opt;\n        });\n        input.select2(opts);\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n        };\n\n        field.parseValue = function(value) {\n          var v = value;\n          if (v && v.length) {\n            v = v.map(function(opt) {\n              if (opt in optMap) {\n                return optMap[opt].id;\n              } else {\n                throw \"Invalid value \" + opt + \" for multiselect field \" + id;\n              }\n            });\n          } else {\n            v = null;\n          }\n          return v;\n        };\n\n        field.setOpts = function(v) {\n          var allOpts = field.data.options;\n          var selectedVal = [];\n          for (var id in allOpts) {\n            var curOpts = allOpts[id];\n            if (v.indexOf(curOpts[\"id\"]) >= 0) {\n              selectedVal.push(curOpts);\n            }\n          }\n\n          opts.data = selectedVal;\n          input.select2(opts);\n        };\n\n        field.getValue = function() {\n          var v = input.select2('data');\n          if (v.length) {\n            return v.map(function(i) {\n              return i.id;\n            });\n          }\n          return null;\n        };\n\n        field.setValue = function(v) {\n          v = v || [];\n          v = v.map(function(i) {\n            return optMap[i];\n          });\n          input.select2('data', v);\n        };\n\n        field.getText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          if (v.length > 0) {\n            return v.map(function(v) {\n              return optMap[v].text\n            }).join(\"; \");\n          }\n          return \"\";\n        };\n\n        field.multiOnChange = function (added, removed) {\n          if (added) {\n            added = added.id.toString();\n          }\n          if (removed) {\n            removed = removed.id.toString();\n          }\n          var data = {\n          };\n          data[field.id] = {\n            multi: true,\n            added: added,\n            removed: removed\n          };\n\n          that._addAllData(data);\n        };\n\n        field.parseText = function(value){\n          var v = value;\n          if (v && v.length) {\n            v = v.map(function(opt) {\n              if (opt in optMap) {\n                return optMap[opt].text;\n              } else {\n                throw \"Invalid text value \" + opt + \" for multiselect field \" + id;\n              }\n            });\n          } else {\n            v = null;\n          }\n          return v;\n        };\n\n        input.on(\"change\", function(e, generated) {\n          var added = e.added;\n          var removed = e.removed;\n          //field.onChange();\n          field.multiOnChange(added, removed);\n        });\n\n        field.input = input;\n\n        that._createDeleteButton(field);\n      },\n\n      _createNumericField: function(field) {\n        var id = field.id;\n        var data = field.data;\n        var that = this;\n        var input = this._createElement(\"<input>\").addClass(\"plate-setup-tab-input\")\n          .attr(\"placeholder\", data.placeholder || \"\").attr(\"id\", id);\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        that.defaultWell[id] = null;\n\n        // Adding unit\n        var units = data.units || [];\n        var defaultUnit = data.defaultUnit || null;\n        var unitInput = null;\n        if (defaultUnit) {\n          if (units.length) {\n            if (units.indexOf(defaultUnit) < 0) {\n              defaultUnit = units[0];\n            }\n          } else {\n            units = [defaultUnit];\n          }\n        } else {\n          if (units.length) {\n            defaultUnit = units[0];\n          }\n        }\n\n        if (units.length) {\n          field.units = units;\n          field.hasUnits = true;\n          field.defaultUnit = defaultUnit;\n          if (units.length == 1) {\n            var unitText = $(\"<div></div>\").addClass(\"plate-setup-tab-unit\");\n            unitText.text(defaultUnit);\n            field.root.find(\".plate-setup-tab-field-container\").append(unitText);\n          } else {\n            unitInput = this._createElement(\"<input/>\").attr(\"id\", id)\n              .addClass(\"plate-setup-tab-label-select-field\");\n\n            field.root.find(\".plate-setup-tab-field-container\").append(unitInput);\n\n            var selected = null;\n            var unitData = units.map(function(unit) {\n              var o = {\n                id: unit,\n                text: unit\n              };\n              if (unit == defaultUnit) {\n                selected = o;\n              }\n              return o;\n            });\n\n            var opts = {\n              data: unitData,\n              allowClear: false,\n              minimumResultsForSearch: 10\n            };\n\n            unitInput.select2(opts);\n            unitInput.select2(\"data\", selected);\n          }\n        }\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n          if (unitInput) {\n            unitInput.prop(\"disabled\", bool);\n          }\n        };\n\n        field.setUnitOpts = function(opts) {\n          field.units = opts || null;\n          field.defaultUnit = null;\n\n          var newUnits = [];\n          var selected = null;\n          if (field.units && field.units.length) {\n            field.defaultUnit = field.units[0];\n            newUnits = field.units.map(function(curUnit) {\n              var cleanUnit = {\n                id: curUnit,\n                text: curUnit\n              };\n              if (curUnit == field.defaultUnit) {\n                selected = cleanUnit;\n              }\n              return cleanUnit;\n            });\n          }\n\n          var newOpts = {\n            data: newUnits,\n            allowClear: false,\n            minimumResultsForSearch: 10\n          };\n          unitInput.select2(newOpts);\n          unitInput.select2(\"data\", selected);\n        };\n\n        field.parseValue = function(value) {\n          var v;\n          if ($.isPlainObject(value)) {\n            if (field.hasUnits) {\n              v = field.parseRegularValue(value.value);\n              if (v === null) {\n                return null;\n              }\n              return {\n                value: v,\n                unit: field.parseUnit(value.unit)\n              };\n            } else {\n              throw \"Value must be plain numeric for numeric field \" + id;\n            }\n          } else {\n            if (field.hasUnits) {\n              v = field.parseRegularValue(value);\n              if (v === null) {\n                return null;\n              }\n              return {\n                value: v,\n                unit: field.defaultUnit\n              };\n            } else {\n              return field.parseRegularValue(value);\n            }\n          }\n        };\n\n        field.getValue = function() {\n          var v = field.getRegularValue();\n\n          if ((v === null) || isNaN(v)) {\n            return null;\n          } else if (field.hasUnits) {\n            var returnVal = {\n              value: v,\n              unit: field.getUnit()\n            };\n\n            if (field.data.hasMultiplexUnit) {\n              // include unitTypeId and UnitId to returnVal\n              for (var unitTypeKey in field.data.unitMap) {\n                var unitTypeUnits = field.data.unitMap[unitTypeKey];\n                unitTypeUnits.forEach(function(unit) {\n                  if (unit.text === returnVal.unit) {\n                    returnVal['unitTypeId'] = unitTypeKey;\n                    returnVal['unitId'] = unit.id;\n                  }\n                })\n              }\n            }\n            return returnVal;\n          } else {\n            return v;\n          }\n        };\n\n        field.setValue = function(value) {\n          if (field.hasUnits) {\n            if ($.isPlainObject(value)) {\n              field.setUnit(value.unit || field.defaultUnit);\n              field.setRegularValue(value.value);\n\n            } else {\n              field.setRegularValue(value);\n              field.setUnit(field.defaultUnit)\n            }\n          } else {\n            field.setRegularValue(value);\n          }\n        };\n\n        field.parseRegularValue = function(value) {\n          if (value == null) {\n            return null;\n          }\n          var v = String(value).trim();\n          if (v === \"\") {\n            return null;\n          }\n          v = Number(value);\n          if (isNaN(v)) {\n            throw \"Invalid value \" + value + \" for numeric field \" + id;\n          }\n          return v;\n        };\n\n        field.getRegularValue = function() {\n          var v = input.val().trim();\n          if (v == \"\") {\n            v = null;\n          } else {\n            v = Number(v);\n          }\n          return v;\n        };\n\n        field.setRegularValue = function(value) {\n          input.val(value);\n        };\n\n        field.parseUnit = function(unit) {\n          if (unit == null || unit === \"\") {\n            return field.defaultUnit;\n          }\n          for (var i = 0; i < units.length; i++) {\n            if (unit.toLowerCase() == units[i].toLowerCase()) {\n              return units[i];\n            }\n          }\n          throw \"Invalid unit \" + unit + \" for field \" + id;\n        };\n\n        field.getUnit = function() {\n          if (unitInput) {\n            return unitInput.val();\n          } else {\n            return field.defaultUnit;\n          }\n        };\n\n        field.setUnit = function(unit) {\n          if (unitInput) {\n            unit = unit || field.defaultUnit;\n            if (unit != null) {\n              unit = {\n                id: unit,\n                text: unit\n              };\n            }\n            unitInput.select2(\"data\", unit);\n          }\n        };\n\n        // val now contains unit\n        field.getText = function(val) {\n          if (typeof(val) === 'object' && val) {\n            var v = val.value;\n            var u = val.unit;\n            if (v == null) {\n              return \"\";\n            }\n            v = v.toString();\n            if (!u) {\n              u = defaultUnit;\n            }\n            if (u) {\n              v = v + \" \" + u;\n            }\n            return v;\n          } else {\n            return field.getRegularText(val);\n          }\n        };\n\n        field.getRegularText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          v = v.toString();\n          return v;\n        };\n\n        field.parseText = function(v){\n          var textVal = field.parseValue(v);\n          if (textVal && typeof(textVal) === \"object\"){\n            return textVal.value + textVal.unit;\n          } else if (textVal) {\n            return textVal\n          } else {\n            return null;\n          }\n        };\n\n        input.on(\"input\", function() {\n          var v = field.getRegularValue();\n          if (isNaN(v)) {\n            //flag field as invalid\n            input.addClass(\"invalid\");\n          } else {\n            input.removeClass(\"invalid\");\n          }\n          field.onChange();\n        });\n        if (unitInput) {\n          unitInput.on(\"change\", function() {\n            field.onChange();\n          });\n        }\n\n        field.input = input;\n        field.unitInput = unitInput;\n      },\n\n      _createBooleanField: function(field) {\n        var id = field.id;\n        var that = this;\n        var input = this._createElement(\"<input/>\").attr(\"id\", id)\n          .addClass(\"plate-setup-tab-select-field\");\n        that.defaultWell[id] = null;\n\n        field.root.find(\".plate-setup-tab-field-container\").append(input);\n        var tval = {\n          id: \"true\",\n          text: \"true\"\n        };\n        var fval = {\n          id: \"false\",\n          text: \"false\"\n        };\n        var opts = {\n          data: [tval, fval],\n          placeholder: \"select\",\n          allowClear: true,\n          minimumResultsForSearch: -1,\n          initSelection: function(element, callback) {\n            var v = element.val();\n            callback({\n              id: v,\n              text: v\n            });\n          }\n        };\n\n        input.select2(opts);\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n        };\n\n        field.parseValue = function(value) {\n          if (value == null) {\n            return null;\n          }\n          var v = String(value).trim().toLowerCase();\n          if (v == \"true\") {\n            v = true;\n          } else if (v == \"false\") {\n            v = false;\n          } else if (v == \"\") {\n            v = null;\n          } else {\n            throw \"Invalid value \" + value + \" for boolean field \" + id;\n          }\n          return v;\n        };\n\n        field.getValue = function() {\n          var v = input.val();\n          switch (v) {\n            case \"true\":\n              return true;\n            case \"false\":\n              return false;\n            default:\n              return null;\n          }\n        };\n\n        field.setValue = function(v) {\n          if (v == true || v == \"true\") {\n            v = tval;\n          } else if (v == false || v == \"false\") {\n            v = fval;\n          } else {\n            v = null;\n          }\n          input.select2('data', v);\n        };\n\n        field.getText = function(v) {\n          if (v == null) {\n            return \"\";\n          }\n          return v.toString();\n        };\n\n        field.parseText = field.parseValue;\n\n        input.on(\"change\", function(e) {\n          field.onChange();\n        });\n\n        field.input = input;\n      },\n\n      _createMultiplexField: function(field) {\n        var that = this;\n        // make correct multiplex data\n        this._createMultiSelectField(field);\n        // overwrite default well for multiplex field\n        that.defaultWell[field.id] = [];\n\n        // single select\n        var nameContainer1 = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-name-singleSelect\").text(\"Select to edit\");\n        var fieldContainer1 = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab-field-container-singleSelect\");\n        field.root.find(\".plate-setup-tab-field-right-side\").append(nameContainer1, fieldContainer1);\n\n        field.singleSelect = this._createElement(\"<input/>\").attr(\"id\", field.id + \"SingleSelect\")\n          .addClass(\"plate-setup-tab-multiplex-single-select-field\");\n\n        field.singleSelect.appendTo(fieldContainer1);\n\n        field.singleSelectValue = function () {\n          var v = field.singleSelect.select2(\"data\");\n          if (v != null) {\n            v = v.id;\n          }\n          return v;\n        };\n\n        var setSingleSelectOptions = function (v, selected_v) {\n          var opts = {\n            allowClear: false,\n            placeholder: \"select\",\n            minimumResultsForSearch: 10,\n            data: v || []\n          }\n          if (!selected_v) {\n            if (opts.data.length) {\n              selected_v = opts.data[0];\n            } else {\n              selected_v = null;\n            }\n          }\n          field.singleSelect.select2('data', []);\n          field.singleSelect.select2(opts);\n          field.singleSelect.select2('data', selected_v);\n          field.singleSelect.prop(\"disabled\", opts.data.length == 0);\n        };\n\n        var singleSelectChange = function () {\n          var v = field.singleSelectValue();\n\n          field.updateSubFieldUnitOpts(v);\n\n          var curData = field.detailData || [];\n          var curSubField = null;\n          curData.forEach(function(val) {\n            if (val[field.id] === v) {\n              curSubField = val;\n            }\n          });\n\n          if (curSubField) {\n            // setvalue for subfield\n            field.subFieldList.forEach(function(subField) {\n              subField.disabled(false);\n              subField.setValue(curSubField[subField.id]);\n            });\n          } else {\n            field.subFieldList.forEach(function(subField) {\n              subField.disabled(true);\n              subField.setValue(null);\n            });\n          }\n          that.readOnlyHandler();\n        };\n\n        setSingleSelectOptions([]);\n\n        field.singleSelect.on(\"change\", singleSelectChange);\n\n        field._changeMultiFieldValue = function(added, removed) {\n          var newSubFieldValue = {};\n          for (var subFieldName in field.data.multiplexFields) {\n            var subFieldId = field.data.multiplexFields[subFieldName].id;\n            newSubFieldValue[subFieldId] = null;\n          }\n\n          var val;\n          if (added) {\n            if (added.value) {\n              val = added.value;\n            } else {\n              newSubFieldValue[field.id] = added.id;\n              val = newSubFieldValue;\n            }\n            added = {\n              id: added.id,\n              value: val\n            };\n          }\n\n          if (removed) {\n            if (removed.value){\n              val = removed.value;\n            } else {\n              newSubFieldValue[field.id] = removed.id;\n              val = newSubFieldValue;\n            }\n            removed = {\n              id: removed.id,\n              value: val\n            };\n          }\n\n          var data = {};\n          data[field.id] = {\n            multi: true,\n            added: added,\n            removed: removed\n          };\n          that._addAllData(data);\n        };\n\n        var multiselectSetValue = field.setValue;\n\n        // overwrite multiplex set value\n        field.setValue = function(v) {\n          // used to keep track of initially loaded multiplex data\n          field.detailData = v;\n          var multiselectValues = null;\n          if (v && v.length) {\n            multiselectValues = v.map(function(val) {\n              return val[field.id]\n            });\n          }\n\n          multiselectSetValue(multiselectValues);\n          var newOptions = field.input.select2('data') || [];\n          setSingleSelectOptions(newOptions);\n          singleSelectChange();\n        };\n\n        field.disabled = function(bool) {\n          field.input.prop(\"disabled\", bool);\n          field.subFieldList.forEach(function(subField) {\n            subField.disabled(bool);\n          });\n          if (bool) {\n            nameContainer1.text(\"Select to inspect\");\n          } else {\n            nameContainer1.text(\"Select to edit\");\n          }\n        };\n\n        field.parseValue = function(value) {\n          var v = value;\n          if (v && v.length) {\n            v = v.map(function(opt) {\n              var valMap = {};\n              valMap[field.id] = opt[field.id];\n              for (var subFieldId in opt) {\n                field.subFieldList.forEach(function(subField) {\n                  if (subField.id === subFieldId) {\n                    valMap[subField.id] = subField.parseValue(opt[subFieldId]);\n                  }\n                });\n              }\n              return valMap;\n            });\n          } else {\n            v = null;\n          }\n          return v;\n        };\n\n        field.updateSubFieldUnitOpts = function(val) {\n          var curOpts;\n          field.data.options.forEach(function(opt) {\n            if (opt.id === val) {\n              curOpts = opt;\n            }\n          });\n          field.subFieldList.forEach(function(subField) {\n            if (subField.data.hasMultiplexUnit) {\n              if (curOpts && curOpts.hasOwnProperty(\"unitOptions\")) {\n\t\t\t\t\t\t\t\tsubField.setUnitOpts(curOpts.unitOptions[subField.id]);\n              } else {\n                subField.setUnitOpts(null);\n              }\n            }\n          })\n        };\n\n        field.multiOnChange = function(added, removed) {\n          field._changeMultiFieldValue(added, removed);\n          var v = field.getValue();\n          var curData = field.detailData;\n          var curIds = [];\n          var curOpt = null;\n          //reshape data for saveback\n          if (curData) {\n            curIds = curData.map(function(val) {\n              return val[field.id]\n            });\n          }\n\n          var newMultiplexVal = [];\n          var selectList = [];\n          if (v) {\n            v.forEach(function(selectedVal) {\n              if (curData) {\n                curData.forEach(function(val) {\n                  if (val[field.id] === selectedVal) {\n                    newMultiplexVal.push(val)\n                  }\n                });\n              }\n              // cases when adding new data\n              if (curIds.indexOf(selectedVal) < 0) {\n                var newVal = {};\n                newVal[field.id] = selectedVal;\n\n                field.updateSubFieldUnitOpts(selectedVal);\n                field.subFieldList.forEach(function(subfield) {\n                  // special handling for subfield which has multiplexUnit\n                  if (subfield.hasUnits) {\n                    if (subfield.data.hasMultiplexUnit) {\n                      subfield.disabled(false);\n                      field.data.options.forEach(function(opt) {\n                        if (opt.id === selectedVal) {\n                          var val = {\n                            value: null,\n                            unit: subfield.units[0]\n                          };\n                          newVal[subfield.id] = subfield.parseValue(val);\n                        }\n                      });\n                    } else {\n                      if (subfield.data.units) {\n                        if (subfield.data.units.length > 1){\n                          subfield.disabled(false);\n                        }\n                      }\n                      var val = {\n                        value: null,\n                        unit: subfield.defaultUnit\n                      };\n                      newVal[subfield.id] = subfield.parseValue(val);\n                    }\n                  }\n                   else {\n                    newVal[subfield.id] = subfield.parseValue(null);\n                  }\n                });\n                newMultiplexVal.push(newVal);\n              }\n            });\n\n            // make data for single select options\n            v.forEach(function(selectId) {\n              field.data.options.forEach(function(opt) {\n                if (opt.id === selectId) {\n                  selectList.push(opt);\n                }\n              });\n            });\n            // set the newest selected to be the current obj\n            curOpt = selectList[v.length - 1];\n          }\n\n          field.detailData = newMultiplexVal;\n          setSingleSelectOptions(selectList, curOpt);\n          singleSelectChange();\n        };\n\n        field.getText = function(v) {\n          if (v === null) {\n            return \"\";\n          }\n          // get subfields that is selected from the checkbox\n          if (field.id in that.globalSelectedMultiplexSubfield) {\n            var checkedSubfields = that.globalSelectedMultiplexSubfield[field.id];\n            var returnVal = [];\n            for (var valIdx in v) {\n              var subV = v[valIdx];\n              var subText = [];\n              for (var optId in field.data.options) {\n                var opt = field.data.options[optId];\n                if (opt.id === subV[field.id]) {\n                  subText.push(opt.text);\n                }\n              }\n              field.subFieldList.forEach(function(subField) {\n                if (checkedSubfields.indexOf(subField.id) >= 0) {\n                  var x = subField.getText(subV[subField.id]);\n                  subText.push(subField.name + \": \" + x);\n                }\n              });\n              returnVal.push(\"{\" + subText.join(\", \") + \"}\");\n            }\n            return returnVal.join(\";\");\n          }\n        };\n\n        field.parseText = function(v) {\n          if (v === null) {\n            return \"\";\n          } else {\n            var returnVal = [];\n            for (var valIdx in v) {\n              var subV = v[valIdx];\n              var subText = [];\n              for (var optId in field.data.options) {\n                var opt = field.data.options[optId];\n                if (opt.id === subV[field.id]) {\n                  subText.push(opt.text);\n                }\n              }\n              field.subFieldList.forEach(function(subField) {\n                var x = subField.getText(subV[subField.id]);\n                if (x) {\n                  subText.push(x);\n                }\n              });\n              returnVal.push(subText);\n            }\n            return returnVal;\n          }\n        };\n\n        field.checkMultiplexCompletion = function(valList) {\n          var valCount = 0;\n          var completionPct = 0;\n          var include = false;\n          function getSubfieldStatus (vals) {\n            var req = 0;\n            var fill = 0;\n            for (var subFieldId in field.subFieldList) {\n              var subField = field.subFieldList[subFieldId];\n              var curVal = vals[subField.id];\n              if (subField.required) {\n                include = true;\n                req++;\n                if (typeof(curVal) === 'object' && curVal) {\n                  if (curVal.value) {\n                    fill++;\n                  }\n                } else if (curVal) {\n                  fill++;\n                }\n              }\n            }\n            return fill/req;\n          }\n\n          // for cases has value in multiplex field\n          if (valList) {\n            if (valList.length > 0){\n              for (var idx in valList) {\n                valCount++;\n                var vals = valList[idx];\n                completionPct += getSubfieldStatus(vals);\n              }\n            } else if (field.required) {\n              include = true;\n              valCount = 1;\n            }\n          }  else if (field.required) {\n            include = true;\n            valCount = 1;\n          }\n\n          return {\n            include: include,\n            completionPct: completionPct/valCount\n          };\n        };\n\n        // valList contains all of the vals for selected val\n        field.applyMultiplexSubFieldColor = function(valList){\n          function updateSubFieldWarningMap (vals) {\n            for (var subFieldId in field.subFieldList) {\n              var subField = field.subFieldList[subFieldId];\n              // loop through each well's multiplexval list\n              if (vals === null){\n                if (field.required && subField.required){\n                  subFieldWarningMap[subField.id].warningStatus.push(true);\n                }\n              } else if (typeof(vals) === \"object\") {\n                if (vals.length === 0) {\n                  if (field.required && subField.required){\n                    subFieldWarningMap[subField.id].warningStatus.push(true);\n                  }\n                } else {\n                  for (var multiplexIdx in vals) {\n                    var curVal = vals[multiplexIdx][subField.id];\n                    if (subField.required) {\n                      if (typeof(curVal) === 'object' && curVal) {\n                        if (!curVal.value) {\n                          subFieldWarningMap[subField.id].warningStatus.push(true);\n                        } else {\n                          subFieldWarningMap[subField.id].warningStatus.push(false);\n                        }\n                      } else if (!curVal) {\n                        subFieldWarningMap[subField.id].warningStatus.push(true);\n                      } else {\n                        subFieldWarningMap[subField.id].warningStatus.push(false);\n                      }\n                    }\n                  }\n                }\n              }\n            }\n          }\n\n          var subFieldWarningMap = {};\n          field.subFieldList.forEach(function(subField){\n            if (subField.required) {\n              subFieldWarningMap[subField.id] = {\n                field: subField,\n                warningStatus: []\n              };\n            }\n          });\n\n          valList.forEach(function(multiplexVals) {\n            updateSubFieldWarningMap(multiplexVals);\n          });\n          // turn off main field when all subfield are filled\n\n          var requiredSubField = [];\n          var mainFieldStatus = [];\n          for (var subFieldId in subFieldWarningMap){\n            var subField = subFieldWarningMap[subFieldId].field;\n            if (subFieldWarningMap[subFieldId].warningStatus.indexOf(true) >= 0) {\n              var text =  subField.name + \" is a required subfield for \" + field.name + \", please make sure all \" + field.name + \" have \" + subField.name;\n              if (field.required){\n                that.fieldWarningMsg(subField, text, true);\n                mainFieldStatus.push(true);\n              } else {\n                that.fieldWarningMsg(subField, text, true);\n                mainFieldStatus.push(true);\n              }\n            } else {\n              that.fieldWarningMsg(subField, \"none\", false);\n              mainFieldStatus.push(false);\n            }\n          }\n          var mainFieldWarning = false;\n          if (mainFieldStatus.indexOf(true) < 0) {\n            mainFieldWarning = false;\n          } else {\n            mainFieldWarning = true;\n          }\n          var warningText;\n          if (field.required) {\n            warningText = field.name + \" is a required field, please also fix missing required subfield(s) below\";\n          } else {\n            warningText = field.name + \" is not a required field, please fix missing required subfield(s) below or remove selected \" + field.name;\n          }\n          that.fieldWarningMsg(field, warningText, mainFieldWarning);\n        };\n\n        field.parseMainFieldVal = function(val) {\n          var optMap = field.data.options;\n          for (var idx = 0; idx < optMap.length; idx++){\n            var curOpt = optMap[idx];\n            if (curOpt.id === val){\n              return curOpt.text\n            }\n          }\n        };\n      },\n\n      _deleteDialog: function (field) {\n        var that = this;\n\n        var valMap = field.allSelectedMultipleVal;\n        var valToRemove;\n        if (valMap) {\n          valToRemove = Object.keys(valMap);\n        } else {\n          valToRemove = [];\n        }\n\n\n        var dialogDiv = $(\"<div/>\").addClass(\"delete-dialog modal\");\n        $('body').append(dialogDiv);\n\n        function killDialog() {\n          dialogDiv.hide();\n          dialogDiv.remove();\n        }\n\n        var dialogContent = $(\"<div/>\").addClass(\"modal-content\").appendTo(dialogDiv);\n        var tableArea = $(\"<div/>\").appendTo(dialogContent);\n        var buttonRow = $(\"<div/>\").addClass(\"dialog-buttons\").css(\"justify-content\", \"flex-end\").appendTo(dialogContent);\n\n        if (valToRemove.length > 0){\n          // apply CSS property for table\n          $(\"<p/>\").text(field.name + \" in selected wells: choose items to delete and click the delete button below\").appendTo(tableArea);\n\n          var table = that._deleteDialogTable(field, valMap);\n          table.appendTo(tableArea);\n          table.addClass(\"plate-popout-table\");\n          table.find('td').addClass(\"plate-popout-td\");\n          table.find('th').addClass(\"plate-popout-th\");\n          table.find('tr').addClass(\"plate-popout-tr\");\n          if (!that.readOnly) {\n            var deleteCheckedButton = $(\"<button class='multiple-field-manage-delete-button'>Delete Checked Items</button>\");\n            buttonRow.append(deleteCheckedButton);\n            deleteCheckedButton.click(function() {\n              table.find(\"input:checked\").each(function () {\n                var val = this.value;\n                field.multiOnChange(null, {id: val});\n              });\n              // refresh selected fields after updating the multiplex field value\n              that.decideSelectedFields();\n              killDialog();\n            });\n          }\n\n        } else {\n          $(\"<p/>\").text(\"No \" + field.name + \" in the selected wells\").appendTo(tableArea);\n        }\n\n        var cancelButton = $(\"<button>Cancel</button>\");\n        buttonRow.append(cancelButton);\n        cancelButton.click(killDialog);\n\n        dialogDiv.show();\n\n        window.onclick = function(event) {\n          if (event.target == dialogDiv[0]) {\n            killDialog();\n          }\n        }\n      },\n\n      _deleteDialogTable: function (field, valMap) {\n        var that = this;\n        var colName = [field.name, \"Counts\"]; //Added because it was missing... no idea what the original should have been\n        if (!that.readOnly) {\n          colName.push(\"Delete\");\n        }\n        var table = $('<table/>');\n        var thead = $('<thead/>').appendTo(table);\n        var tr = $('<tr/>').appendTo(thead);\n\n        tr.append(colName.map(function (text) {\n          return $('<th/>').text(text);\n        }));\n\n        var tbody = $(\"<tbody/>\").appendTo(table);\n\n        field.data.options.forEach(function (opt) {\n          if (opt.id in valMap) {\n            var tr = $('<tr/>').appendTo(tbody);\n            var checkbox = $(\"<input type='checkbox'>\").prop(\"value\", opt.id);\n            $(\"<td/>\").text(opt.text).appendTo(tr);\n            $(\"<td/>\").text(valMap[opt.id]).appendTo(tr);\n            if (!that.readOnly) {\n              $(\"<td/>\").append(checkbox).appendTo(tr);\n            }\n          }\n        });\n\n        return table;\n      },\n\n      _createDeleteButton: function (field) {\n        var that = this;\n        var deleteButton = $(\"<button/>\").addClass(\"plate-setup-remove-all-button\");\n        deleteButton.id = field.id + \"Delete\";\n        deleteButton.text(\"Manage \" + field.name + \"...\");\n        var buttonContainer = that._createElement(\"<div></div>\").addClass(\"plate-setup-remove-all-button-container\");\n        buttonContainer.append(deleteButton);\n\n        field.deleteButton = deleteButton;\n        field.root.find(\".plate-setup-tab-field-right-side\").append(buttonContainer);\n\n        deleteButton.click(function () {\n          that._deleteDialog(field);\n        });\n      }\n\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.engine = function(THIS) {\n    // Methods which look after data changes and stack up accordingly\n    // Remember THIS points to plateLayOutWidget and 'this' points to engine\n    // Use THIS to refer parent this.\n    return {\n      engine: {\n\n        derivative: {},\n        stackUpWithColor: {},\n        stackPointer: 2,\n\n        wellEmpty: function (well) {\n          for (var prop in well) {\n            var curVal = well[prop];\n            if (curVal !== null && curVal !== undefined) {\n              if (Array.isArray(curVal)) {\n                if (curVal.length > 0) {\n                  return false;\n                }\n              } else {\n                return false;\n              }\n            }\n          }\n          return true;\n        },\n\n        searchAndStack: function() {\n          // This method search and stack the change we made.\n          this.stackUpWithColor = {};\n          this.stackPointer = 1;\n          var derivativeJson = {};\n          for (var idx in this.derivative) {\n            var data = this.derivative[idx];\n            var wellData = {};\n            for (var i = 0; i < THIS.globalSelectedAttributes.length; i++) {\n              var attr = THIS.globalSelectedAttributes[i]; \n\n              if (attr in THIS.globalSelectedMultiplexSubfield){\n                var selectedSubFields = THIS.globalSelectedMultiplexSubfield[attr];\n                var newMultiplexVal = [];\n                for (var multiplexIdx in data[attr]){\n                  var curMultiplexVals = data[attr][multiplexIdx];\n                  var newVal = {};\n                  newVal[attr] = curMultiplexVals[attr];\n                  selectedSubFields.forEach(function (subFieldId) {\n                    newVal[subFieldId] = curMultiplexVals[subFieldId];\n                  });\n                  newMultiplexVal.push(newVal);\n                }\n                wellData[attr] = newMultiplexVal;\n              } else {\n                if (data[attr] != null) {\n                  wellData[attr] = data[attr];\n                }\n              }\n            }\n            if ($.isEmptyObject(wellData)) {\n              derivativeJson[idx] = null; \n            } else {\n              derivativeJson[idx] = JSON.stringify(wellData);\n            }\n          }\n\n          while (!$.isEmptyObject(derivativeJson)) {\n            var keys = Object.keys(derivativeJson).map(function (k) {return parseFloat(k, 10);});\n            keys.sort(function (a, b) {return a-b;}); \n\n            var refDerivativeIndex = keys[0];\n            var referenceDerivative = derivativeJson[refDerivativeIndex];\n            var arr = [];\n\n            if (!referenceDerivative) {\n              // if no checked box has value, push it to first spot\n              if (this.stackUpWithColor[0]) {\n                this.stackUpWithColor[0].push(refDerivativeIndex);\n              } else {\n                this.stackUpWithColor[0] = [refDerivativeIndex];\n              }\n\n              delete derivativeJson[refDerivativeIndex];\n            } else {\n              // if checked boxes have values\n              for (var i = 0; i < keys.length; i++) {\n                var idx = keys[i]; \n                if (referenceDerivative == derivativeJson[idx]) {\n                  arr.push(idx);\n                  this.stackUpWithColor[this.stackPointer] = arr;\n                  delete derivativeJson[idx];\n                }\n              }\n              if (arr.length > 0)\n                this.stackPointer++;\n            }\n          }\n        },\n\n        applyColors: function() {\n\n          var wholeNoTiles = 0;\n          var wholePercentage = 0;\n\n          THIS.addBottomTableHeadings();\n\n          for (var i = 0; i < THIS.allTiles.length; i++) {\n            var tile = THIS.allTiles[i];\n            THIS.setTileVisible(tile, false);\n          }\n\n          for (var color = 0; color < this.stackPointer; color++) {\n            var arr = this.stackUpWithColor[color];\n            if (arr) {\n              THIS.addBottomTableRow(color, arr);\n\n              for (var tileIndex in arr) {\n                wholeNoTiles++;\n                var index = this.stackUpWithColor[color][tileIndex]; \n                var tile = THIS.allTiles[index];\n                var well = this.derivative[index];\n                THIS.setTileColor(tile, color, this.stackPointer); \n                // Checks if all the required fields are filled\n                var completion = this.checkCompletion(well, tile);\n                THIS.setTileComplete(tile, completion == 1); \n                wholePercentage = wholePercentage + completion;\n              }\n            }\n          }\n\n          wholePercentage = Math.floor(100 * wholePercentage / wholeNoTiles);\n\n          if (isNaN(wholePercentage)) {\n            THIS.overLayTextContainer.text(\"Completion Percentage: 0%\");\n          } else {\n            THIS.overLayTextContainer.text(\"Completion Percentage: \" + wholePercentage + \"%\");\n          }\n        },\n\n        checkCompletion: function(wellData, tile) {\n          var req = 0; \n          var fill = 0;\n          for (var i = 0; i < THIS.fieldList.length; i++) {\n            var field = THIS.fieldList[i];\n            if (field.checkMultiplexCompletion){\n              // also apply color\n              var multiplexStatus = field.checkMultiplexCompletion(wellData[field.id]);\n              if (multiplexStatus.include) {\n                fill += multiplexStatus.completionPct;\n                req++;\n              }\n            } else {\n              if (field.required) {\n                req++;\n                if (wellData[field.id] !== null) {\n                  fill++;\n                }\n              }\n            }\n          }\n          if (req === fill) {\n            return 1; \n          }\n          return fill / req;\n        },\n      }\n    }\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.fabricEvents = function() {\n    // This object contains Menu items and how it works;\n    return {\n      colorToIndex: {},\n      startCoords: {\n        x: 0,\n        y: 0\n      },\n      focalWell: {\n        row: 0,\n        col: 0\n      },\n      selectedAreas: [],\n\n      _clickCoords: function(evt) {\n        //Get XY Coords for a given event. \n        var rect = evt.e.target.getBoundingClientRect();\n        return {\n          x: evt.e.clientX - rect.left,\n          y: evt.e.clientY - rect.top\n        };\n      },\n\n      _fabricEvents: function() {\n        // Set up event handling. \n        var that = this;\n\n        $(that.target).on(\"getPlates\", function(evt, data) {\n          // This method should be compatable to redo/undo.\n          that.getPlates(JSON.parse(data));\n        });\n\n        that.mainFabricCanvas.on(\"mouse:down\", function(evt) {\n          // Start selecting new area\n          that.selecting = true;\n          var coords = that._clickCoords(evt);\n\n          var areas = that.selectedAreas.slice();\n          var focalWell = that.focalWell;\n          var startCoords = that._wellToCoords(focalWell, true);\n          var rect = that._coordsToRect(startCoords, coords);\n\n          if (evt.e.ctrlKey) {\n            //adding new area\n            startCoords = coords;\n            rect = that._coordsToRect(startCoords, coords);\n            focalWell = that._coordsToWell(startCoords);\n            if (evt.e.shiftKey) {\n              //replacing existing areas\n              areas = [that._rectToArea(rect)];\n            } else {\n              areas.push(that._rectToArea(rect));\n            }\n          } else {\n            if (evt.e.shiftKey) {\n              //Altering last area\n              areas[areas.length - 1] = that._rectToArea(rect);\n            } else {\n              //Creating new area\n              startCoords = coords;\n              rect = that._coordsToRect(startCoords, coords);\n              focalWell = that._coordsToWell(startCoords);\n              areas = [that._rectToArea(rect)];\n            }\n          }\n\n          that.startCoords = startCoords;\n          that.setSelection(areas, focalWell);\n          that.mainFabricCanvas.renderAll();\n        });\n\n        that.mainFabricCanvas.on(\"mouse:move\", function(evt) {\n          if (that.selecting) {\n            // continue selecting new area\n            var areas = that.selectedAreas.slice();\n            var endCoords = that._clickCoords(evt);\n            var rect = that._coordsToRect(that.startCoords, endCoords);\n            var area = that._rectToArea(rect);\n            if (area) {\n              areas[areas.length - 1] = area;\n            }\n\n            that.setSelection(areas, that.focalWell);\n            that.mainFabricCanvas.renderAll();\n          }\n\n        });\n\n        that.mainFabricCanvas.on(\"mouse:up\", function(evt) {\n          // finish selecting new area\n          that.selecting = false;\n          var areas = that.selectedAreas.slice();\n          var endCoords = that._clickCoords(evt);\n          var rect = that._coordsToRect(that.startCoords, endCoords);\n          var area = that._rectToArea(rect);\n          if (area) {\n            areas[areas.length - 1] = area;\n          }\n\n          that.setSelection(areas, that.focalWell);\n          that.decideSelectedFields();\n          that.mainFabricCanvas.renderAll();\n          that._trigger(\"selectedWells\", null, {selectedAddress: that.getSelectedAddress()});\n        });\n      },\n\n      setSelection: function(areas, focalWell) {\n        this.selectedAreas = areas;\n        this.focalWell = focalWell;\n        this.allSelectedObjects = this._areasToTiles(areas);\n        this._setSelectedTiles();\n        this._setFocalWellRect(this.focalWell);\n        document.activeElement.blur();\n      },\n\n      _setFocalWellRect: function(well) {\n        var flag;\n        // check if not allow to add or delete existing wells\n        if (this.disableAddDeleteWell) {\n          var address = this.locToAddress({\n            r: well.row,\n            c: well.col\n          });\n          if  (this.addressAllowToEdit.indexOf(address) < 0) {\n            flag = false;\n            this.setFieldsDisabled(true);\n          } else {\n            flag = true;\n            this.setFieldsDisabled(false);\n          }\n        } else if (well) {\n          flag = true;\n        }\n\n        if (flag) {\n          var rect = this._areaToRect(this._wellToArea(well));\n          var strokeWidth = 2;\n          if (this.focalWellRect) {\n            //update focalWellRect\n            this.focalWellRect.top = rect.top;\n            this.focalWellRect.left = rect.left;\n            this.focalWellRect.width = rect.width - strokeWidth;\n            this.focalWellRect.height = rect.height - strokeWidth;\n          } else {\n            //create focalWellRect\n            this.focalWellRect = new fabric.Rect({\n              width: rect.width - strokeWidth,\n              height: rect.height - strokeWidth,\n              left: rect.left,\n              top: rect.top,\n              fill: null,\n              strokeWidth: strokeWidth,\n              stroke: \"black\",\n              selectable: false\n            });\n            this.mainFabricCanvas.add(this.focalWellRect);\n          }\n        } else {\n          //clear focalWellRect\n          this.mainFabricCanvas.remove(this.focalWellRect);\n          this.focalWellRect = null;\n        }\n      },\n\n      _setSelectedTiles: function() {\n        // Update selected tile display only\n        var selectedTiles = this.allSelectedObjects;\n        this.allTiles.forEach(function(tile) {\n          var selected = selectedTiles.indexOf(tile) >= 0;\n          tile.highlight.visible = selected;\n        })\n      },\n\n      _getSelectedWells: function () {\n        var that = this; \n        return this.allSelectedObjects.map(function (tile) {\n          var well = that.engine.derivative[tile.index];\n          if (!well) {\n            well = that.defaultWell; \n          }\n          return well; \n        }); \n      },\n\n      _getCommonFields: function (wells) {\n        if (wells.length) {\n          var referenceWell = wells[0];\n          var referenceFields = $.extend(true, {}, referenceWell);\n          for (var i = 1; i < wells.length; i++) {\n            var fields = wells[i];\n            for (var field in referenceFields) {\n              if (Array.isArray(referenceFields[field])) {\n                var refArr = referenceFields[field]; \n                var agrArr = []; \n                for (var j = 0; j < refArr.length; j++) {\n                  var v = refArr[j];\n                  if (v && typeof(v) === \"object\") {\n                    if (this.containsObject(v, fields[field])) {\n                      agrArr.push(v);\n                    }\n                  } else {\n                    if ($.inArray(v, fields[field]) >= 0) {\n                      agrArr.push(v);\n                    }\n                  }\n                }\n                referenceFields[field] = agrArr; \n              } else {\n                if (fields[field] && typeof(fields[field]) ===\"object\" && referenceFields[field] && typeof(referenceFields[field]) ===\"object\"){\n                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){\n                    delete referenceFields[field];\n                  }\n                } else if (referenceFields[field] != fields[field]) {\n                  delete referenceFields[field];\n                }\n              }\n            }\n          }\n          return referenceFields\n        } else {\n          return {};\n        }\n      },\n\n      containsObject: function(obj, list) {\n        var equality = [];\n        if (list) {\n          list.forEach(function(val) {\n            //evaluate val and obj\n            var evaluate = [];\n            Object.keys(val).forEach(function(listKey){\n              if (Object.keys(obj).indexOf(listKey) >= 0){\n                var curVal = val[listKey];\n                if (typeof(curVal) === 'object' && curVal) {\n                  if (obj[listKey]){\n                    evaluate.push((curVal.unit === obj[listKey].unit) && (curVal.value === obj[listKey].value));\n                  } else {\n                    // when obj[listKey] is null but curVal is not\n                    evaluate.push(false);\n                  }\n                } else {\n                  evaluate.push(curVal === obj[listKey]);\n                }\n              }\n            });\n            equality.push(evaluate.indexOf(false) < 0);\n          });\n          return equality.indexOf(true) >= 0;\n        } else {\n          return false;\n        }\n      },\n\n      _getCommonWell: function (wells) {\n        if (wells.length) {\n          var referenceWell = wells[0];\n          var referenceFields = $.extend(true, {}, referenceWell);\n          for (var i = 1; i < wells.length; i++) {\n            var well = wells[i];\n            var fields = well;\n            for (var field in referenceFields) {\n              if (Array.isArray(referenceFields[field])) {\n                var refArr = referenceFields[field]; \n                var agrArr = []; \n                for (var j = 0; j < refArr.length; j++) {\n                  var v = refArr[j];\n                  // for multiplex field\n                  if (typeof(refArr[j]) ===\"object\"){\n                    if (this.containsObject(v, fields[field])) {\n                      agrArr.push(v);\n                    }\n                  } else {\n                    if ($.inArray(v, fields[field]) >= 0) {\n                      agrArr.push(v);\n                    }\n                  }\n                }\n                referenceFields[field] = agrArr; \n              } else {\n                if (fields[field] && typeof(fields[field]) ===\"object\" && referenceFields[field] && typeof(referenceFields[field]) ===\"object\"){\n                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){\n                    referenceFields[field] = null;\n                  }\n                } else if (referenceFields[field] != fields[field]) {\n                  referenceFields[field] = null;\n                }\n\n              }\n            }\n          }\n          return referenceFields;\n        } else {\n          return this.defaultWell; \n        }\n      }, \n\n      _getAllMultipleVal: function (wells) {\n        var multipleFieldList = this.multipleFieldList;\n\n        multipleFieldList.forEach(function(multiplexField) {\n          if(wells.length) {\n            var curMultipleVal = {};\n            wells.forEach(function (wellData) {\n              var id = multiplexField.id;\n              if (wellData[id]){\n                if (wellData[id].length > 0) {\n                  wellData[id].forEach(function (multipleVal) {\n                    if (typeof(multipleVal) === 'object') {\n                      if (multipleVal[id] in curMultipleVal) {\n                        curMultipleVal[multipleVal[id]] ++;\n                      } else {\n                        curMultipleVal[multipleVal[id]] = 1;\n                      }\n                    } else {\n                      if (multipleVal in curMultipleVal) {\n                        curMultipleVal[multipleVal] ++;\n\n                      } else {\n                        curMultipleVal[multipleVal] = 1;\n                      }\n                    }\n                  })\n                }\n              }\n            });\n            multiplexField.allSelectedMultipleVal = curMultipleVal;\n          } else {\n            multiplexField.allSelectedMultipleVal = null\n          }\n        });\n      },\n\n      decideSelectedFields: function() {\n        var wells = this._getSelectedWells();\n        this._getAllMultipleVal(wells);\n        this.applyFieldWarning(wells);\n        var well = this._getCommonWell(wells); \n        this._addDataToTabFields(well);\n      },\n\n      // get well value differences for each well in wellsHash\n      getDifferentWellsVals: function(wellsHash) {\n        var wells = [];\n        for (var wellId in wellsHash){\n          wells.push(wellsHash[wellId]);\n        }\n        var differentWellsVals = {};\n        if (wells.length > 1){\n          var commonWell = this._getCommonWell(wells);\n          var allFieldVal = {};\n          for (var fieldIdx in wellsHash[0]) {\n            allFieldVal[fieldIdx] = [];\n          }\n          for (var wellIdx in wells){\n            var diffWellVal = {};\n            var curWellData = wells[wellIdx];\n            for (var fieldId in curWellData) {\n              var commonVal = commonWell[fieldId];\n              var curVal = curWellData[fieldId];\n              var newVal = null;\n              if (Array.isArray(curVal)) {\n                // get uncommonVal\n                newVal = [];\n                for (var idx = 0; idx < curVal.length; idx ++){\n                  var curMultiVal = curVal[idx];\n                  // multiplex field\n                  if (curMultiVal && typeof(curMultiVal === \"object\")){\n                    if (!this.containsObject(curMultiVal, commonVal)) {\n                      newVal.push(curMultiVal);\n                      if (!this.containsObject(curMultiVal, allFieldVal[fieldId])) {\n                        allFieldVal[fieldId].push(curMultiVal);\n                      }\n                    }\n                  } else {\n                    if (commonVal.indexOf(curMultiVal) >= 0) {\n                      newVal.push(curMultiVal);\n                      if (!allFieldVal[fieldId].indexOf(curMultiVal) >= 0) {\n                        allFieldVal[fieldId].push(curMultiVal);\n                      }\n                    }\n                  }\n                }\n              } else if (curVal && typeof(curVal) === \"object\"){\n                if (commonVal && typeof(commonVal) ===\"object\"){\n                  if (!((curVal.value === commonVal.value) || (curVal.unit === commonVal.unit))){\n                    newVal = curVal;\n                    if (!this.containsObject(curVal, allFieldVal[fieldId])) {\n                      allFieldVal[fieldId].push(curVal);\n                    }\n                  }\n                } else {\n                  newVal = curVal;\n                  if (!this.containsObject(curVal, allFieldVal[fieldId])) {\n                    allFieldVal[fieldId].push(curVal);\n                  }\n                }\n              } else if (curVal !== commonVal) {\n                newVal = curVal;\n                if (!allFieldVal[fieldId].indexOf(curVal) >= 0) {\n                  allFieldVal[fieldId].push(curVal);\n                }\n              }\n              diffWellVal[fieldId] = newVal;\n            }\n\n\n            differentWellsVals[wellIdx] = diffWellVal;\n          }\n\n          // clean up step for fields that are empty\n          for (var fieldId in allFieldVal) {\n            if (allFieldVal[fieldId].length === 0) {\n              for (var wellIdx in differentWellsVals){\n                delete differentWellsVals[wellIdx][fieldId];\n              }\n            }\n          }\n\n          return differentWellsVals;\n        } else if (wellsHash[0]) {\n          var well = {};\n          for (var fieldId in wellsHash[0]) {\n            var curVal = wellsHash[0][fieldId];\n            if (Array.isArray(curVal)){\n              if (curVal.length > 0) {\n                well[fieldId] = curVal\n              }\n            } else if (curVal){\n              well[fieldId] = curVal;\n            }\n          }\n          return {\n            0: well\n          };\n        }\n      },\n\n      // get all wells that has data\n      getWellSetAddressWithData: function(){\n        var address = [];\n        var derivative = this.engine.derivative;\n        for (var id in derivative){\n          address.push(this.indexToAddress(id));\n        }\n        return address;\n      }\n\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\nplateLayOutWidget.assets = function () {\n    return {\n        _assets: {\n            doImg: '&#10003;',\n            dontImg: '',\n            warningImg: '&#9888;'\n        }\n    };\n};\n","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.interface = function() {\n    // interface holds all the methods to put the interface in place\n    return {\n\n      _createInterface: function() {\n\n        var divIdentifier = '<div></div>';\n        this.container = this._createElement(divIdentifier).addClass(\"plate-setup-wrapper\");\n        this.topSection = this._createElement(divIdentifier).addClass(\"plate-setup-top-section\");\n\n        this.topLeft = this._createElement(divIdentifier).addClass(\"plate-setup-top-left\");\n        this.topRight = this._createElement(divIdentifier).addClass(\"plate-setup-top-right\");\n\n        this.overLayContainer = this._createElement(divIdentifier).addClass(\"plate-setup-overlay-container\");\n        this.canvasContainer = this._createElement(divIdentifier).addClass(\"plate-setup-canvas-container\");\n\n        this._createOverLay();\n        $(this.topLeft).append(this.overLayContainer);\n\n        this._createCanvas();\n        $(this.topLeft).append(this.canvasContainer);\n\n\n        $(this.topSection).append(this.topLeft);\n        $(this.topSection).append(this.topRight);\n\n        $(this.container).append(this.topSection);\n        $(this.element).append(this.container);\n\n        this._initiateFabricCanvas();\n\n        this._createTabAtRight();\n        this._createTabs();\n\n        this._placePresetTabs();\n        // Bottom of the screen\n        this._bottomScreen();\n        // Canvas\n        this._canvas();\n\n        this.bottomForFirstTime();\n\n        var that = this;\n        this._setShortcuts();\n        $(document.body).keyup(function(e) {\n          that._handleShortcuts(e);\n        });\n\n        this._configureUndoRedoArray();\n      },\n\n      _createElement: function(element) {\n        return $(element);\n      },\n\n      _setShortcuts: function () {\n        var that = this; \n        window.addEventListener(\"cut\", function (e) {\n          if (document.activeElement == document.body) {\n            that.copyCriteria();\n            that.clearCriteria();\n            e.preventDefault();\n          }\n        });\n        window.addEventListener(\"copy\", function (e) {\n          if (document.activeElement == document.body) {\n            that.copyCriteria();\n            e.preventDefault();\n          }\n        });\n        window.addEventListener(\"paste\", function (e) {\n          if (document.activeElement == document.body) {\n            that.pasteCriteria();\n            e.preventDefault();\n          }\n        });\n      },\n\n      _handleShortcuts: function(e) {\n        if (document.activeElement === document.body) {\n          if (e.keyCode == 46) {\n            this.clearCriteria();\n            e.preventDefault();\n          } else if (e.ctrlKey || e.metaKey) {\n            if (e.keyCode == 90) {\n              if (e.shiftKey) {\n                this.redo();\n              } else {\n                this.undo();\n              }\n              e.preventDefault();\n            } else if (e.keyCode == 89) {\n              this.redo();\n              e.preventDefault();\n            }\n          }\n        }\n      },\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.loadPlate = function(THIS) {\n    // Methods which look after data changes and stack up accordingly\n    // Remember THIS points to plateLayOutWidget and 'this' points to engine\n    return {\n\n      getPlates: function (data) {\n        //sanitize input\n        var derivative = {}; \n        for (var index in data.derivative) {\n          var well = data.derivative[index]; \n          derivative[index] = this.sanitizeWell(well); \n        }\n\n        var checkboxes = data.checkboxes || []; \n        var selection = this.sanitizeAreas(data.selectedAreas, data.focalWell); \n\n        var sanitized = {\n          \"derivative\": derivative,\n          \"checkboxes\": checkboxes,\n          \"selectedAreas\": selection.selectedAreas,\n          \"focalWell\": selection.focalWell\n        }; \n\n        this.setData(sanitized);\n      }, \n\n      sanitizeAreas: function (selectedAreas, focalWell) {\n        var that = this; \n        var rows = this.dimensions.rows;\n        var cols = this.dimensions.cols;\n\n        if (!selectedAreas) {\n          selectedAreas = [];\n        }\n        if (selectedAreas.length) {\n          selectedAreas = selectedAreas.map(function (area) {\n            return {\n              minCol: that._coordIndex(Math.min(area.minCol, area.maxCol), cols), \n              minRow: that._coordIndex(Math.min(area.minRow, area.maxRow), rows), \n              maxCol: that._coordIndex(Math.max(area.minCol, area.maxCol), cols), \n              maxRow: that._coordIndex(Math.max(area.minRow, area.maxRow), rows)\n            }; \n          }); \n          var area = selectedAreas[selectedAreas.length - 1];\n          if (focalWell && !this._wellInArea(focalWell, area)) {\n            focalWell = null;\n          }\n          if (!focalWell) {\n            focalWell = {\n              row: area.minRow,\n              col: area.minCol\n            };\n          }\n        } else {\n          if (!focalWell) {\n            focalWell = {\n              row: 0,\n              col: 0\n            };\n          }\n          selectedAreas = [this._wellToArea(focalWell)];\n        }\n        return {\n          selectedAreas: selectedAreas, \n          focalWell: focalWell\n        };\n      }, \n\n      sanitizeWell: function (well) {\n        var newWell = {};\n        for (var i = 0; i < this.fieldList.length; i++) {\n          var field = this.fieldList[i];\n          newWell[field.id] = field.parseValue(well[field.id]);\n        }\n        return newWell; \n      }, \n\n      setData: function(data) {\n        this.engine.derivative = $.extend(true, {}, data.derivative);\n        this.setCheckboxes(data.checkboxes);\n        this.setSelection(data.selectedAreas, data.focalWell);\n        this._colorMixer();\n        this.decideSelectedFields();\n        this.mainFabricCanvas.renderAll();\n      },\n\n    }\n  }\n})(jQuery, fabric);","var GET_PLATES = 'getPlates';\nvar IS_READ_ONLY = 'isReadOnly';\nvar IS_DISABLE_ADD_DELETE_WELL = 'isDisableAddDeleteWell';\nvar GET_SELECTED_OBJECT = 'getSelectedObject';\nvar SETSELECTEDWELL = 'setSelectedWell';","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.overlay = function() {\n    // overlay holds all the methods to put the part just above the canvas which contains all those\n    // 'completion percentage' annd 'copy Criteria' button etc ...\n    return {\n\n      _createOverLay: function() {\n\n        var that = this;\n        this.overLayTextContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-overlay-text-container\");\n        this.overLayTextContainer.text(\"Completion Percentage:\");\n        this.overLayContainer.append(this.overLayTextContainer);\n        this.overLayButtonContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-overlay-button-container\");\n        this.overLayContainer.append(this.overLayButtonContainer);\n\n        this.clearCriteriaButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.clearCriteriaButton.text(\"Clear\");\n        this.overLayButtonContainer.append(this.clearCriteriaButton);\n\n        this.clearCriteriaButton.click(function(evt) {\n          that.clearCriteria();\n        });\n\n        this.copyCriteriaButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.copyCriteriaButton.text(\"Copy\");\n        this.overLayButtonContainer.append(this.copyCriteriaButton);\n\n        this.copyCriteriaButton.click(function(evt) {\n          that.copyCriteria();\n        });\n\n        this.pasteCriteriaButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.pasteCriteriaButton.text(\"Paste\");\n        this.overLayButtonContainer.append(this.pasteCriteriaButton);\n\n        this.pasteCriteriaButton.click(function(evt) {\n          that.pasteCriteria();\n        });\n\n        this.undoButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.undoButton.text(\"Undo\");\n        this.overLayButtonContainer.append(this.undoButton);\n\n        this.undoButton.click(function(evt) {\n          that.undo();\n        });\n\n        this.redoButton = this._createElement(\"<button />\").addClass(\"plate-setup-button\");\n        this.redoButton.text(\"Redo\");\n        this.overLayButtonContainer.append(this.redoButton);\n\n        this.redoButton.click(function(evt) {\n          that.redo();\n        });\n\n      },\n\n      clearCriteria: function() {\n        if (this.allSelectedObjects) {\n          var noOfSelectedObjects = this.allSelectedObjects.length;\n          var hasWellUpdate = false;\n          for (var objectIndex = 0; objectIndex < noOfSelectedObjects; objectIndex++) {\n            var tile = this.allSelectedObjects[objectIndex];\n            if (tile.index in this.engine.derivative) {\n              // handling for clearing well when not allowed to add or delete wells\n              if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {\n                var well = JSON.parse(JSON.stringify(this.defaultWell));\n                var defaultValue = this.emptyWellWithDefaultVal;\n                for (var key in defaultValue){\n                  if (key in well) {\n                    well[key] = defaultValue[key];\n                    this._applyFieldData(key, defaultValue[key]);\n                  } else {\n                    console.log(\"Well does not contain key: \" + key + \", please contact support\");\n                  }\n                }\n                this.engine.derivative[tile.index] = well;\n              } else {\n                delete this.engine.derivative[tile.index];\n              }\n              hasWellUpdate = true;\n            }\n          }\n          if (hasWellUpdate){\n            this.derivativeChange();\n          }\n\n          this._colorMixer();\n          this.decideSelectedFields();\n        } else {\n          alert(\"Please select any well\");\n        }\n      },\n\n      copyCriteria: function() {\n        if (this.allSelectedObjects) {\n          var wells = this._getSelectedWells(); \n          this.commonWell = this._getCommonFields(wells); \n        } else {\n          alert(\"Please select any well.\");\n        }\n      },\n\n      pasteCriteria: function() {\n        if (this.commonWell) {\n          this._addAllData(this.commonWell);\n          this.decideSelectedFields();\n          this.mainFabricCanvas.renderAll();\n        }\n      }\n    };\n  }\n})(jQuery, fabric);","$.widget(\"DNA.plateLayOut\", {\n\n  plateLayOutWidget: {},\n\n  options: {\n    value: 0\n  },\n\n  allTiles: [], // All tiles containes all thise circles in the canvas\n\n  addressToLoc: function (layoutAddress) {\n    var m = /^([A-Z]+)(\\d+)$/.exec(layoutAddress.trim().toUpperCase())\n    if (m) {\n      var row_v = m[1]; \n      var col = parseInt(m[2])-1;\n      var row; \n      for (var i = 0; i < row_v.length; i++) {\n        var c = row_v.charCodeAt(i) - 65; \n        if (i) {\n            row += 1;\n            row *= 26; \n            row += c ; \n        } else {\n            row = c;\n        }\n      }\n      return {\n        r: row, \n        c: col\n      };\n    } else {\n      throw layoutAddress + \" not a proper layout address\"; \n    }\n  },\n\n  locToIndex: function (loc, dimensions) {\n    if (!dimensions) {\n      dimensions = this.dimensions;\n    }\n    if (loc.r < 0) {\n      t\n    }\n    if (!(loc.r >= 0 && loc.r < dimensions.rows)) {\n      throw \"Row index \" + (loc.r + 1) + \" invalid\"; \n    }\n    if (!(loc.c >= 0 && loc.c < dimensions.cols)) {\n      throw \"Column index \" + (loc.c + 1) + \" invalid\"; \n    }\n    return loc.r*dimensions.cols + loc.c; \n  },\n\n  addressToIndex: function (layoutAddress, dimensions) {\n    var loc = this.addressToLoc(layoutAddress); \n    return this.locToIndex(loc, dimensions); \n  }, \n\n  _rowKey: function (i) {\n    var c1 = i % 26;\n    var c2 = (i - c1) / 26;\n    var code = String.fromCharCode(65 + c1);\n    if (c2 > 0) {\n      code = String.fromCharCode(64 + c2) + code;\n    }\n    return code;\n  }, \n\n  indexToLoc: function (index, dimensions) {\n    if (!dimensions) {\n      dimensions = this.dimensions;\n    }\n\n    if (index >= dimensions.rows * dimensions.cols) {\n      throw \"Index too high: \" + index.toString(10); \n    }\n    var loc = {}; \n    loc.c = index % dimensions.cols;\n    loc.r = (index - loc.c) / dimensions.cols;\n\n    return loc; \n  },\n\n  locToAddress: function (loc) {\n    return this._rowKey(loc.r) + (loc.c + 1).toString(10);\n  },\n\n  indexToAddress: function (index, dimensions) {\n    var loc = this.indexToLoc(index, dimensions); \n    return this.locToAddress(loc); \n  },\n\n  getDimensions: function () {\n    return $.extend(true, {}, this.dimensions);\n  },\n\n  _create: function() {\n    var rows = parseInt(this.options.numRows || 8);\n    var cols = parseInt(this.options.numCols || 12);\n    this.dimensions = {\n      rows: rows,\n      cols: cols\n    };\n    this.rowIndex = [];\n    for (var i = 0; i < rows; i++) {\n      this.rowIndex.push(this._rowKey(i));\n    }\n\n    this.target = (this.element[0].id) ? \"#\" + this.element[0].id : \".\" + this.element[0].className;\n\n    // Import classes from other files.. Here we import it using extend and add it to this\n    // object. internally we add to widget.DNA.getPlates.prototype.\n    // Helpers are methods which return other methods and objects.\n    // add Objects to plateLayOutWidget and it will be added to this object.\n    // set read only well\n    if (this.options.readOnly){\n      this.isReadOnly(true);\n    }\n\n    for (var component in plateLayOutWidget) {\n      // Incase some properties has to initialize with data from options hash,\n      // we provide it sending this object.\n      $.extend(this, new plateLayOutWidget[component](this));\n    }\n\n    this.imgSrc = this.options.imgSrc || \"assets\";\n\n    this._createInterface();\n\n    this._trigger(\"created\", null, this);\n\n    return this;\n  },\n\n  _init: function() {\n    // This is invoked when the user use the plugin after _create is called.\n    // The point is _create is invoked for the very first time and for all other\n    // times _init is used.\n  },\n\n  addData: function() {\n    alert(\"wow this is good\");\n  },\n\n  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}\n  getTextDerivative: function(wellsData) {\n    var textDerivative = {};\n    var fieldMap = this.fieldMap;\n    for (var idx in wellsData){\n      var textValWell = {};\n      var textFieldIdWell = {};\n      var curWellData = wellsData[idx];\n      for (var fieldId in curWellData){\n        if (fieldId in this.fieldMap){\n          var field = this.fieldMap[fieldId];\n          var textVal = field.parseText(curWellData[fieldId]);\n          textFieldIdWell[field.name] = textVal;\n          textValWell[fieldId] = textVal;\n        } else {\n          // do not convert if not a field (ex: layout_address)\n          textFieldIdWell[fieldId] = curWellData[fieldId];\n          textValWell[fieldId] = curWellData[fieldId];\n        }\n      }\n      textDerivative[idx] = {\n        textVal: textValWell,\n        textFieldVal: textFieldIdWell\n      };\n    }\n\n    return textDerivative;\n  },\n\n  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}\n  getWellsDifferences: function(wellsData) {\n    return this.getDifferentWellsVals(wellsData);\n  },\n\n  setFieldsDisabled: function(flag){\n    this.fieldList.forEach(function(field){\n      field.disabled(flag);\n    });\n  },\n\n  isReadOnly: function(flag){\n    if (flag){\n      this.readOnly = true;\n    } else {\n      this.readOnly = false;\n    }\n    this.readOnlyHandler();\n  },\n\n  readOnlyHandler: function(){\n    if (this.readOnly){\n      this.overLayButtonContainer.css(\"display\", \"none\");\n      $('.multiple-field-manage-delete-button').css(\"display\", \"none\");\n      this.setFieldsDisabled(true);\n    } else {\n      this.overLayButtonContainer.css(\"display\", \"flex\");\n      $('.multiple-field-manage-delete-button').css(\"display\", \"none\");\n      if (!this.disableAddDeleteWell) {\n        this.setFieldsDisabled(false);\n      }\n    }\n  },\n\n  disableAddDeleteWell: null,\n  // column_with_default_val will be used to determine empty wells, format: {field_name: default_val}\n  isDisableAddDeleteWell: function(flag, column_with_default_val){\n    if (flag){\n      this.disableAddDeleteWell = true;\n      this.addressAllowToEdit = this.getWellSetAddressWithData();\n      // configure undo redo action\n      this.actionPointer = 0;\n      this.undoRedoArray = [];\n      this.undoRedoArray.push(this.createObject());\n      if (column_with_default_val) {\n        this.emptyWellWithDefaultVal = column_with_default_val;\n      }\n    } else {\n      this.disableAddDeleteWell = false;\n      this.setFieldsDisabled(false);\n      this.emptyWellWithDefaultVal = null;\n    }\n    this._fabricEvents();\n  },\n\n  getSelectedObject: function() {\n    var selectedAddress = [];\n    for (var i = 0; i < this.allSelectedObjects.length; i++){\n      selectedAddress.push(this.allSelectedObjects[i].address);\n    }\n    var selectedObjects = {};\n    var derivative = this.engine.derivative;\n    for (var loc in derivative){\n      var address = this.indexToAddress(loc);\n      if (selectedAddress.indexOf(address) >= 0) {\n        selectedObjects[address] = derivative[loc];\n      }\n    }\n    return selectedObjects;\n  },\n\n  getSelectedIndex: function() {\n    return this.allSelectedObjects.map(function(selectedObj){\n        return that.addressToIndex(selectedObj.address)\n    });\n  },\n\n  getSelectedAddress: function() {\n    return this.allSelectedObjects.map(function(selectedObj){\n      return selectedObj.address;\n    });\n  },\n\n  setSelectedWell: function(addressList) {\n    var areas = [];\n    var minRow = 999;\n    var locMap = {};\n    for (var id = 0; id < addressList.length; id++){\n      var wellIdx = this.addressToIndex(addressList[id]);\n      var loc = this.indexToLoc(wellIdx);\n      areas.push({\n        minCol: loc.c,\n        minRow: loc.r,\n        maxCol: loc.c,\n        maxRow: loc.r\n      });\n      if (loc.r <= minRow) {\n        minRow = loc.r;\n        if (loc.r in locMap) {\n          locMap[loc.r].push(loc.c);\n        } else {\n          locMap[loc.r] = [loc.c];\n        }\n      }\n    }\n    var focalWell = {\n      row: minRow,\n      col: Math.min.apply(null, locMap[minRow])\n    };\n\n    this.setSelection(areas, focalWell);\n    this.decideSelectedFields();\n    this.mainFabricCanvas.renderAll();\n  }\n\n});","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.preset = function(me) {\n    // All the preset action goes here\n    return {\n\n      presets: [],\n\n      _placePresetTabs: function() {\n        var presets = this.options.attributes.presets;\n\n        if (presets && presets.length) {\n          this.wellAttrContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-well-attr-container\")\n            .text(\"Checkbox presets\");\n          this.tabContainer.append(this.wellAttrContainer);\n\n          this.presetTabContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-preset-container\");\n          this.tabContainer.append(this.presetTabContainer);\n\n          for (var i = 0; i < presets.length; i++) {\n            var preset = presets[i];\n            var divText = this._createElement(\"<div></div>\").addClass(\"plate-setup-prest-tab-div\")\n              .text(preset.title);\n\n            var presetButton = this._createElement(\"<div></div>\").addClass(\"plate-setup-prest-tab\")\n              .data(\"preset\", preset.fields).append(divText);\n            this.presetTabContainer.append(presetButton);\n\n            var that = this;\n            presetButton.click(function() {\n              var preset = $(this);\n              that._selectPreset(preset);\n            });\n            this.presets.push(presetButton);\n          }\n        }\n      },\n\n      _clearPresetSelection: function() {\n        for (var j = 0; j < this.presets.length; j++) {\n          var p = this.presets[j]; \n          p.removeClass(\"plate-setup-prest-tab-selected\")\n            .addClass(\"plate-setup-prest-tab\"); \n        }\n      },\n\n      _selectPreset: function (preset) {\n        this.setCheckboxes(preset.data(\"preset\")); \n        preset.removeClass(\"plate-setup-prest-tab\")\n          .addClass(\"plate-setup-prest-tab-selected\");\n      },\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.tabs = function() {\n    // Tabs crete and manage tabs at the right side of the canvas.\n    return {\n\n      allTabs: [],\n\n      defaultWell: {},\n\n      allDataTabs: [], // To hold all the tab contents. this contains all the tabs and its elements and elements\n      // Settings as a whole. its very usefull, when we have units for a specific field.\n      // it goes like tabs-> individual field-> units and checkbox\n\n      _createTabAtRight: function() {\n        this.tabContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-tab-container\");\n        $(this.topRight).append(this.tabContainer);\n      },\n\n      _createTabs: function() {\n        // this could be done using z-index. just imagine few cards stacked up.\n        // Check if options has tab data.\n        // Originally we will be pulling tab data from developer.\n        // Now we are building upon dummy data.\n        this.tabHead = this._createElement(\"<div></div>\").addClass(\"plate-setup-tab-head\");\n        $(this.tabContainer).append(this.tabHead);\n\n        var tabData = this.options.attributes.tabs;\n        var that = this;\n\n        tabData.forEach(function (tab, tabIndex) {\n          that.allTabs[tabIndex] = that._createElement(\"<div></div>\").addClass(\"plate-setup-tab\");\n          $(that.allTabs[tabIndex]).data(\"index\", tabIndex)\n            .text(tab.name);\n\n          $(that.allTabs[tabIndex]).click(function() {\n            that._tabClickHandler(this);\n          });\n\n          $(that.tabHead).append(that.allTabs[tabIndex]);\n        }); \n\n        this.tabDataContainer = this._createElement(\"<div></div>\").addClass(\"plate-setup-tab-data-container\");\n        $(this.tabContainer).append(this.tabDataContainer);\n\n        this._addDataTabs(tabData);\n\n        $(this.allTabs[0]).click();\n\n        this._addTabData();\n      },\n\n      _tabClickHandler: function(clickedTab) {\n\n        if (this.selectedTab) {\n          $(this.selectedTab).removeClass(\"plate-setup-tab-selected\")\n            .addClass(\"plate-setup-tab\");\n\n          var previouslyClickedTabIndex = $(this.selectedTab).data(\"index\");\n          $(this.allDataTabs[previouslyClickedTabIndex]).css(\"z-index\", 0);\n          this.readOnlyHandler();\n        }\n\n        $(clickedTab).addClass(\"plate-setup-tab-selected\");\n\n        this.selectedTab = clickedTab;\n\n        var clickedTabIndex = $(clickedTab).data(\"index\");\n        $(this.allDataTabs[clickedTabIndex]).css(\"z-index\", 1000);\n      },\n\n      _addDataTabs: function(tabs) {\n\n        var tabIndex = 0;\n\n        for (var tabData in tabs) {\n          this.allDataTabs[tabIndex++] = this._createElement(\"<div></div>\").addClass(\"plate-setup-data-div\")\n            .css(\"z-index\", 0);\n          $(this.tabDataContainer).append(this.allDataTabs[tabIndex - 1]);\n        }\n      }\n    };\n  }\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.undoRedoManager = function(THIS) {\n\n    return {\n\n      undoRedoArray: [],\n\n      actionPointer: null,\n\n      addToUndoRedo: function(data) {\n\n        if (this.actionPointer != null) {\n          var i = this.actionPointer + 1; \n          if (i < this.undoRedoArray.length) {\n            this.undoRedoArray.splice(i, this.undoRedoArray.length - i);\n          }\n        }\n        this.actionPointer = null;\n        this.undoRedoArray.push($.extend(true, {}, data));\n      },\n\n      _configureUndoRedoArray: function() {\n\n        var data = {\n          checkboxes: [],\n          derivative: {},\n          selectedAreas: [{\n            minRow: 0,\n            minCol: 0,\n            maxRow: 0,\n            maxCol: 0\n          }],\n          focalWell: {\n            row: 0,\n            col: 0\n          }\n        };\n\n        this.undoRedoArray = []; \n        this.actionPointer = null; \n        this.undoRedoArray.push($.extend({}, data));\n      },\n\n      undo: function() {\n        console.log(\"undo\");\n        return this.shiftUndoRedo(-1); \n      },\n\n      redo: function() {\n        console.log(\"redo\");\n        return this.shiftUndoRedo(1); \n      }, \n\n      shiftUndoRedo: function (pointerDiff) {\n        var pointer = this.actionPointer;\n        if (pointer == null) {\n          pointer = this.undoRedoArray.length - 1; \n        }\n        pointer += pointerDiff; \n        return this.setUndoRedo(pointer); \n      }, \n\n      setUndoRedo: function (pointer) {\n        if (pointer < 0) {\n          return false; \n        }\n        if (pointer >= this.undoRedoArray.length) {\n          return false; \n        }\n        this.undoRedoActive = true; \n        this.setData(this.undoRedoArray[pointer]);\n        this.actionPointer = pointer; \n        this.undoRedoActive = false;\n        this.derivativeChange();\n        return true;\n      }\n    }\n  };\n\n})(jQuery, fabric);","var plateLayOutWidget = plateLayOutWidget || {};\n\n(function($, fabric) {\n\n  plateLayOutWidget.wellArea = function(fabric) {\n\n    return {\n\n      _areasToTiles: function(areas) {\n        //Convert areas to tiles\n        var cols = this.dimensions.cols;\n        var that = this;\n        return areas.reduce(function(tiles, area) {\n          if (area) {\n            for (var r = area.minRow; r <= area.maxRow; r++) {\n              for (var c = area.minCol; c <= area.maxCol; c++) {\n                var tile = that.allTiles[c + cols * r];\n                if (tiles.indexOf(tile) < 0) {\n                  if (that.disableAddDeleteWell){\n                    if(that.addressAllowToEdit.indexOf(tile.address) >= 0){\n                      tiles.push(tile);\n                    }\n                  } else {\n                    tiles.push(tile);\n                  }\n                }\n              }\n            }\n          }\n          return tiles;\n        }, []);\n      },\n\n      _encodeArea: function(area) {\n        //Encode area as string\n        if ((area.minRow == area.maxRow) && (area.minCol == area.maxCol)) {\n          return this.rowIndex[area.minRow] + area.minCol.toString(10);\n        } else {\n          return this.rowIndex[area.minRow] + area.minCol.toString(10) + \":\" + this.rowIndex[area.maxRow] + area.maxCol.toString(10);\n        }\n      },\n\n      _encodeAreas: function(areas) {\n        //Encode an array of areas as a string\n        var that = this;\n        return areas.map(function(area) {\n          return that._encodeArea(area);\n        }).join(\",\");\n      },\n\n      _decodeWell: function(wellAddress) {\n        var that = this;\n        var adRx = new RegExp(\"^\\\\s*(\" + that.rowIndex.join(\"|\") + \")(\\\\d+)\\\\s*$\")\n        var rcRx = /^\\s*R(\\d+)C(\\d+)\\s*$/i;\n\n        var match;\n        match = wellAddress.match(adRx);\n        if (match) {\n          var row = that.rowIndex.indexOf(match[1]);\n          if (row >= 0) {\n            return {\n              row: row,\n              col: parseInt(match[2]) - 1\n            };\n          }\n        }\n        match = wellAddress.match(rcRx);\n        if (match) {\n          return {\n            row: parseInt(match[1]) - 1,\n            col: parseInt(match[2]) - 1\n          };\n        }\n\n        throw \"Invalid well address: \" + wellAddress;\n      },\n\n      _decodeArea: function(areaAddress) {\n        //Decode single area as string\n        var that = this;\n        var wells = areaAddress.split(\":\").map(function(wellAddress) {\n          return that._decodeWell(wellAddress);\n        })\n        if (wells.length == 1) {\n          return {\n            minRow: wells[0].row,\n            minCol: wells[0].col,\n            maxRow: wells[0].row,\n            maxCol: wells[0].col\n          }\n        } else if (wells.length == 2) {\n          var minRow = Math.min(wells[0].row, wells[1].row)\n          return {\n            minRow: Math.min(wells[0].row, wells[1].row),\n            minCol: Math.min(wells[0].col, wells[1].col),\n            maxRow: Math.max(wells[0].row, wells[1].row),\n            maxCol: Math.max(wells[0].col, wells[1].col)\n          }\n        } else {\n          throw \"Invalid address: \" + areaAddress;\n        }\n      },\n\n      _decodeAreas: function(areasAddress) {\n        //Decode single area as string\n        var that = this;\n        return areasAddress.split(\",\").map(function(areaAddress) {\n          return that._decodeArea(areaAddress);\n        });\n      },\n\n      _wellToArea: function(well) {\n        //Convert a well to an area\n        return {\n          minCol: well.col,\n          minRow: well.row,\n          maxCol: well.col,\n          maxRow: well.row\n        }\n      },\n\n      _wellInArea: function(well, area) {\n        //Determine if a well lies within an area\n        return well.row >= area.minRow && well.row <= area.maxRow && well.col >= area.minCol && well.col <= area.maxCol;\n      },\n\n      _coordsToRect: function(startCoords, endCoords) {\n        //Convert two XY coords to a bounding box\n        var left = Math.min(startCoords.x, endCoords.x);\n        var top = Math.min(startCoords.y, endCoords.y);\n        var height = Math.abs(endCoords.y - startCoords.y);\n        var width = Math.abs(endCoords.x - startCoords.x);\n        return {\n          top: top,\n          left: left,\n          height: height,\n          width: width\n        };\n      },\n\n      _coordIndex: function(v, count) {\n        var i;\n        if (v < 0) {\n          i = 0;\n        } else if (v >= count) {\n          i = count - 1;\n        } else {\n          i = Math.floor(v);\n        }\n        return i;\n      },\n\n      _coordsToWell: function(coord) {\n        //Convert a coordinate to a well\n        var cols = this.dimensions.cols;\n        var rows = this.dimensions.rows;\n\n        var w = this.sizes.spacing; \n        var m = this.sizes.label_spacing; \n\n        var x = (coord.x - m) / w;\n        var y = (coord.y - m) / w;\n\n        var row = this._coordIndex(y, rows);\n        var col = this._coordIndex(x, cols);\n\n        return {\n          row: row,\n          col: col,\n        };\n      },\n\n      _wellToCoords: function(well, center) {\n        //Convert a well to a coordinate\n        var w = this.sizes.spacing; \n        var m = this.sizes.label_spacing; \n        var x = well.col * w + m;\n        var y = well.row * w + m;\n        if (center) {\n          var hw = w/2;\n          x = x + hw;\n          y = y + hw;\n        }\n\n        return {\n          x: x,\n          y: y\n        };\n      },\n\n      _areaToRect: function(area) {\n        //Convert area to rectangle\n        var rows = area.maxRow - area.minRow + 1;\n        var cols = area.maxCol - area.minCol + 1;\n\n        var w = this.sizes.spacing; \n        var m = this.sizes.label_spacing; \n\n        return {\n          top: area.minRow * w + m,\n          left: area.minCol * w + m,\n          height: rows * w,\n          width: cols * w\n        }\n      },\n\n      _rectToArea: function(rect) {\n        //Convert a rectangular region to an area\n        var rows = this.dimensions.rows;\n        var cols = this.dimensions.cols;\n\n        var w = this.sizes.spacing; \n        var m = this.sizes.label_spacing; \n\n        var left = (rect.left - m) / w;\n        var top = (rect.top - m) / w;\n        var height = rect.height / w;\n        var width = rect.width / w;\n        var right = left + width;\n        var bottom = top + height;\n\n        //select whole row\n        if (right < 0) {\n          right = cols;\n        }\n        if (left >= cols) {\n          left = 0;\n        }\n        //select whole col\n        if (bottom < 0) {\n          bottom = rows;\n        }\n        if (top <= 0) {\n          top = 0;\n        }\n\n        return {\n          minCol: this._coordIndex(left, cols),\n          minRow: this._coordIndex(top, rows),\n          maxCol: this._coordIndex(right, cols),\n          maxRow: this._coordIndex(bottom, rows)\n        };\n      }\n\n    }\n  }\n})(jQuery, fabric);"]}
\ No newline at end of file
diff --git a/dist/package.json b/dist/package.json
deleted file mode 100644
index 4f0efc3..0000000
--- a/dist/package.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-  "name": "plate-map",
-  "version": "1.0.2",
-  "description": "JavaScript Plate Layout is an open source tool developed collaboratively by [Chai Biotechnologies](www.chaibio.com) and [New England Biolabs](www.neb.com) for visualizing and editing the layout of scientific assay plates.",
-  "scripts": {
-    "build.dist": "gulp build.dist",
-    "build.dev": "gulp build.dev",
-    "serve.dev": "gulp serve.dev",
-    "build.prod": "gulp build.prod",
-    "serve.prod": "gulp serve.prod",
-    "start": "gulp serve.dev"
-  },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/nebiolabs/plate-map.git"
-  },
-  "main": "dist/js/plate-map.js",
-  "style": "dist/css/plate-map.css",
-  "keywords": [],
-  "author": "Langhorst, Brad <Langhorst@neb.com>",
-  "license": "AGPL-3.0-only",
-  "bugs": {
-    "url": "https://github.com/nebiolabs/plate-map/issues"
-  },
-  "homepage": "https://github.com/nebiolabs/plate-map#readme",
-  "dependencies": {
-    "bootstrap": "^4.1.3",
-    "clipboard": "^2.0.4",
-    "fabric": "^2.6.0",
-    "jquery": "^3.3.1",
-    "jquery-ui-dist": "^1.12.1",
-    "popper.js": "^1.14.7",
-    "select2": "^3.5.1"
-  },
-  "devDependencies": {
-    "browser-sync": "^2.26.3",
-    "del": "^3.0.0",
-    "gulp": "^4.0.0",
-    "gulp-clean-css": "^4.0.0",
-    "gulp-concat": "^2.6.1",
-    "gulp-connect": "^5.7.0",
-    "gulp-htmlmin": "^5.0.1",
-    "gulp-inject": "^5.0.2",
-    "gulp-rename": "^1.4.0",
-    "gulp-uglify": "^3.0.1",
-    "merge-stream": "^1.0.1",
-    "run-sequence": "^2.2.1"
-  }
-}
diff --git a/src/js/plate-layout.js b/src/js/plate-layout.js
index 87bf4ec..dae3e5f 100755
--- a/src/js/plate-layout.js
+++ b/src/js/plate-layout.js
@@ -121,8 +121,6 @@ $.widget("DNA.plateLayOut", {
       $.extend(this, new plateLayOutWidget[component](this));
     }
 
-    this.imgSrc = this.options.imgSrc || "assets";
-
     this._createInterface();
 
     this._trigger("created", null, this);

From 45738844f9284331bff5ac999580f7d0d7da4ef7 Mon Sep 17 00:00:00 2001
From: Zahen Malla Osman <zahen.malla-osman@abolis.fr>
Date: Thu, 21 Mar 2019 09:47:34 +0100
Subject: [PATCH 06/10] Indent JS files with 2-spaces + rm stackPointer param
 from setTileColor()

---
 src/js/add-data-on-change.js     |  42 +--
 src/js/add-data-to-tabs.js       |   2 +-
 src/js/add-tab-data.js           | 171 ++++-----
 src/js/add-warning-msg.js        |  26 +-
 src/js/bottom-table.js           |  10 +-
 src/js/canvas.js                 |  16 +-
 src/js/color-manager.js          |   2 +-
 src/js/create-canvas-elements.js |  92 ++---
 src/js/create-field.js           |  83 +++--
 src/js/engine.js                 |  32 +-
 src/js/example.js                | 400 ++++++++++----------
 src/js/fabric-events.js          | 100 ++---
 src/js/image_assets.js           |  16 +-
 src/js/interface.js              |  10 +-
 src/js/load-plate.js             |  42 +--
 src/js/overlay.js                |   8 +-
 src/js/plate-layout.js           | 612 +++++++++++++++----------------
 src/js/preset.js                 |   8 +-
 src/js/tabs.js                   |   4 +-
 src/js/undo-redo-manager.js      |  32 +-
 src/js/well-area.js              |  22 +-
 21 files changed, 868 insertions(+), 862 deletions(-)

diff --git a/src/js/add-data-on-change.js b/src/js/add-data-on-change.js
index d756755..5434171 100755
--- a/src/js/add-data-on-change.js
+++ b/src/js/add-data-on-change.js
@@ -17,8 +17,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
             if (tile.index in this.engine.derivative) {
               well = this.engine.derivative[tile.index];
             } else {
-              well = $.extend(true, {}, this.defaultWell); 
-              this.engine.derivative[tile.index] = well; 
+              well = $.extend(true, {}, this.defaultWell);
+              this.engine.derivative[tile.index] = well;
             }
             var processedData = this.processWellData(data, well, noOfSelectedObjects, wells);
             wells = processedData.wells;
@@ -28,8 +28,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
               if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {
                 var wellCopy = JSON.parse(JSON.stringify(well));
                 var defaultValue = this.emptyWellWithDefaultVal;
-                for (var key in defaultValue){
-                  if (key in wellCopy){
+                for (var key in defaultValue) {
+                  if (key in wellCopy) {
                     wellCopy[key] = defaultValue[key];
                     this._applyFieldData(key, defaultValue[key]);
                   }
@@ -51,13 +51,13 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
       processWellData: function(newData, curWell, noOfSelectedObjects, wellList) {
 
-        if (!wellList){
+        if (!wellList) {
           wellList = [];
         }
         for (var id in newData) {
           var v;
-          if (newData[id] !== undefined && newData[id] !== null ) {
-            if (newData[id].multi){
+          if (newData[id] !== undefined && newData[id] !== null) {
+            if (newData[id].multi) {
               var curData = newData[id];
               var preData = curWell[id];
               var newDt = this._getMultiData(preData, curData, id, noOfSelectedObjects);
@@ -83,7 +83,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var addNew = curData.added;
         var removed = curData.removed;
         if (addNew) {
-          if (preData){
+          if (preData) {
             if (addNew.value) {
               var add = true;
               for (var listIdx in preData) {
@@ -96,7 +96,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
                     if (val[fieldId].toString() === addNew.id.toString()) {
                       for (var subFieldId in val) {
                         // over write previous data if only one well is selected
-                        if (subFieldId in addNew.value && subFieldId !== fieldId){
+                        if (subFieldId in addNew.value && subFieldId !== fieldId) {
                           if (noOfSelectedObjects === 1) {
                             val[subFieldId] = addNew.value[subFieldId];
                           } else if (addNew.value[subFieldId]) {
@@ -119,7 +119,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             preData = [];
             if (addNew.value) {
               preData.push(addNew.value);
-            } else if (addNew){
+            } else if (addNew) {
               preData.push(addNew);
             }
           }
@@ -128,7 +128,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var removeListIndex = function(preData, removeIndex) {
           var newPreData = [];
           for (var idx in preData) {
-            if (parseInt(idx) !== parseInt(removeIndex)){
+            if (parseInt(idx) !== parseInt(removeIndex)) {
               newPreData.push(preData[idx]);
             }
           }
@@ -148,7 +148,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             // remove nested element
             preData = removeListIndex(preData, removeIndex);
           } else {
-            if (preData){
+            if (preData) {
               removeIndex = preData.indexOf(removed);
               if (removeIndex >= 0) {
                 preData = removeListIndex(preData, removeIndex);
@@ -157,29 +157,29 @@ var plateLayOutWidget = plateLayOutWidget || {};
           }
         }
         if (preData && (preData.length == 0)) {
-          preData = null; 
+          preData = null;
         }
         return preData
       },
 
       _colorMixer: function() {
         if (!this.undoRedoActive) {
-            var data = this.createObject();
-            this.addToUndoRedo(data);
+          var data = this.createObject();
+          this.addToUndoRedo(data);
         }
-        this.engine.searchAndStack(); 
+        this.engine.searchAndStack();
         this.engine.applyColors();
         this.mainFabricCanvas.renderAll();
       },
 
-      derivativeChange: function(){
-          this._trigger("updateWells", null, this.createObject());
+      derivativeChange: function() {
+        this._trigger("updateWells", null, this.createObject());
       },
 
       createObject: function() {
-        var derivative = $.extend(true, {}, this.engine.derivative); 
-        var checkboxes = this.globalSelectedAttributes.slice(); 
-        var selectedAreas = this.selectedAreas.slice(); 
+        var derivative = $.extend(true, {}, this.engine.derivative);
+        var checkboxes = this.globalSelectedAttributes.slice();
+        var selectedAreas = this.selectedAreas.slice();
         var focalWell = this.focalWell;
 
         return {
diff --git a/src/js/add-data-to-tabs.js b/src/js/add-data-to-tabs.js
index 095a29e..9f4ad50 100755
--- a/src/js/add-data-to-tabs.js
+++ b/src/js/add-data-to-tabs.js
@@ -14,7 +14,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
       },
 
       _applyFieldData: function(id, v) {
-        this.fieldMap[id].setValue(v); 
+        this.fieldMap[id].setValue(v);
       }
     }
   }
diff --git a/src/js/add-tab-data.js b/src/js/add-tab-data.js
index 1bc7c44..c08e86a 100755
--- a/src/js/add-tab-data.js
+++ b/src/js/add-tab-data.js
@@ -6,55 +6,56 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
     return {
 
-      fieldList: [], 
+      fieldList: [],
       fieldMap: {},
       autoId: 1,
 
       _addTabData: function() {
-          // Here we may need more changes because attributes format likely to change
-          var tabData = this.options.attributes.tabs;
-          var that = this;
-          this.requiredField = [];
-          var multiplexFieldArray = [];
-          tabData.forEach(function (tab, tabPointer) {
-            if (tab["fields"]) {
-              var tabFields = tab["fields"];
-              var fieldArray = [];
-              var fieldArrayIndex = 0;
-              // Now we look for fields in the json
-              for (var field in tabFields) {
-                var data = tabFields[field];
-
-                if (!data.id) {
-                  data.id = "Auto" + that.autoId++;
-                  console.log("Field autoassigned id " + data.id);
-                }
-                if (!data.type) {
-                  data.type = "text";
-                  console.log("Field " + data.id + " autoassigned type " + data.type);
-                }
+        // Here we may need more changes because attributes format likely to change
+        var tabData = this.options.attributes.tabs;
+        var that = this;
+        this.requiredField = [];
+        var multiplexFieldArray = [];
+        tabData.forEach(function(tab, tabPointer) {
+          if (tab["fields"]) {
+            var tabFields = tab["fields"];
+            var fieldArray = [];
+            var fieldArrayIndex = 0;
+            // Now we look for fields in the json
+            for (var field in tabFields) {
+              var data = tabFields[field];
+
+              if (!data.id) {
+                data.id = "Auto" + that.autoId++;
+                console.log("Field autoassigned id " + data.id);
+              }
+              if (!data.type) {
+                data.type = "text";
+                console.log("Field " + data.id + " autoassigned type " + data.type);
+              }
 
-                var field_val;
-                if (data.type === "multiplex") {
-                  field_val = that._makeMultiplexField(data, tabPointer, fieldArray);
+              var field_val;
+              if (data.type === "multiplex") {
+                field_val = that._makeMultiplexField(data, tabPointer, fieldArray);
+                multiplexFieldArray.push(field_val);
+              } else {
+                field_val = that._makeRegularField(data, tabPointer, fieldArray, true);
+                if (data.type === "multiselect") {
                   multiplexFieldArray.push(field_val);
-                } else {
-                  field_val = that._makeRegularField(data, tabPointer, fieldArray, true);
-                  if (data.type === "multiselect") {
-                    multiplexFieldArray.push(field_val);
-                  }
-                };
+                }
               }
-
-              that.allDataTabs[tabPointer]["fields"] = fieldArray;
-            } else {
-              console.log("unknown format in field initialization");
+              ;
             }
-          });
-          that.multipleFieldList = multiplexFieldArray;
+
+            that.allDataTabs[tabPointer]["fields"] = fieldArray;
+          } else {
+            console.log("unknown format in field initialization");
+          }
+        });
+        that.multipleFieldList = multiplexFieldArray;
       },
 
-      _makeSubField: function (data, tabPointer, fieldArray) {
+      _makeSubField: function(data, tabPointer, fieldArray) {
         var that = this;
         if (!data.id) {
           data.id = "Auto" + that.autoId++;
@@ -90,52 +91,52 @@ var plateLayOutWidget = plateLayOutWidget || {};
         return field;
       },
 
-      _makeRegularField: function (data, tabPointer, fieldArray, checkbox){
-          var that = this;
-          var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
-          var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
-          var wrapperDivRightSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-right-side ");
-          var nameContainer = that._createElement("<div></div>").addClass("plate-setup-tab-name").text(data.name);
-          var fieldContainer = that._createElement("<div></div>").addClass("plate-setup-tab-field-container");
-
-          wrapperDivRightSide.append(nameContainer);
-          wrapperDivRightSide.append(fieldContainer);
-          wrapperDiv.append(wrapperDivLeftSide);
-          wrapperDiv.append(wrapperDivRightSide);
-          that.allDataTabs[tabPointer].append(wrapperDiv);
-
-          var field = {
-            id: data.id,
-            name: data.name,
-            root: wrapperDiv,
-            data: data,
-            required: data.required
-          };
+      _makeRegularField: function(data, tabPointer, fieldArray, checkbox) {
+        var that = this;
+        var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
+        var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
+        var wrapperDivRightSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-right-side ");
+        var nameContainer = that._createElement("<div></div>").addClass("plate-setup-tab-name").text(data.name);
+        var fieldContainer = that._createElement("<div></div>").addClass("plate-setup-tab-field-container");
 
-          if (field.required) {
-            that.requiredField.push(field.id);
-          }
+        wrapperDivRightSide.append(nameContainer);
+        wrapperDivRightSide.append(fieldContainer);
+        wrapperDiv.append(wrapperDivLeftSide);
+        wrapperDiv.append(wrapperDivRightSide);
+        that.allDataTabs[tabPointer].append(wrapperDiv);
 
-          fieldArray.push(field);
-          that.fieldList.push(field);
-          that.fieldMap[field.id] = field;
+        var field = {
+          id: data.id,
+          name: data.name,
+          root: wrapperDiv,
+          data: data,
+          required: data.required
+        };
 
-          // Adding checkbox
-          if (checkbox) {
-            that._addCheckBox(field);
-          }
-          that._createField(field);
+        if (field.required) {
+          that.requiredField.push(field.id);
+        }
 
-          field.onChange = function () {
-            var v = field.getValue();
-            var data = {};
-            data[field.id] = v;
-            that._addAllData(data);
-          };
-          return field;
+        fieldArray.push(field);
+        that.fieldList.push(field);
+        that.fieldMap[field.id] = field;
+
+        // Adding checkbox
+        if (checkbox) {
+          that._addCheckBox(field);
+        }
+        that._createField(field);
+
+        field.onChange = function() {
+          var v = field.getValue();
+          var data = {};
+          data[field.id] = v;
+          that._addAllData(data);
+        };
+        return field;
       },
 
-      _makeMultiplexField: function (data, tabPointer, fieldArray) {
+      _makeMultiplexField: function(data, tabPointer, fieldArray) {
         var that = this;
         var wrapperDiv = that._createElement("<div></div>").addClass("plate-setup-tab-default-field");
         var wrapperDivLeftSide = that._createElement("<div></div>").addClass("plate-setup-tab-field-left-side");
@@ -177,7 +178,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         //store required field
         if (field.required || requiredSubField.length) {
-          this.requiredField.push ({
+          this.requiredField.push({
             multiplexId: field.id,
             subFields: requiredSubField
           });
@@ -187,14 +188,14 @@ var plateLayOutWidget = plateLayOutWidget || {};
         that._createField(field);
         that._addCheckBox(field);
 
-        subFieldList.forEach(function (subfield) {
+        subFieldList.forEach(function(subfield) {
           subfield.mainMultiplexField = field;
           fieldArray.push(subfield);
           that._createField(subfield);
           that._addCheckBox(subfield);
           delete that.defaultWell[subfield.id];
           // overwrite subField setvalue
-          subfield.onChange = function () {
+          subfield.onChange = function() {
             var v = subfield.getValue();
             var mainRefField = subfield.mainMultiplexField;
             var curId = mainRefField.singleSelectValue();
@@ -211,7 +212,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             field._changeMultiFieldValue(returnVal, null);
             var curDataLs = mainRefField.detailData;
             if (curDataLs !== null) {
-              curId = mainRefField.singleSelectValue(); 
+              curId = mainRefField.singleSelectValue();
               curDataLs = curDataLs.map(function(curData) {
                 if (curData[mainRefField.id] === curId) {
                   curData[subfield.id] = v;
@@ -224,10 +225,10 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         });
 
-        field.getValue = function(){
+        field.getValue = function() {
           var v = field.input.select2('data');
           if (v.length) {
-            return v.map(function (i) {
+            return v.map(function(i) {
               return i.id;
             });
           }
diff --git a/src/js/add-warning-msg.js b/src/js/add-warning-msg.js
index 963664b..c607f21 100644
--- a/src/js/add-warning-msg.js
+++ b/src/js/add-warning-msg.js
@@ -2,16 +2,16 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
 (function($, fabric) {
 
-  plateLayOutWidget.addWarningMsg = function () {
+  plateLayOutWidget.addWarningMsg = function() {
     // For those check boxes associated with every field in the tab
     return {
-      fieldWarningMsg: function (field, text, include) {
+      fieldWarningMsg: function(field, text, include) {
         var that = this;
         var imgId = "fieldWarning" + field.id;
         var img = $("<span>").html(that._assets.warningImg).attr("id", imgId).addClass("plate-field-warning-image");
         //field.root.find(".plate-setup-tab-name").append('<img id="theImg" src="theImg.png" />')
         if (include) {
-          if (field.root.find("#" + imgId).length <= 0){
+          if (field.root.find("#" + imgId).length <= 0) {
             field.root.find(".plate-setup-tab-name").text(" " + field.name);
             field.root.find(".plate-setup-tab-name").prepend(img);
 
@@ -19,9 +19,9 @@ var plateLayOutWidget = plateLayOutWidget || {};
             popText.text(text);
             field.root.find(".plate-setup-tab-name").append(popText);
 
-            $("#" + imgId).hover(function (e) {
+            $("#" + imgId).hover(function(e) {
               popText[0].style.display = 'flex';
-            }, function () {
+            }, function() {
               popText.hide();
             });
           }
@@ -35,7 +35,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         }
       },
 
-      removeWarningMsg: function (field, text, include) {
+      removeWarningMsg: function(field, text, include) {
         var that = this;
         var imgId = "fieldWarning" + field.id;
         var img = $("<span>").html(that._assets.warningImg).attr("id", imgId).addClass("plate-field-warning-image");
@@ -47,9 +47,9 @@ var plateLayOutWidget = plateLayOutWidget || {};
           popText.text(text);
           field.root.find(".plate-setup-tab-name").append(popText);
 
-          $("#" + imgId).hover(function (e) {
+          $("#" + imgId).hover(function(e) {
             popText[0].style.display = 'inline-block';
-          }, function () {
+          }, function() {
             popText.hide();
           });
 
@@ -67,11 +67,11 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var req = 0;
         var fill = 0;
         var fieldData = {};
-        that.fieldList.forEach(function(field){
+        that.fieldList.forEach(function(field) {
           fieldData[field.id] = [];
         });
-        wells.forEach(function(well){
-          if (!that.engine.wellEmpty(well)){
+        wells.forEach(function(well) {
+          if (!that.engine.wellEmpty(well)) {
             for (var fieldId in fieldData) {
               if (fieldId in well) {
                 fieldData[fieldId].push(well[fieldId]);
@@ -83,12 +83,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
         });
         for (var i = 0; i < that.fieldList.length; i++) {
           var field = that.fieldList[i];
-          if (field.applyMultiplexSubFieldColor){
+          if (field.applyMultiplexSubFieldColor) {
             field.applyMultiplexSubFieldColor(fieldData[field.id]);
           } else {
             if (field.required) {
               var include = false;
-              fieldData[field.id].forEach(function(val){
+              fieldData[field.id].forEach(function(val) {
                 // for multiselect
                 if (val instanceof Array) {
                   if (val.length === 0) {
diff --git a/src/js/bottom-table.js b/src/js/bottom-table.js
index c728ea6..bcbf12d 100755
--- a/src/js/bottom-table.js
+++ b/src/js/bottom-table.js
@@ -54,13 +54,13 @@ var plateLayOutWidget = plateLayOutWidget || {};
         numberText.text(color);
         plateIdDiv.append(numberText);
 
-        numberText.click(function(evt){
-          var addressToSelect = singleStack.map(function(addressIdx){
+        numberText.click(function(evt) {
+          var addressToSelect = singleStack.map(function(addressIdx) {
             return that.indexToAddress(addressIdx)
           });
           if (evt.ctrlKey) {
-            that.getSelectedAddress().forEach(function(val){
-              if (addressToSelect.indexOf(val) < 0){
+            that.getSelectedAddress().forEach(function(val) {
+              if (addressToSelect.indexOf(val) < 0) {
                 addressToSelect.push(val);
               }
             })
@@ -146,7 +146,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var dim = this.getDimensions();
         var that = this;
         for (var colorIdx in colorLocIdxMap) {
-          colorLocMap[colorIdx] = colorLocIdxMap[colorIdx].map(function (locIdx) {
+          colorLocMap[colorIdx] = colorLocIdxMap[colorIdx].map(function(locIdx) {
             return that.indexToAddress(locIdx, dim);
           })
         }
diff --git a/src/js/canvas.js b/src/js/canvas.js
index badb587..ea4a5d7 100755
--- a/src/js/canvas.js
+++ b/src/js/canvas.js
@@ -20,18 +20,18 @@ var plateLayOutWidget = plateLayOutWidget || {};
       },
 
       _initiateFabricCanvas: function() {
-        var w = this.canvasContainer.width(); 
-        var h = this.canvasContainer.height(); 
+        var w = this.canvasContainer.width();
+        var h = this.canvasContainer.height();
 
         this._setCanvasArea(w, h);
 
         this.mainFabricCanvas = new fabric.Canvas('DNAcanvas', {
-            backgroundColor: '#f5f5f5',
-            selection: false,
-            stateful: false,
-            hoverCursor: "pointer",
-            renderOnAddRemove: false,
-          })
+          backgroundColor: '#f5f5f5',
+          selection: false,
+          stateful: false,
+          hoverCursor: "pointer",
+          renderOnAddRemove: false,
+        })
           .setWidth(w)
           .setHeight(h);
       },
diff --git a/src/js/color-manager.js b/src/js/color-manager.js
index 4568a11..24dc3a7 100755
--- a/src/js/color-manager.js
+++ b/src/js/color-manager.js
@@ -5,7 +5,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
   plateLayOutWidget.colorManager = function() {
 
     return {
-        // See these are color pairs for the gradient.
+      // See these are color pairs for the gradient.
       colorPairs: [
         ["#e6e6e6", "#808080"],
         ["#66e8ff", "#0082c8"],
diff --git a/src/js/create-canvas-elements.js b/src/js/create-canvas-elements.js
index f3bfa5a..afdf49d 100755
--- a/src/js/create-canvas-elements.js
+++ b/src/js/create-canvas-elements.js
@@ -6,31 +6,31 @@ var plateLayOutWidget = plateLayOutWidget || {};
     // this class manages creating all the elements within canvas
     return {
 
-      scaleFactor: 1, 
+      scaleFactor: 1,
 
       baseSizes: {
-        spacing: 48, 
-        tile_radius: 22, 
-        center_radius_complete: 10, 
-        center_radius_incomplete: 14, 
-        label_size: 14, 
-        label_spacing: 24, 
+        spacing: 48,
+        tile_radius: 22,
+        center_radius_complete: 10,
+        center_radius_incomplete: 14,
+        label_size: 14,
+        label_spacing: 24,
         text_size: 13,
-        stroke: 0.5, 
+        stroke: 0.5,
         gap: 2
-      }, 
+      },
 
       _setCanvasArea: function(w, h) {
         this.scaleFactor = Math.min(
-           h / (this.dimensions.rows * this.baseSizes.spacing + this.baseSizes.label_spacing), 
-           w / (this.dimensions.cols * this.baseSizes.spacing + this.baseSizes.label_spacing));
+          h / (this.dimensions.rows * this.baseSizes.spacing + this.baseSizes.label_spacing),
+          w / (this.dimensions.cols * this.baseSizes.spacing + this.baseSizes.label_spacing));
 
-        var sizes = {}
+        var sizes = {};
         for (var prop in this.baseSizes) {
-          sizes[prop] = this.baseSizes[prop] * this.scaleFactor; 
+          sizes[prop] = this.baseSizes[prop] * this.scaleFactor;
         }
-        this.sizes = sizes; 
-      }, 
+        this.sizes = sizes;
+      },
 
       _canvas: function() {
         // Those 1,2,3 s and A,B,C s
@@ -46,12 +46,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         var spacing = this.sizes.spacing;
         var d1 = this.sizes.label_spacing / 2;
-        var d2 = this.sizes.label_spacing + this.sizes.spacing / 2; 
-        var fontSize = this.sizes.label_size; 
+        var d2 = this.sizes.label_spacing + this.sizes.spacing / 2;
+        var fontSize = this.sizes.label_size;
 
         // For column
-        var top = d1; 
-        var left = d2;  
+        var top = d1;
+        var left = d2;
         for (var i = 1; i <= cols; i++) {
           var tempFabricText = new fabric.IText(i.toString(), {
             fill: 'black',
@@ -64,16 +64,16 @@ var plateLayOutWidget = plateLayOutWidget || {};
             selectable: false,
             fontWeight: "400"
           });
-          left += spacing; 
+          left += spacing;
 
           this.mainFabricCanvas.add(tempFabricText);
         }
 
         // for row
-        top = d2; 
-        left = d1; 
+        top = d2;
+        left = d1;
         for (var i = 1; i <= rows; i++) {
-          var tempFabricText = new fabric.IText(this.rowIndex[i-1], {
+          var tempFabricText = new fabric.IText(this.rowIndex[i - 1], {
             fill: 'black',
             originX: 'center',
             originY: 'center',
@@ -84,7 +84,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             selectable: false,
             fontWeight: "400"
           });
-          top += spacing; 
+          top += spacing;
 
           this.mainFabricCanvas.add(tempFabricText);
         }
@@ -97,9 +97,9 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var tileCounter = 0;
         for (var row = 0; row < rows; row++) {
           for (var col = 0; col < cols; col++) {
-            var index = this.allTiles.length; 
-            var tile = this._createTile(row, col); 
-            tile.index = tileCounter++; 
+            var index = this.allTiles.length;
+            var tile = this._createTile(row, col);
+            tile.index = tileCounter++;
             this.allTiles.push(tile);
             this.mainFabricCanvas.add(tile.background);
             this.mainFabricCanvas.add(tile.highlight);
@@ -113,17 +113,17 @@ var plateLayOutWidget = plateLayOutWidget || {};
         this._fabricEvents();
       },
 
-      _createTile: function (row, col) {
-        var tile = {}; 
+      _createTile: function(row, col) {
+        var tile = {};
 
-        tile.visible = false; 
-        tile.colorIndex = null; 
-        tile.row = row; 
-        tile.col = col; 
-        tile.address = this.rowIndex[row] + (col + 1); 
+        tile.visible = false;
+        tile.colorIndex = null;
+        tile.row = row;
+        tile.col = col;
+        tile.address = this.rowIndex[row] + (col + 1);
 
         var top = (row + 1) * this.sizes.spacing;
-        var left = (col + 1) * this.sizes.spacing; 
+        var left = (col + 1) * this.sizes.spacing;
 
         tile.background = new fabric.Circle({
           top: top,
@@ -140,8 +140,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         tile.background.setGradient("fill", {
           type: "radial",
-          x1: this.sizes.tile_radius, 
-          x2: this.sizes.tile_radius, 
+          x1: this.sizes.tile_radius,
+          x2: this.sizes.tile_radius,
           y1: this.sizes.tile_radius + this.sizes.gap,
           y2: this.sizes.tile_radius + this.sizes.gap,
           r1: this.sizes.tile_radius - this.sizes.gap,
@@ -172,7 +172,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           radius: this.sizes.tile_radius,
           stroke: 'gray',
           strokeWidth: this.sizes.stroke,
-          evented: false, 
+          evented: false,
           visible: false
         });
 
@@ -203,10 +203,10 @@ var plateLayOutWidget = plateLayOutWidget || {};
           visible: false
         });
 
-        return tile; 
-      }, 
+        return tile;
+      },
 
-      setTileComplete: function (tile, complete) {
+      setTileComplete: function(tile, complete) {
         if (complete) {
           tile.circleCenter.radius = this.sizes.center_radius_complete;
           tile.circleText.fill = "black";
@@ -216,22 +216,22 @@ var plateLayOutWidget = plateLayOutWidget || {};
           tile.circleText.fill = "red";
           tile.circleText.fontWeight = 'bold';
         }
-      }, 
+      },
 
-      setTileVisible: function (tile, visible) {
+      setTileVisible: function(tile, visible) {
         tile.visible = visible;
         tile.circle.visible = tile.visible;
         tile.circleCenter.visible = tile.visible;
         tile.circleText.visible = tile.visible;
       },
 
-      setTileColor: function(tile, color, stackPointer) {
+      setTileColor: function(tile, color) {
         this.setTileVisible(tile, true);
-        tile.colorIndex = parseInt(color); 
+        tile.colorIndex = parseInt(color);
         tile.circleText.text = String(tile.colorIndex);
 
         if (color > 0) {
-          color = ((color - 1) % (this.colorPairs.length -1)) + 1;
+          color = ((color - 1) % (this.colorPairs.length - 1)) + 1;
         }
         var colorStops = this.colorPairs[color];
 
diff --git a/src/js/create-field.js b/src/js/create-field.js
index 2792cb7..249cc8f 100755
--- a/src/js/create-field.js
+++ b/src/js/create-field.js
@@ -273,15 +273,14 @@ var plateLayOutWidget = plateLayOutWidget || {};
           return "";
         };
 
-        field.multiOnChange = function (added, removed) {
+        field.multiOnChange = function(added, removed) {
           if (added) {
             added = added.id.toString();
           }
           if (removed) {
             removed = removed.id.toString();
           }
-          var data = {
-          };
+          var data = {};
           data[field.id] = {
             multi: true,
             added: added,
@@ -291,7 +290,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           that._addAllData(data);
         };
 
-        field.parseText = function(value){
+        field.parseText = function(value) {
           var v = value;
           if (v && v.length) {
             v = v.map(function(opt) {
@@ -559,7 +558,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         // val now contains unit
         field.getText = function(val) {
-          if (typeof(val) === 'object' && val) {
+          if (typeof (val) === 'object' && val) {
             var v = val.value;
             var u = val.unit;
             if (v == null) {
@@ -586,9 +585,9 @@ var plateLayOutWidget = plateLayOutWidget || {};
           return v;
         };
 
-        field.parseText = function(v){
+        field.parseText = function(v) {
           var textVal = field.parseValue(v);
-          if (textVal && typeof(textVal) === "object"){
+          if (textVal && typeof (textVal) === "object") {
             return textVal.value + textVal.unit;
           } else if (textVal) {
             return textVal
@@ -726,7 +725,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         field.singleSelect.appendTo(fieldContainer1);
 
-        field.singleSelectValue = function () {
+        field.singleSelectValue = function() {
           var v = field.singleSelect.select2("data");
           if (v != null) {
             v = v.id;
@@ -734,7 +733,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           return v;
         };
 
-        var setSingleSelectOptions = function (v, selected_v) {
+        var setSingleSelectOptions = function(v, selected_v) {
           var opts = {
             allowClear: false,
             placeholder: "select",
@@ -754,7 +753,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           field.singleSelect.prop("disabled", opts.data.length == 0);
         };
 
-        var singleSelectChange = function () {
+        var singleSelectChange = function() {
           var v = field.singleSelectValue();
 
           field.updateSubFieldUnitOpts(v);
@@ -808,7 +807,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           }
 
           if (removed) {
-            if (removed.value){
+            if (removed.value) {
               val = removed.value;
             } else {
               newSubFieldValue[field.id] = removed.id;
@@ -891,7 +890,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           field.subFieldList.forEach(function(subField) {
             if (subField.data.hasMultiplexUnit) {
               if (curOpts && curOpts.hasOwnProperty("unitOptions")) {
-								subField.setUnitOpts(curOpts.unitOptions[subField.id]);
+                subField.setUnitOpts(curOpts.unitOptions[subField.id]);
               } else {
                 subField.setUnitOpts(null);
               }
@@ -945,7 +944,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
                       });
                     } else {
                       if (subfield.data.units) {
-                        if (subfield.data.units.length > 1){
+                        if (subfield.data.units.length > 1) {
                           subfield.disabled(false);
                         }
                       }
@@ -955,8 +954,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
                       };
                       newVal[subfield.id] = subfield.parseValue(val);
                     }
-                  }
-                   else {
+                  } else {
                     newVal[subfield.id] = subfield.parseValue(null);
                   }
                 });
@@ -1040,7 +1038,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
           var valCount = 0;
           var completionPct = 0;
           var include = false;
-          function getSubfieldStatus (vals) {
+
+          function getSubfieldStatus(vals) {
             var req = 0;
             var fill = 0;
             for (var subFieldId in field.subFieldList) {
@@ -1049,7 +1048,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
               if (subField.required) {
                 include = true;
                 req++;
-                if (typeof(curVal) === 'object' && curVal) {
+                if (typeof curVal === 'object' && curVal) {
                   if (curVal.value) {
                     fill++;
                   }
@@ -1058,12 +1057,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
                 }
               }
             }
-            return fill/req;
+            return fill / req;
           }
 
           // for cases has value in multiplex field
           if (valList) {
-            if (valList.length > 0){
+            if (valList.length > 0) {
               for (var idx in valList) {
                 valCount++;
                 var vals = valList[idx];
@@ -1073,37 +1072,37 @@ var plateLayOutWidget = plateLayOutWidget || {};
               include = true;
               valCount = 1;
             }
-          }  else if (field.required) {
+          } else if (field.required) {
             include = true;
             valCount = 1;
           }
 
           return {
             include: include,
-            completionPct: completionPct/valCount
+            completionPct: completionPct / valCount
           };
         };
 
         // valList contains all of the vals for selected val
-        field.applyMultiplexSubFieldColor = function(valList){
-          function updateSubFieldWarningMap (vals) {
+        field.applyMultiplexSubFieldColor = function(valList) {
+          function updateSubFieldWarningMap(vals) {
             for (var subFieldId in field.subFieldList) {
               var subField = field.subFieldList[subFieldId];
               // loop through each well's multiplexval list
-              if (vals === null){
-                if (field.required && subField.required){
+              if (vals === null) {
+                if (field.required && subField.required) {
                   subFieldWarningMap[subField.id].warningStatus.push(true);
                 }
-              } else if (typeof(vals) === "object") {
+              } else if (typeof (vals) === "object") {
                 if (vals.length === 0) {
-                  if (field.required && subField.required){
+                  if (field.required && subField.required) {
                     subFieldWarningMap[subField.id].warningStatus.push(true);
                   }
                 } else {
                   for (var multiplexIdx in vals) {
                     var curVal = vals[multiplexIdx][subField.id];
                     if (subField.required) {
-                      if (typeof(curVal) === 'object' && curVal) {
+                      if (typeof (curVal) === 'object' && curVal) {
                         if (!curVal.value) {
                           subFieldWarningMap[subField.id].warningStatus.push(true);
                         } else {
@@ -1122,7 +1121,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           }
 
           var subFieldWarningMap = {};
-          field.subFieldList.forEach(function(subField){
+          field.subFieldList.forEach(function(subField) {
             if (subField.required) {
               subFieldWarningMap[subField.id] = {
                 field: subField,
@@ -1138,11 +1137,11 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
           var requiredSubField = [];
           var mainFieldStatus = [];
-          for (var subFieldId in subFieldWarningMap){
+          for (var subFieldId in subFieldWarningMap) {
             var subField = subFieldWarningMap[subFieldId].field;
             if (subFieldWarningMap[subFieldId].warningStatus.indexOf(true) >= 0) {
-              var text =  subField.name + " is a required subfield for " + field.name + ", please make sure all " + field.name + " have " + subField.name;
-              if (field.required){
+              var text = subField.name + " is a required subfield for " + field.name + ", please make sure all " + field.name + " have " + subField.name;
+              if (field.required) {
                 that.fieldWarningMsg(subField, text, true);
                 mainFieldStatus.push(true);
               } else {
@@ -1171,16 +1170,16 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         field.parseMainFieldVal = function(val) {
           var optMap = field.data.options;
-          for (var idx = 0; idx < optMap.length; idx++){
+          for (var idx = 0; idx < optMap.length; idx++) {
             var curOpt = optMap[idx];
-            if (curOpt.id === val){
+            if (curOpt.id === val) {
               return curOpt.text
             }
           }
         };
       },
 
-      _deleteDialog: function (field) {
+      _deleteDialog: function(field) {
         var that = this;
 
         var valMap = field.allSelectedMultipleVal;
@@ -1204,7 +1203,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var tableArea = $("<div/>").appendTo(dialogContent);
         var buttonRow = $("<div/>").addClass("dialog-buttons").css("justify-content", "flex-end").appendTo(dialogContent);
 
-        if (valToRemove.length > 0){
+        if (valToRemove.length > 0) {
           // apply CSS property for table
           $("<p/>").text(field.name + " in selected wells: choose items to delete and click the delete button below").appendTo(tableArea);
 
@@ -1218,7 +1217,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             var deleteCheckedButton = $("<button class='multiple-field-manage-delete-button'>Delete Checked Items</button>");
             buttonRow.append(deleteCheckedButton);
             deleteCheckedButton.click(function() {
-              table.find("input:checked").each(function () {
+              table.find("input:checked").each(function() {
                 var val = this.value;
                 field.multiOnChange(null, {id: val});
               });
@@ -1245,7 +1244,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         }
       },
 
-      _deleteDialogTable: function (field, valMap) {
+      _deleteDialogTable: function(field, valMap) {
         var that = this;
         var colName = [field.name, "Counts"]; //Added because it was missing... no idea what the original should have been
         if (!that.readOnly) {
@@ -1255,13 +1254,13 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var thead = $('<thead/>').appendTo(table);
         var tr = $('<tr/>').appendTo(thead);
 
-        tr.append(colName.map(function (text) {
+        tr.append(colName.map(function(text) {
           return $('<th/>').text(text);
         }));
 
         var tbody = $("<tbody/>").appendTo(table);
 
-        field.data.options.forEach(function (opt) {
+        field.data.options.forEach(function(opt) {
           if (opt.id in valMap) {
             var tr = $('<tr/>').appendTo(tbody);
             var checkbox = $("<input type='checkbox'>").prop("value", opt.id);
@@ -1276,7 +1275,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         return table;
       },
 
-      _createDeleteButton: function (field) {
+      _createDeleteButton: function(field) {
         var that = this;
         var deleteButton = $("<button/>").addClass("plate-setup-remove-all-button");
         deleteButton.id = field.id + "Delete";
@@ -1287,7 +1286,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         field.deleteButton = deleteButton;
         field.root.find(".plate-setup-tab-field-right-side").append(buttonContainer);
 
-        deleteButton.click(function () {
+        deleteButton.click(function() {
           that._deleteDialog(field);
         });
       }
diff --git a/src/js/engine.js b/src/js/engine.js
index 35316cd..d0694f4 100755
--- a/src/js/engine.js
+++ b/src/js/engine.js
@@ -14,7 +14,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         stackUpWithColor: {},
         stackPointer: 2,
 
-        wellEmpty: function (well) {
+        wellEmpty: function(well) {
           for (var prop in well) {
             var curVal = well[prop];
             if (curVal !== null && curVal !== undefined) {
@@ -39,16 +39,16 @@ var plateLayOutWidget = plateLayOutWidget || {};
             var data = this.derivative[idx];
             var wellData = {};
             for (var i = 0; i < THIS.globalSelectedAttributes.length; i++) {
-              var attr = THIS.globalSelectedAttributes[i]; 
+              var attr = THIS.globalSelectedAttributes[i];
 
-              if (attr in THIS.globalSelectedMultiplexSubfield){
+              if (attr in THIS.globalSelectedMultiplexSubfield) {
                 var selectedSubFields = THIS.globalSelectedMultiplexSubfield[attr];
                 var newMultiplexVal = [];
-                for (var multiplexIdx in data[attr]){
+                for (var multiplexIdx in data[attr]) {
                   var curMultiplexVals = data[attr][multiplexIdx];
                   var newVal = {};
                   newVal[attr] = curMultiplexVals[attr];
-                  selectedSubFields.forEach(function (subFieldId) {
+                  selectedSubFields.forEach(function(subFieldId) {
                     newVal[subFieldId] = curMultiplexVals[subFieldId];
                   });
                   newMultiplexVal.push(newVal);
@@ -61,15 +61,19 @@ var plateLayOutWidget = plateLayOutWidget || {};
               }
             }
             if ($.isEmptyObject(wellData)) {
-              derivativeJson[idx] = null; 
+              derivativeJson[idx] = null;
             } else {
               derivativeJson[idx] = JSON.stringify(wellData);
             }
           }
 
           while (!$.isEmptyObject(derivativeJson)) {
-            var keys = Object.keys(derivativeJson).map(function (k) {return parseFloat(k, 10);});
-            keys.sort(function (a, b) {return a-b;}); 
+            var keys = Object.keys(derivativeJson).map(function(k) {
+              return parseFloat(k, 10);
+            });
+            keys.sort(function(a, b) {
+              return a - b;
+            });
 
             var refDerivativeIndex = keys[0];
             var referenceDerivative = derivativeJson[refDerivativeIndex];
@@ -87,7 +91,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             } else {
               // if checked boxes have values
               for (var i = 0; i < keys.length; i++) {
-                var idx = keys[i]; 
+                var idx = keys[i];
                 if (referenceDerivative == derivativeJson[idx]) {
                   arr.push(idx);
                   this.stackUpWithColor[this.stackPointer] = arr;
@@ -119,14 +123,14 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
               for (var tileIndex in arr) {
                 wholeNoTiles++;
-                var index = this.stackUpWithColor[color][tileIndex]; 
+                var index = this.stackUpWithColor[color][tileIndex];
                 var tile = THIS.allTiles[index];
                 var well = this.derivative[index];
                 this.colorMap.set(index, color);
                 THIS.setTileColor(tile, color);
                 // Checks if all the required fields are filled
                 var completion = this.checkCompletion(well, tile);
-                THIS.setTileComplete(tile, completion == 1); 
+                THIS.setTileComplete(tile, completion == 1);
                 wholePercentage = wholePercentage + completion;
               }
             }
@@ -142,11 +146,11 @@ var plateLayOutWidget = plateLayOutWidget || {};
         },
 
         checkCompletion: function(wellData, tile) {
-          var req = 0; 
+          var req = 0;
           var fill = 0;
           for (var i = 0; i < THIS.fieldList.length; i++) {
             var field = THIS.fieldList[i];
-            if (field.checkMultiplexCompletion){
+            if (field.checkMultiplexCompletion) {
               // also apply color
               var multiplexStatus = field.checkMultiplexCompletion(wellData[field.id]);
               if (multiplexStatus.include) {
@@ -163,7 +167,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             }
           }
           if (req === fill) {
-            return 1; 
+            return 1;
           }
           return fill / req;
         },
diff --git a/src/js/example.js b/src/js/example.js
index 4080092..fbf4af7 100644
--- a/src/js/example.js
+++ b/src/js/example.js
@@ -1,210 +1,212 @@
 // Wait for all the script load from the loader.js and fire up
-window.onload = function () {
-    var fields = {
-        polymerase: {
-            required: true,
-            id: 'pol',
-            name: 'Polymerase',
-            type: 'multiselect',
-            placeHolder: "Polymerase",
-            options: [
-                {
-                    id: 234,
-                    text: 'Taq 1, processive enzyme with long name'
-                },
-                {
-                    id: 123,
-                    text: 'Taq 2'
-                },
-                {
-                    id: 3,
-                    text: 'Taq 3'
-                },
-                {
-                    id: 4,
-                    text: 'Taq 4'
-                },
-                {
-                    id: 5,
-                    text: 'Taq 5'
-                }
-            ]
+window.onload = function() {
+  var fields = {
+    polymerase: {
+      required: true,
+      id: 'pol',
+      name: 'Polymerase',
+      type: 'multiselect',
+      placeHolder: "Polymerase",
+      options: [
+        {
+          id: 234,
+          text: 'Taq 1, processive enzyme with long name'
         },
-        volume: {
-            required: true,
-            id: 'volume',
-            name: 'Volume',
-            type: 'numeric',
-            placeholder: "Volume",
-            units: ["uL", "mL"],
-            defaultUnit: "uL"
+        {
+          id: 123,
+          text: 'Taq 2'
         },
-        conc: {
-            required: true,
-            id: 'conc',
-            name: 'Concentration',
-            type: 'numeric',
-            placeholder: "Conc.",
-            defaultUnit: "ng/ul (final)"
+        {
+          id: 3,
+          text: 'Taq 3'
         },
-        on_ice: {
-            required: true,
-            id: "on_ice",
-            name: "On Ice",
-            type: "boolean",
-            placeHolder: "On Ice"
-        }
-    };
-    var amplicons_field = {
-        amplicons: {
-            required: true,
-            id: 'amplicons',
-            name: "Amplicons",
-            type: "multiplex",
-            placeHolder: "Amplicons",
-            options: [
-                {
-                    id: 'A',
-                    text: 'Amplicon_A'
-                },
-                {
-                    id: 'B',
-                    text: 'Amplicon_B'
-                },
-                {
-                    id: 'C',
-                    text: 'Amplicon_C'
-                },
-                {
-                    id: 'D',
-                    text: 'Amplicon_D'
-                }
-            ],
-            multiplexFields: {
-                template_ngul: {
-                    required: true,
-                    id: 'template_ngul',
-                    name: 'template conc',
-                    type: 'select',
-                    options: [
-                        {id: 'a', text: "a"},
-                        {id: 'b', text: "b"},
-                        {id: 'c', text: "c"}
-                    ]
-                },
-                primer_umolarity: {
-                    required: true,
-                    id: 'primer_umolarity',
-                    name: 'Primer conc',
-                    type: 'numeric',
-                    placeHolder: "Primer",
-                    units: ['uM (final)', "unit1"],
-                    defaultUnit: 'uM (final)'
-                },
-                probe_umolarity: {
-                    required: true,
-                    id: 'probe_umolarity',
-                    name: 'Probe conc',
-                    type: 'numeric',
-                    placeHolder: "Probe",
-                    defaultUnit: 'uM (final)'
-                },
-                dilution_factor: {
-                    required: true,
-                    id: 'dilution_factor',
-                    name: 'Dilution factor',
-                    type: 'numeric',
-                    placeHolder: "Dilution factor",
-                    defaultUnit: 'X'
-                }
-            },
+        {
+          id: 4,
+          text: 'Taq 4'
         },
-    };
-    var attributes = {
-        presets: [
-            {
-                title: "Pol/Vol",
-                fields: ["volume", "pol"]
-            },
-            {
-                title: "Vol",
-                fields: ["volume"]
-            }
-        ],
-        tabs: [
-            {
-                name: "Settings",
-                fields: fields
-            },
-            {
-                name: "amplicons",
-                fields: amplicons_field
-            }
-        ]
-    };
-    window.plateData = {};
-    function makeNewPlate(obj) {
-        var d = $("#my-plate-layout").plateLayOut("getDimensions");
-        var rows = d.rows;
-        var cols = d.cols;
-        var wells = {};
-        for (var r = 0; r < rows; r++) {
-            var volume = 100;
-            var pol = (r < (rows / 2)) ? 234 : 123;
-            var on_ice = Boolean(r % 2);
-            for (var c = 0; c < cols; c++) {
-                var i = r * cols + c;
-                var v = volume;
-                var vunit = "mL";
-                var amplicons = [{
-                    amplicons: "A",
-                    template_ngul: 'a',
-                    primer_umolarity: 2,
-                    probe_umolarity: 3,
-                    dilution_factor: 4
-                },
-                    {
-                        amplicons: "B",
-                        template_ngul: 'b',
-                        primer_umolarity: 22,
-                        probe_umolarity: 33,
-                        dilution_factor: 44
-                    }];
-                if (v < 1) {
-                    v *= 1000;
-                    vunit = "uL";
-                }
-                wells[i.toString()] = {
-                    volume: v,
-                    pol: pol,
-                    amplicons: amplicons,
-                    on_ice: on_ice
-                };
-                if ((c % 2) > 0) {
-                    volume /= 10
-                }
-            }
+        {
+          id: 5,
+          text: 'Taq 5'
         }
-        return {
-            derivative: wells,
-            checkboxes: ["volume", "pol"]
-        };
+      ]
+    },
+    volume: {
+      required: true,
+      id: 'volume',
+      name: 'Volume',
+      type: 'numeric',
+      placeholder: "Volume",
+      units: ["uL", "mL"],
+      defaultUnit: "uL"
+    },
+    conc: {
+      required: true,
+      id: 'conc',
+      name: 'Concentration',
+      type: 'numeric',
+      placeholder: "Conc.",
+      defaultUnit: "ng/ul (final)"
+    },
+    on_ice: {
+      required: true,
+      id: "on_ice",
+      name: "On Ice",
+      type: "boolean",
+      placeHolder: "On Ice"
     }
-    $("#my-plate-layout").plateLayOut({
-        numRows: 8,
-        numCols: 12,
-        attributes: attributes,
-        // scrollToGroup: false, // optional
+  };
+  var amplicons_field = {
+    amplicons: {
+      required: true,
+      id: 'amplicons',
+      name: "Amplicons",
+      type: "multiplex",
+      placeHolder: "Amplicons",
+      options: [
+        {
+          id: 'A',
+          text: 'Amplicon_A'
+        },
+        {
+          id: 'B',
+          text: 'Amplicon_B'
+        },
+        {
+          id: 'C',
+          text: 'Amplicon_C'
+        },
+        {
+          id: 'D',
+          text: 'Amplicon_D'
+        }
+      ],
+      multiplexFields: {
+        template_ngul: {
+          required: true,
+          id: 'template_ngul',
+          name: 'template conc',
+          type: 'select',
+          options: [
+            {id: 'a', text: "a"},
+            {id: 'b', text: "b"},
+            {id: 'c', text: "c"}
+          ]
+        },
+        primer_umolarity: {
+          required: true,
+          id: 'primer_umolarity',
+          name: 'Primer conc',
+          type: 'numeric',
+          placeHolder: "Primer",
+          units: ['uM (final)', "unit1"],
+          defaultUnit: 'uM (final)'
+        },
+        probe_umolarity: {
+          required: true,
+          id: 'probe_umolarity',
+          name: 'Probe conc',
+          type: 'numeric',
+          placeHolder: "Probe",
+          defaultUnit: 'uM (final)'
+        },
+        dilution_factor: {
+          required: true,
+          id: 'dilution_factor',
+          name: 'Dilution factor',
+          type: 'numeric',
+          placeHolder: "Dilution factor",
+          defaultUnit: 'X'
+        }
+      },
+    },
+  };
+  var attributes = {
+    presets: [
+      {
+        title: "Pol/Vol",
+        fields: ["volume", "pol"]
+      },
+      {
+        title: "Vol",
+        fields: ["volume"]
+      }
+    ],
+    tabs: [
+      {
+        name: "Settings",
+        fields: fields
+      },
+      {
+        name: "amplicons",
+        fields: amplicons_field
+      }
+    ]
+  };
+  window.plateData = {};
 
-        updateWells: function (event, data) {
-            //data has changed
-            window.plateData = data;
-            console.log(Object.keys(data.derivative).length + " wells updated");
+  function makeNewPlate(obj) {
+    var d = $("#my-plate-layout").plateLayOut("getDimensions");
+    var rows = d.rows;
+    var cols = d.cols;
+    var wells = {};
+    for (var r = 0; r < rows; r++) {
+      var volume = 100;
+      var pol = (r < (rows / 2)) ? 234 : 123;
+      var on_ice = Boolean(r % 2);
+      for (var c = 0; c < cols; c++) {
+        var i = r * cols + c;
+        var v = volume;
+        var vunit = "mL";
+        var amplicons = [{
+          amplicons: "A",
+          template_ngul: 'a',
+          primer_umolarity: 2,
+          probe_umolarity: 3,
+          dilution_factor: 4
         },
-        created: function (event, data) {
-            console.log("Created");
+          {
+            amplicons: "B",
+            template_ngul: 'b',
+            primer_umolarity: 22,
+            probe_umolarity: 33,
+            dilution_factor: 44
+          }];
+        if (v < 1) {
+          v *= 1000;
+          vunit = "uL";
+        }
+        wells[i.toString()] = {
+          volume: v,
+          pol: pol,
+          amplicons: amplicons,
+          on_ice: on_ice
+        };
+        if ((c % 2) > 0) {
+          volume /= 10
         }
-    });
-    window.plateData = makeNewPlate();
-    $("#my-plate-layout").plateLayOut("getPlates", window.plateData);
+      }
+    }
+    return {
+      derivative: wells,
+      checkboxes: ["volume", "pol"]
+    };
+  }
+
+  $("#my-plate-layout").plateLayOut({
+    numRows: 8,
+    numCols: 12,
+    attributes: attributes,
+    // scrollToGroup: false, // optional
+
+    updateWells: function(event, data) {
+      //data has changed
+      window.plateData = data;
+      console.log(Object.keys(data.derivative).length + " wells updated");
+    },
+    created: function(event, data) {
+      console.log("Created");
+    }
+  });
+  window.plateData = makeNewPlate();
+  $("#my-plate-layout").plateLayOut("getPlates", window.plateData);
 };
\ No newline at end of file
diff --git a/src/js/fabric-events.js b/src/js/fabric-events.js
index 589b2fa..3097085 100755
--- a/src/js/fabric-events.js
+++ b/src/js/fabric-events.js
@@ -105,7 +105,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           that.decideSelectedFields();
           that.mainFabricCanvas.renderAll();
           that._trigger("selectedWells", null, {selectedAddress: that.getSelectedAddress()});
-          if(that.options.scrollToGroup === undefined || that.options.scrollToGroup) {
+          if (that.options.scrollToGroup === undefined || that.options.scrollToGroup) {
             that.selectObjectInBottomTab();
           }
         });
@@ -128,7 +128,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             r: well.row,
             c: well.col
           });
-          if  (this.addressAllowToEdit.indexOf(address) < 0) {
+          if (this.addressAllowToEdit.indexOf(address) < 0) {
             flag = false;
             this.setFieldsDisabled(true);
           } else {
@@ -178,18 +178,18 @@ var plateLayOutWidget = plateLayOutWidget || {};
         })
       },
 
-      _getSelectedWells: function () {
-        var that = this; 
-        return this.allSelectedObjects.map(function (tile) {
+      _getSelectedWells: function() {
+        var that = this;
+        return this.allSelectedObjects.map(function(tile) {
           var well = that.engine.derivative[tile.index];
           if (!well) {
-            well = that.defaultWell; 
+            well = that.defaultWell;
           }
-          return well; 
-        }); 
+          return well;
+        });
       },
 
-      _getCommonFields: function (wells) {
+      _getCommonFields: function(wells) {
         if (wells.length) {
           var referenceWell = wells[0];
           var referenceFields = $.extend(true, {}, referenceWell);
@@ -197,11 +197,11 @@ var plateLayOutWidget = plateLayOutWidget || {};
             var fields = wells[i];
             for (var field in referenceFields) {
               if (Array.isArray(referenceFields[field])) {
-                var refArr = referenceFields[field]; 
-                var agrArr = []; 
+                var refArr = referenceFields[field];
+                var agrArr = [];
                 for (var j = 0; j < refArr.length; j++) {
                   var v = refArr[j];
-                  if (v && typeof(v) === "object") {
+                  if (v && typeof (v) === "object") {
                     if (this.containsObject(v, fields[field])) {
                       agrArr.push(v);
                     }
@@ -211,10 +211,10 @@ var plateLayOutWidget = plateLayOutWidget || {};
                     }
                   }
                 }
-                referenceFields[field] = agrArr; 
+                referenceFields[field] = agrArr;
               } else {
-                if (fields[field] && typeof(fields[field]) ==="object" && referenceFields[field] && typeof(referenceFields[field]) ==="object"){
-                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){
+                if (fields[field] && typeof (fields[field]) === "object" && referenceFields[field] && typeof (referenceFields[field]) === "object") {
+                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)) {
                     delete referenceFields[field];
                   }
                 } else if (referenceFields[field] != fields[field]) {
@@ -235,11 +235,11 @@ var plateLayOutWidget = plateLayOutWidget || {};
           list.forEach(function(val) {
             //evaluate val and obj
             var evaluate = [];
-            Object.keys(val).forEach(function(listKey){
-              if (Object.keys(obj).indexOf(listKey) >= 0){
+            Object.keys(val).forEach(function(listKey) {
+              if (Object.keys(obj).indexOf(listKey) >= 0) {
                 var curVal = val[listKey];
-                if (typeof(curVal) === 'object' && curVal) {
-                  if (obj[listKey]){
+                if (typeof (curVal) === 'object' && curVal) {
+                  if (obj[listKey]) {
                     evaluate.push((curVal.unit === obj[listKey].unit) && (curVal.value === obj[listKey].value));
                   } else {
                     // when obj[listKey] is null but curVal is not
@@ -258,7 +258,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         }
       },
 
-      _getCommonWell: function (wells) {
+      _getCommonWell: function(wells) {
         if (wells.length) {
           var referenceWell = wells[0];
           var referenceFields = $.extend(true, {}, referenceWell);
@@ -267,12 +267,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
             var fields = well;
             for (var field in referenceFields) {
               if (Array.isArray(referenceFields[field])) {
-                var refArr = referenceFields[field]; 
-                var agrArr = []; 
+                var refArr = referenceFields[field];
+                var agrArr = [];
                 for (var j = 0; j < refArr.length; j++) {
                   var v = refArr[j];
                   // for multiplex field
-                  if (typeof(refArr[j]) ==="object"){
+                  if (typeof (refArr[j]) === "object") {
                     if (this.containsObject(v, fields[field])) {
                       agrArr.push(v);
                     }
@@ -282,10 +282,10 @@ var plateLayOutWidget = plateLayOutWidget || {};
                     }
                   }
                 }
-                referenceFields[field] = agrArr; 
+                referenceFields[field] = agrArr;
               } else {
-                if (fields[field] && typeof(fields[field]) ==="object" && referenceFields[field] && typeof(referenceFields[field]) ==="object"){
-                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)){
+                if (fields[field] && typeof (fields[field]) === "object" && referenceFields[field] && typeof (referenceFields[field]) === "object") {
+                  if ((fields[field].value !== referenceFields[field].value) || (fields[field].unit !== referenceFields[field].unit)) {
                     referenceFields[field] = null;
                   }
                 } else if (referenceFields[field] != fields[field]) {
@@ -297,30 +297,30 @@ var plateLayOutWidget = plateLayOutWidget || {};
           }
           return referenceFields;
         } else {
-          return this.defaultWell; 
+          return this.defaultWell;
         }
-      }, 
+      },
 
-      _getAllMultipleVal: function (wells) {
+      _getAllMultipleVal: function(wells) {
         var multipleFieldList = this.multipleFieldList;
 
         multipleFieldList.forEach(function(multiplexField) {
-          if(wells.length) {
+          if (wells.length) {
             var curMultipleVal = {};
-            wells.forEach(function (wellData) {
+            wells.forEach(function(wellData) {
               var id = multiplexField.id;
-              if (wellData[id]){
+              if (wellData[id]) {
                 if (wellData[id].length > 0) {
-                  wellData[id].forEach(function (multipleVal) {
-                    if (typeof(multipleVal) === 'object') {
+                  wellData[id].forEach(function(multipleVal) {
+                    if (typeof (multipleVal) === 'object') {
                       if (multipleVal[id] in curMultipleVal) {
-                        curMultipleVal[multipleVal[id]] ++;
+                        curMultipleVal[multipleVal[id]]++;
                       } else {
                         curMultipleVal[multipleVal[id]] = 1;
                       }
                     } else {
                       if (multipleVal in curMultipleVal) {
-                        curMultipleVal[multipleVal] ++;
+                        curMultipleVal[multipleVal]++;
 
                       } else {
                         curMultipleVal[multipleVal] = 1;
@@ -341,24 +341,24 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var wells = this._getSelectedWells();
         this._getAllMultipleVal(wells);
         this.applyFieldWarning(wells);
-        var well = this._getCommonWell(wells); 
+        var well = this._getCommonWell(wells);
         this._addDataToTabFields(well);
       },
 
       // get well value differences for each well in wellsHash
       getDifferentWellsVals: function(wellsHash) {
         var wells = [];
-        for (var wellId in wellsHash){
+        for (var wellId in wellsHash) {
           wells.push(wellsHash[wellId]);
         }
         var differentWellsVals = {};
-        if (wells.length > 1){
+        if (wells.length > 1) {
           var commonWell = this._getCommonWell(wells);
           var allFieldVal = {};
           for (var fieldIdx in wellsHash[0]) {
             allFieldVal[fieldIdx] = [];
           }
-          for (var wellIdx in wells){
+          for (var wellIdx in wells) {
             var diffWellVal = {};
             var curWellData = wells[wellIdx];
             for (var fieldId in curWellData) {
@@ -368,10 +368,10 @@ var plateLayOutWidget = plateLayOutWidget || {};
               if (Array.isArray(curVal)) {
                 // get uncommonVal
                 newVal = [];
-                for (var idx = 0; idx < curVal.length; idx ++){
+                for (var idx = 0; idx < curVal.length; idx++) {
                   var curMultiVal = curVal[idx];
                   // multiplex field
-                  if (curMultiVal && typeof(curMultiVal === "object")){
+                  if (curMultiVal && typeof (curMultiVal === "object")) {
                     if (!this.containsObject(curMultiVal, commonVal)) {
                       newVal.push(curMultiVal);
                       if (!this.containsObject(curMultiVal, allFieldVal[fieldId])) {
@@ -387,9 +387,9 @@ var plateLayOutWidget = plateLayOutWidget || {};
                     }
                   }
                 }
-              } else if (curVal && typeof(curVal) === "object"){
-                if (commonVal && typeof(commonVal) ==="object"){
-                  if (!((curVal.value === commonVal.value) || (curVal.unit === commonVal.unit))){
+              } else if (curVal && typeof (curVal) === "object") {
+                if (commonVal && typeof (commonVal) === "object") {
+                  if (!((curVal.value === commonVal.value) || (curVal.unit === commonVal.unit))) {
                     newVal = curVal;
                     if (!this.containsObject(curVal, allFieldVal[fieldId])) {
                       allFieldVal[fieldId].push(curVal);
@@ -417,7 +417,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           // clean up step for fields that are empty
           for (var fieldId in allFieldVal) {
             if (allFieldVal[fieldId].length === 0) {
-              for (var wellIdx in differentWellsVals){
+              for (var wellIdx in differentWellsVals) {
                 delete differentWellsVals[wellIdx][fieldId];
               }
             }
@@ -428,11 +428,11 @@ var plateLayOutWidget = plateLayOutWidget || {};
           var well = {};
           for (var fieldId in wellsHash[0]) {
             var curVal = wellsHash[0][fieldId];
-            if (Array.isArray(curVal)){
+            if (Array.isArray(curVal)) {
               if (curVal.length > 0) {
                 well[fieldId] = curVal
               }
-            } else if (curVal){
+            } else if (curVal) {
               well[fieldId] = curVal;
             }
           }
@@ -443,10 +443,10 @@ var plateLayOutWidget = plateLayOutWidget || {};
       },
 
       // get all wells that has data
-      getWellSetAddressWithData: function(){
+      getWellSetAddressWithData: function() {
         var address = [];
         var derivative = this.engine.derivative;
-        for (var id in derivative){
+        for (var id in derivative) {
           address.push(this.indexToAddress(id));
         }
         return address;
diff --git a/src/js/image_assets.js b/src/js/image_assets.js
index 1310a8a..1f8ca0e 100644
--- a/src/js/image_assets.js
+++ b/src/js/image_assets.js
@@ -1,11 +1,11 @@
 var plateLayOutWidget = plateLayOutWidget || {};
 
-plateLayOutWidget.assets = function () {
-    return {
-        _assets: {
-            doImg: '&#10003;',
-            dontImg: '',
-            warningImg: '&#9888;'
-        }
-    };
+plateLayOutWidget.assets = function() {
+  return {
+    _assets: {
+      doImg: '&#10003;',
+      dontImg: '',
+      warningImg: '&#9888;'
+    }
+  };
 };
diff --git a/src/js/interface.js b/src/js/interface.js
index ed5aa9e..ef68e70 100755
--- a/src/js/interface.js
+++ b/src/js/interface.js
@@ -57,22 +57,22 @@ var plateLayOutWidget = plateLayOutWidget || {};
         return $(element);
       },
 
-      _setShortcuts: function () {
-        var that = this; 
-        window.addEventListener("cut", function (e) {
+      _setShortcuts: function() {
+        var that = this;
+        window.addEventListener("cut", function(e) {
           if (document.activeElement == document.body) {
             that.copyCriteria();
             that.clearCriteria();
             e.preventDefault();
           }
         });
-        window.addEventListener("copy", function (e) {
+        window.addEventListener("copy", function(e) {
           if (document.activeElement == document.body) {
             that.copyCriteria();
             e.preventDefault();
           }
         });
-        window.addEventListener("paste", function (e) {
+        window.addEventListener("paste", function(e) {
           if (document.activeElement == document.body) {
             that.pasteCriteria();
             e.preventDefault();
diff --git a/src/js/load-plate.js b/src/js/load-plate.js
index 7bd1b3a..9111b6b 100755
--- a/src/js/load-plate.js
+++ b/src/js/load-plate.js
@@ -7,29 +7,29 @@ var plateLayOutWidget = plateLayOutWidget || {};
     // Remember THIS points to plateLayOutWidget and 'this' points to engine
     return {
 
-      getPlates: function (data) {
+      getPlates: function(data) {
         //sanitize input
-        var derivative = {}; 
+        var derivative = {};
         for (var index in data.derivative) {
-          var well = data.derivative[index]; 
-          derivative[index] = this.sanitizeWell(well); 
+          var well = data.derivative[index];
+          derivative[index] = this.sanitizeWell(well);
         }
 
-        var checkboxes = data.checkboxes || []; 
-        var selection = this.sanitizeAreas(data.selectedAreas, data.focalWell); 
+        var checkboxes = data.checkboxes || [];
+        var selection = this.sanitizeAreas(data.selectedAreas, data.focalWell);
 
         var sanitized = {
           "derivative": derivative,
           "checkboxes": checkboxes,
           "selectedAreas": selection.selectedAreas,
           "focalWell": selection.focalWell
-        }; 
+        };
 
         this.setData(sanitized);
-      }, 
+      },
 
-      sanitizeAreas: function (selectedAreas, focalWell) {
-        var that = this; 
+      sanitizeAreas: function(selectedAreas, focalWell) {
+        var that = this;
         var rows = this.dimensions.rows;
         var cols = this.dimensions.cols;
 
@@ -37,14 +37,14 @@ var plateLayOutWidget = plateLayOutWidget || {};
           selectedAreas = [];
         }
         if (selectedAreas.length) {
-          selectedAreas = selectedAreas.map(function (area) {
+          selectedAreas = selectedAreas.map(function(area) {
             return {
-              minCol: that._coordIndex(Math.min(area.minCol, area.maxCol), cols), 
-              minRow: that._coordIndex(Math.min(area.minRow, area.maxRow), rows), 
-              maxCol: that._coordIndex(Math.max(area.minCol, area.maxCol), cols), 
+              minCol: that._coordIndex(Math.min(area.minCol, area.maxCol), cols),
+              minRow: that._coordIndex(Math.min(area.minRow, area.maxRow), rows),
+              maxCol: that._coordIndex(Math.max(area.minCol, area.maxCol), cols),
               maxRow: that._coordIndex(Math.max(area.minRow, area.maxRow), rows)
-            }; 
-          }); 
+            };
+          });
           var area = selectedAreas[selectedAreas.length - 1];
           if (focalWell && !this._wellInArea(focalWell, area)) {
             focalWell = null;
@@ -65,19 +65,19 @@ var plateLayOutWidget = plateLayOutWidget || {};
           selectedAreas = [this._wellToArea(focalWell)];
         }
         return {
-          selectedAreas: selectedAreas, 
+          selectedAreas: selectedAreas,
           focalWell: focalWell
         };
-      }, 
+      },
 
-      sanitizeWell: function (well) {
+      sanitizeWell: function(well) {
         var newWell = {};
         for (var i = 0; i < this.fieldList.length; i++) {
           var field = this.fieldList[i];
           newWell[field.id] = field.parseValue(well[field.id]);
         }
-        return newWell; 
-      }, 
+        return newWell;
+      },
 
       setData: function(data) {
         this.engine.derivative = $.extend(true, {}, data.derivative);
diff --git a/src/js/overlay.js b/src/js/overlay.js
index f448e5d..ac622ea 100755
--- a/src/js/overlay.js
+++ b/src/js/overlay.js
@@ -69,7 +69,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
               if (this.emptyWellWithDefaultVal && this.disableAddDeleteWell) {
                 var well = JSON.parse(JSON.stringify(this.defaultWell));
                 var defaultValue = this.emptyWellWithDefaultVal;
-                for (var key in defaultValue){
+                for (var key in defaultValue) {
                   if (key in well) {
                     well[key] = defaultValue[key];
                     this._applyFieldData(key, defaultValue[key]);
@@ -84,7 +84,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
               hasWellUpdate = true;
             }
           }
-          if (hasWellUpdate){
+          if (hasWellUpdate) {
             this.derivativeChange();
           }
 
@@ -97,8 +97,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
       copyCriteria: function() {
         if (this.allSelectedObjects) {
-          var wells = this._getSelectedWells(); 
-          this.commonWell = this._getCommonFields(wells); 
+          var wells = this._getSelectedWells();
+          this.commonWell = this._getCommonFields(wells);
         } else {
           alert("Please select any well.");
         }
diff --git a/src/js/plate-layout.js b/src/js/plate-layout.js
index 398d286..2c2497a 100755
--- a/src/js/plate-layout.js
+++ b/src/js/plate-layout.js
@@ -1,331 +1,331 @@
 $.widget("DNA.plateLayOut", {
 
-    plateLayOutWidget: {},
-
-    options: {
-        value: 0
-    },
-
-    allTiles: [], // All tiles containes all thise circles in the canvas
-
-    addressToLoc: function (layoutAddress) {
-        var m = /^([A-Z]+)(\d+)$/.exec(layoutAddress.trim().toUpperCase())
-        if (m) {
-            var row_v = m[1];
-            var col = parseInt(m[2]) - 1;
-            var row;
-            for (var i = 0; i < row_v.length; i++) {
-                var c = row_v.charCodeAt(i) - 65;
-                if (i) {
-                    row += 1;
-                    row *= 26;
-                    row += c;
-                } else {
-                    row = c;
-                }
-            }
-            return {
-                r: row,
-                c: col
-            };
+  plateLayOutWidget: {},
+
+  options: {
+    value: 0
+  },
+
+  allTiles: [], // All tiles containes all thise circles in the canvas
+
+  addressToLoc: function(layoutAddress) {
+    var m = /^([A-Z]+)(\d+)$/.exec(layoutAddress.trim().toUpperCase())
+    if (m) {
+      var row_v = m[1];
+      var col = parseInt(m[2]) - 1;
+      var row;
+      for (var i = 0; i < row_v.length; i++) {
+        var c = row_v.charCodeAt(i) - 65;
+        if (i) {
+          row += 1;
+          row *= 26;
+          row += c;
         } else {
-            throw layoutAddress + " not a proper layout address";
+          row = c;
         }
-    },
+      }
+      return {
+        r: row,
+        c: col
+      };
+    } else {
+      throw layoutAddress + " not a proper layout address";
+    }
+  },
 
-    locToIndex: function (loc, dimensions) {
-        if (!dimensions) {
-            dimensions = this.dimensions;
-        }
-        if (loc.r < 0) {
-            t
-        }
-        if (!(loc.r >= 0 && loc.r < dimensions.rows)) {
-            throw "Row index " + (loc.r + 1) + " invalid";
-        }
-        if (!(loc.c >= 0 && loc.c < dimensions.cols)) {
-            throw "Column index " + (loc.c + 1) + " invalid";
-        }
-        return loc.r * dimensions.cols + loc.c;
-    },
-
-    addressToIndex: function (layoutAddress, dimensions) {
-        var loc = this.addressToLoc(layoutAddress);
-        return this.locToIndex(loc, dimensions);
-    },
-
-    _rowKey: function (i) {
-        var c1 = i % 26;
-        var c2 = (i - c1) / 26;
-        var code = String.fromCharCode(65 + c1);
-        if (c2 > 0) {
-            code = String.fromCharCode(64 + c2) + code;
-        }
-        return code;
-    },
+  locToIndex: function(loc, dimensions) {
+    if (!dimensions) {
+      dimensions = this.dimensions;
+    }
+    if (loc.r < 0) {
+      t
+    }
+    if (!(loc.r >= 0 && loc.r < dimensions.rows)) {
+      throw "Row index " + (loc.r + 1) + " invalid";
+    }
+    if (!(loc.c >= 0 && loc.c < dimensions.cols)) {
+      throw "Column index " + (loc.c + 1) + " invalid";
+    }
+    return loc.r * dimensions.cols + loc.c;
+  },
+
+  addressToIndex: function(layoutAddress, dimensions) {
+    var loc = this.addressToLoc(layoutAddress);
+    return this.locToIndex(loc, dimensions);
+  },
+
+  _rowKey: function(i) {
+    var c1 = i % 26;
+    var c2 = (i - c1) / 26;
+    var code = String.fromCharCode(65 + c1);
+    if (c2 > 0) {
+      code = String.fromCharCode(64 + c2) + code;
+    }
+    return code;
+  },
 
-    indexToLoc: function (index, dimensions) {
-        if (!dimensions) {
-            dimensions = this.dimensions;
-        }
+  indexToLoc: function(index, dimensions) {
+    if (!dimensions) {
+      dimensions = this.dimensions;
+    }
 
-        if (index >= dimensions.rows * dimensions.cols) {
-            throw "Index too high: " + index.toString(10);
-        }
-        var loc = {};
-        loc.c = index % dimensions.cols;
-        loc.r = (index - loc.c) / dimensions.cols;
-
-        return loc;
-    },
-
-    locToAddress: function (loc) {
-        return this._rowKey(loc.r) + (loc.c + 1).toString(10);
-    },
-
-    indexToAddress: function (index, dimensions) {
-        var loc = this.indexToLoc(index, dimensions);
-        return this.locToAddress(loc);
-    },
-
-    getDimensions: function () {
-        return $.extend(true, {}, this.dimensions);
-    },
-
-    _create: function () {
-        var rows = parseInt(this.options.numRows || 8);
-        var cols = parseInt(this.options.numCols || 12);
-        this.dimensions = {
-            rows: rows,
-            cols: cols
-        };
-        this.rowIndex = [];
-        for (var i = 0; i < rows; i++) {
-            this.rowIndex.push(this._rowKey(i));
-        }
+    if (index >= dimensions.rows * dimensions.cols) {
+      throw "Index too high: " + index.toString(10);
+    }
+    var loc = {};
+    loc.c = index % dimensions.cols;
+    loc.r = (index - loc.c) / dimensions.cols;
+
+    return loc;
+  },
+
+  locToAddress: function(loc) {
+    return this._rowKey(loc.r) + (loc.c + 1).toString(10);
+  },
+
+  indexToAddress: function(index, dimensions) {
+    var loc = this.indexToLoc(index, dimensions);
+    return this.locToAddress(loc);
+  },
+
+  getDimensions: function() {
+    return $.extend(true, {}, this.dimensions);
+  },
+
+  _create: function() {
+    var rows = parseInt(this.options.numRows || 8);
+    var cols = parseInt(this.options.numCols || 12);
+    this.dimensions = {
+      rows: rows,
+      cols: cols
+    };
+    this.rowIndex = [];
+    for (var i = 0; i < rows; i++) {
+      this.rowIndex.push(this._rowKey(i));
+    }
 
-        this.target = (this.element[0].id) ? "#" + this.element[0].id : "." + this.element[0].className;
+    this.target = (this.element[0].id) ? "#" + this.element[0].id : "." + this.element[0].className;
 
-        // Import classes from other files.. Here we import it using extend and add it to this
-        // object. internally we add to widget.DNA.getPlates.prototype.
-        // Helpers are methods which return other methods and objects.
-        // add Objects to plateLayOutWidget and it will be added to this object.
-        // set read only well
-        if (this.options.readOnly) {
-            this.isReadOnly(true);
-        }
+    // Import classes from other files.. Here we import it using extend and add it to this
+    // object. internally we add to widget.DNA.getPlates.prototype.
+    // Helpers are methods which return other methods and objects.
+    // add Objects to plateLayOutWidget and it will be added to this object.
+    // set read only well
+    if (this.options.readOnly) {
+      this.isReadOnly(true);
+    }
 
-        for (var component in plateLayOutWidget) {
-            // Incase some properties has to initialize with data from options hash,
-            // we provide it sending this object.
-            $.extend(this, new plateLayOutWidget[component](this));
-        }
+    for (var component in plateLayOutWidget) {
+      // Incase some properties has to initialize with data from options hash,
+      // we provide it sending this object.
+      $.extend(this, new plateLayOutWidget[component](this));
+    }
 
-        this.imgSrc = this.options.imgSrc || "assets";
-
-        this._createInterface();
-
-        this._trigger("created", null, this);
-
-        return this;
-    },
-
-    _init: function () {
-        // This is invoked when the user use the plugin after _create is called.
-        // The point is _create is invoked for the very first time and for all other
-        // times _init is used.
-    },
-
-    addData: function () {
-        alert("wow this is good");
-    },
-
-    // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
-    getTextDerivative: function (wellsData) {
-        var textDerivative = {};
-        var fieldMap = this.fieldMap;
-        for (var idx in wellsData) {
-            var textValWell = {};
-            var textFieldIdWell = {};
-            var curWellData = wellsData[idx];
-            for (var fieldId in curWellData) {
-                if (fieldId in this.fieldMap) {
-                    var field = this.fieldMap[fieldId];
-                    var textVal = field.parseText(curWellData[fieldId]);
-                    textFieldIdWell[field.name] = textVal;
-                    textValWell[fieldId] = textVal;
-                } else {
-                    // do not convert if not a field (ex: layout_address)
-                    textFieldIdWell[fieldId] = curWellData[fieldId];
-                    textValWell[fieldId] = curWellData[fieldId];
-                }
-            }
-            textDerivative[idx] = {
-                textVal: textValWell,
-                textFieldVal: textFieldIdWell
-            };
+    this.imgSrc = this.options.imgSrc || "assets";
+
+    this._createInterface();
+
+    this._trigger("created", null, this);
+
+    return this;
+  },
+
+  _init: function() {
+    // This is invoked when the user use the plugin after _create is called.
+    // The point is _create is invoked for the very first time and for all other
+    // times _init is used.
+  },
+
+  addData: function() {
+    alert("wow this is good");
+  },
+
+  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
+  getTextDerivative: function(wellsData) {
+    var textDerivative = {};
+    var fieldMap = this.fieldMap;
+    for (var idx in wellsData) {
+      var textValWell = {};
+      var textFieldIdWell = {};
+      var curWellData = wellsData[idx];
+      for (var fieldId in curWellData) {
+        if (fieldId in this.fieldMap) {
+          var field = this.fieldMap[fieldId];
+          var textVal = field.parseText(curWellData[fieldId]);
+          textFieldIdWell[field.name] = textVal;
+          textValWell[fieldId] = textVal;
+        } else {
+          // do not convert if not a field (ex: layout_address)
+          textFieldIdWell[fieldId] = curWellData[fieldId];
+          textValWell[fieldId] = curWellData[fieldId];
         }
+      }
+      textDerivative[idx] = {
+        textVal: textValWell,
+        textFieldVal: textFieldIdWell
+      };
+    }
 
-        return textDerivative;
-    },
-
-    // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
-    getWellsDifferences: function (wellsData) {
-        return this.getDifferentWellsVals(wellsData);
-    },
-
-    setFieldsDisabled: function (flag) {
-        this.fieldList.forEach(function (field) {
-            field.disabled(flag);
-        });
-    },
+    return textDerivative;
+  },
+
+  // wellsData follows syntax: {0:{field1: val1, field2: val2}, 1:{field1: val1, field2: val2}}
+  getWellsDifferences: function(wellsData) {
+    return this.getDifferentWellsVals(wellsData);
+  },
+
+  setFieldsDisabled: function(flag) {
+    this.fieldList.forEach(function(field) {
+      field.disabled(flag);
+    });
+  },
+
+  isReadOnly: function(flag) {
+    if (flag) {
+      this.readOnly = true;
+    } else {
+      this.readOnly = false;
+    }
+    this.readOnlyHandler();
+  },
+
+  readOnlyHandler: function() {
+    if (this.readOnly) {
+      this.overLayButtonContainer.css("display", "none");
+      $('.multiple-field-manage-delete-button').css("display", "none");
+      this.setFieldsDisabled(true);
+    } else {
+      this.overLayButtonContainer.css("display", "flex");
+      $('.multiple-field-manage-delete-button').css("display", "none");
+      if (!this.disableAddDeleteWell) {
+        this.setFieldsDisabled(false);
+      }
+    }
+  },
+
+  disableAddDeleteWell: null,
+  // column_with_default_val will be used to determine empty wells, format: {field_name: default_val}
+  isDisableAddDeleteWell: function(flag, column_with_default_val) {
+    if (flag) {
+      this.disableAddDeleteWell = true;
+      this.addressAllowToEdit = this.getWellSetAddressWithData();
+      // configure undo redo action
+      this.actionPointer = 0;
+      this.undoRedoArray = [];
+      this.undoRedoArray.push(this.createObject());
+      if (column_with_default_val) {
+        this.emptyWellWithDefaultVal = column_with_default_val;
+      }
+    } else {
+      this.disableAddDeleteWell = false;
+      this.setFieldsDisabled(false);
+      this.emptyWellWithDefaultVal = null;
+    }
+    this._fabricEvents();
+  },
 
-    isReadOnly: function (flag) {
-        if (flag) {
-            this.readOnly = true;
-        } else {
-            this.readOnly = false;
+  getSelectedObject: function() {
+    var selectedAddress = [];
+    for (var i = 0; i < this.allSelectedObjects.length; i++) {
+      selectedAddress.push(this.allSelectedObjects[i].address);
+    }
+    var selectedObjects = {};
+    var derivative = this.engine.derivative;
+    for (var index in derivative) {
+      var address = this.indexToAddress(index);
+      if (selectedAddress.indexOf(address) >= 0) {
+        var well = JSON.parse(JSON.stringify(derivative[index]));
+        well.colorIndex = this.engine.colorMap.get(Number(index));
+        selectedObjects[address] = well;
+      }
+    }
+    return selectedObjects;
+  },
+
+  selectObjectInBottomTab: function() {
+    var selectedObjects = this.getSelectedObject();
+    var selectedObjectAddress;
+    for (var prop in selectedObjects) {
+      if (!selectedObjectAddress) {
+        selectedObjectAddress = prop;
+      } else {
+        return;  // scroll to matching group only if a single well has been selected
+      }
+    }
+    if (selectedObjects[selectedObjectAddress]) {
+      var colorIndex = selectedObjects[selectedObjectAddress].colorIndex;
+      var trs = document.querySelectorAll('table.plate-setup-bottom-table tr');
+      for (var i = 1; i < trs.length; i++) { // start at 1 to skip the table headers
+        var tds = trs[i].children;
+        var isSelected = tds[0].querySelector('button').innerHTML === colorIndex.toString();
+        for (var j = 1; j < tds.length; j++) {
+          if (isSelected) {
+            tds[j].style.background = '#22cb94';
+          } else {
+            tds[j].style.background = '#ffffff';
+          }
         }
-        this.readOnlyHandler();
-    },
-
-    readOnlyHandler: function () {
-        if (this.readOnly) {
-            this.overLayButtonContainer.css("display", "none");
-            $('.multiple-field-manage-delete-button').css("display", "none");
-            this.setFieldsDisabled(true);
-        } else {
-            this.overLayButtonContainer.css("display", "flex");
-            $('.multiple-field-manage-delete-button').css("display", "none");
-            if (!this.disableAddDeleteWell) {
-                this.setFieldsDisabled(false);
-            }
+        if (isSelected) {
+          scrollTo(document.querySelector('.plate-setup-bottom-table-container'), tds[0].offsetTop, 300);
         }
-    },
-
-    disableAddDeleteWell: null,
-    // column_with_default_val will be used to determine empty wells, format: {field_name: default_val}
-    isDisableAddDeleteWell: function (flag, column_with_default_val) {
-        if (flag) {
-            this.disableAddDeleteWell = true;
-            this.addressAllowToEdit = this.getWellSetAddressWithData();
-            // configure undo redo action
-            this.actionPointer = 0;
-            this.undoRedoArray = [];
-            this.undoRedoArray.push(this.createObject());
-            if (column_with_default_val) {
-                this.emptyWellWithDefaultVal = column_with_default_val;
-            }
+      }
+    }
+  },
+
+  getSelectedIndex: function() {
+    return this.allSelectedObjects.map(function(selectedObj) {
+      return that.addressToIndex(selectedObj.address)
+    });
+  },
+
+  getSelectedAddress: function() {
+    return this.allSelectedObjects.map(function(selectedObj) {
+      return selectedObj.address;
+    });
+  },
+
+  setSelectedWell: function(addressList) {
+    var areas = [];
+    var minRow = 999;
+    var locMap = {};
+    for (var id = 0; id < addressList.length; id++) {
+      var wellIdx = this.addressToIndex(addressList[id]);
+      var loc = this.indexToLoc(wellIdx);
+      areas.push({
+        minCol: loc.c,
+        minRow: loc.r,
+        maxCol: loc.c,
+        maxRow: loc.r
+      });
+      if (loc.r <= minRow) {
+        minRow = loc.r;
+        if (loc.r in locMap) {
+          locMap[loc.r].push(loc.c);
         } else {
-            this.disableAddDeleteWell = false;
-            this.setFieldsDisabled(false);
-            this.emptyWellWithDefaultVal = null;
-        }
-        this._fabricEvents();
-    },
-
-    getSelectedObject: function () {
-        var selectedAddress = [];
-        for (var i = 0; i < this.allSelectedObjects.length; i++) {
-            selectedAddress.push(this.allSelectedObjects[i].address);
+          locMap[loc.r] = [loc.c];
         }
-        var selectedObjects = {};
-        var derivative = this.engine.derivative;
-        for (var index in derivative) {
-            var address = this.indexToAddress(index);
-            if (selectedAddress.indexOf(address) >= 0) {
-                var well = JSON.parse(JSON.stringify(derivative[index]));
-                well.colorIndex = this.engine.colorMap.get(Number(index));
-                selectedObjects[address] = well;
-            }
-        }
-        return selectedObjects;
-    },
-
-    selectObjectInBottomTab: function () {
-        var selectedObjects = this.getSelectedObject();
-        var selectedObjectAddress;
-        for (var prop in selectedObjects) {
-            if (!selectedObjectAddress) {
-                selectedObjectAddress = prop;
-            } else {
-                return;  // scroll to matching group only if a single well has been selected
-            }
-        }
-        if (selectedObjects[selectedObjectAddress]) {
-            var colorIndex = selectedObjects[selectedObjectAddress].colorIndex;
-            var trs = document.querySelectorAll('table.plate-setup-bottom-table tr');
-            for (var i = 1; i < trs.length; i++) { // start at 1 to skip the table headers
-                var tds = trs[i].children;
-                var isSelected = tds[0].querySelector('button').innerHTML === colorIndex.toString();
-                for (var j = 1; j < tds.length; j++) {
-                    if (isSelected) {
-                        tds[j].style.background = '#22cb94';
-                    } else {
-                        tds[j].style.background = '#ffffff';
-                    }
-                }
-                if (isSelected) {
-                    scrollTo(document.querySelector('.plate-setup-bottom-table-container'), tds[0].offsetTop, 300);
-                }
-            }
-        }
-    },
-
-    getSelectedIndex: function () {
-        return this.allSelectedObjects.map(function (selectedObj) {
-            return that.addressToIndex(selectedObj.address)
-        });
-    },
-
-    getSelectedAddress: function () {
-        return this.allSelectedObjects.map(function (selectedObj) {
-            return selectedObj.address;
-        });
-    },
-
-    setSelectedWell: function (addressList) {
-        var areas = [];
-        var minRow = 999;
-        var locMap = {};
-        for (var id = 0; id < addressList.length; id++) {
-            var wellIdx = this.addressToIndex(addressList[id]);
-            var loc = this.indexToLoc(wellIdx);
-            areas.push({
-                minCol: loc.c,
-                minRow: loc.r,
-                maxCol: loc.c,
-                maxRow: loc.r
-            });
-            if (loc.r <= minRow) {
-                minRow = loc.r;
-                if (loc.r in locMap) {
-                    locMap[loc.r].push(loc.c);
-                } else {
-                    locMap[loc.r] = [loc.c];
-                }
-            }
-        }
-        var focalWell = {
-            row: minRow,
-            col: Math.min.apply(null, locMap[minRow])
-        };
-
-        this.setSelection(areas, focalWell);
-        this.decideSelectedFields();
-        this.mainFabricCanvas.renderAll();
+      }
     }
+    var focalWell = {
+      row: minRow,
+      col: Math.min.apply(null, locMap[minRow])
+    };
+
+    this.setSelection(areas, focalWell);
+    this.decideSelectedFields();
+    this.mainFabricCanvas.renderAll();
+  }
 
 });
 
 // https://stackoverflow.com/questions/17733076/smooth-scroll-anchor-links-without-jquery
 function scrollTo(element, to, duration) {
-    if (duration <= 0) return;
-    var difference = to - element.scrollTop;
-    var perTick = difference / duration * 10;
-    setTimeout(function () {
-        element.scrollTop = element.scrollTop + perTick;
-        if (element.scrollTop === to) return;
-        scrollTo(element, to, duration - 10);
-    }, 10);
+  if (duration <= 0) return;
+  var difference = to - element.scrollTop;
+  var perTick = difference / duration * 10;
+  setTimeout(function() {
+    element.scrollTop = element.scrollTop + perTick;
+    if (element.scrollTop === to) return;
+    scrollTo(element, to, duration - 10);
+  }, 10);
 }
\ No newline at end of file
diff --git a/src/js/preset.js b/src/js/preset.js
index 218b900..c5968af 100755
--- a/src/js/preset.js
+++ b/src/js/preset.js
@@ -40,14 +40,14 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
       _clearPresetSelection: function() {
         for (var j = 0; j < this.presets.length; j++) {
-          var p = this.presets[j]; 
+          var p = this.presets[j];
           p.removeClass("plate-setup-prest-tab-selected")
-            .addClass("plate-setup-prest-tab"); 
+            .addClass("plate-setup-prest-tab");
         }
       },
 
-      _selectPreset: function (preset) {
-        this.setCheckboxes(preset.data("preset")); 
+      _selectPreset: function(preset) {
+        this.setCheckboxes(preset.data("preset"));
         preset.removeClass("plate-setup-prest-tab")
           .addClass("plate-setup-prest-tab-selected");
       },
diff --git a/src/js/tabs.js b/src/js/tabs.js
index 8ff9545..7a8482e 100755
--- a/src/js/tabs.js
+++ b/src/js/tabs.js
@@ -30,7 +30,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var tabData = this.options.attributes.tabs;
         var that = this;
 
-        tabData.forEach(function (tab, tabIndex) {
+        tabData.forEach(function(tab, tabIndex) {
           that.allTabs[tabIndex] = that._createElement("<div></div>").addClass("plate-setup-tab");
           $(that.allTabs[tabIndex]).data("index", tabIndex)
             .text(tab.name);
@@ -40,7 +40,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           });
 
           $(that.tabHead).append(that.allTabs[tabIndex]);
-        }); 
+        });
 
         this.tabDataContainer = this._createElement("<div></div>").addClass("plate-setup-tab-data-container");
         $(this.tabContainer).append(this.tabDataContainer);
diff --git a/src/js/undo-redo-manager.js b/src/js/undo-redo-manager.js
index e6a226c..c26c954 100755
--- a/src/js/undo-redo-manager.js
+++ b/src/js/undo-redo-manager.js
@@ -13,7 +13,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
       addToUndoRedo: function(data) {
 
         if (this.actionPointer != null) {
-          var i = this.actionPointer + 1; 
+          var i = this.actionPointer + 1;
           if (i < this.undoRedoArray.length) {
             this.undoRedoArray.splice(i, this.undoRedoArray.length - i);
           }
@@ -39,40 +39,40 @@ var plateLayOutWidget = plateLayOutWidget || {};
           }
         };
 
-        this.undoRedoArray = []; 
-        this.actionPointer = null; 
+        this.undoRedoArray = [];
+        this.actionPointer = null;
         this.undoRedoArray.push($.extend({}, data));
       },
 
       undo: function() {
         console.log("undo");
-        return this.shiftUndoRedo(-1); 
+        return this.shiftUndoRedo(-1);
       },
 
       redo: function() {
         console.log("redo");
-        return this.shiftUndoRedo(1); 
-      }, 
+        return this.shiftUndoRedo(1);
+      },
 
-      shiftUndoRedo: function (pointerDiff) {
+      shiftUndoRedo: function(pointerDiff) {
         var pointer = this.actionPointer;
         if (pointer == null) {
-          pointer = this.undoRedoArray.length - 1; 
+          pointer = this.undoRedoArray.length - 1;
         }
-        pointer += pointerDiff; 
-        return this.setUndoRedo(pointer); 
-      }, 
+        pointer += pointerDiff;
+        return this.setUndoRedo(pointer);
+      },
 
-      setUndoRedo: function (pointer) {
+      setUndoRedo: function(pointer) {
         if (pointer < 0) {
-          return false; 
+          return false;
         }
         if (pointer >= this.undoRedoArray.length) {
-          return false; 
+          return false;
         }
-        this.undoRedoActive = true; 
+        this.undoRedoActive = true;
         this.setData(this.undoRedoArray[pointer]);
-        this.actionPointer = pointer; 
+        this.actionPointer = pointer;
         this.undoRedoActive = false;
         this.derivativeChange();
         return true;
diff --git a/src/js/well-area.js b/src/js/well-area.js
index 364a649..e030a53 100644
--- a/src/js/well-area.js
+++ b/src/js/well-area.js
@@ -16,8 +16,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
               for (var c = area.minCol; c <= area.maxCol; c++) {
                 var tile = that.allTiles[c + cols * r];
                 if (tiles.indexOf(tile) < 0) {
-                  if (that.disableAddDeleteWell){
-                    if(that.addressAllowToEdit.indexOf(tile.address) >= 0){
+                  if (that.disableAddDeleteWell) {
+                    if (that.addressAllowToEdit.indexOf(tile.address) >= 0) {
                       tiles.push(tile);
                     }
                   } else {
@@ -155,8 +155,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var cols = this.dimensions.cols;
         var rows = this.dimensions.rows;
 
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
+        var w = this.sizes.spacing;
+        var m = this.sizes.label_spacing;
 
         var x = (coord.x - m) / w;
         var y = (coord.y - m) / w;
@@ -172,12 +172,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
       _wellToCoords: function(well, center) {
         //Convert a well to a coordinate
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
+        var w = this.sizes.spacing;
+        var m = this.sizes.label_spacing;
         var x = well.col * w + m;
         var y = well.row * w + m;
         if (center) {
-          var hw = w/2;
+          var hw = w / 2;
           x = x + hw;
           y = y + hw;
         }
@@ -193,8 +193,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var rows = area.maxRow - area.minRow + 1;
         var cols = area.maxCol - area.minCol + 1;
 
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
+        var w = this.sizes.spacing;
+        var m = this.sizes.label_spacing;
 
         return {
           top: area.minRow * w + m,
@@ -209,8 +209,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var rows = this.dimensions.rows;
         var cols = this.dimensions.cols;
 
-        var w = this.sizes.spacing; 
-        var m = this.sizes.label_spacing; 
+        var w = this.sizes.spacing;
+        var m = this.sizes.label_spacing;
 
         var left = (rect.left - m) / w;
         var top = (rect.top - m) / w;

From 211f879a05957fd3ea3e0a7d87f67c6b37aa6b73 Mon Sep 17 00:00:00 2001
From: Jeremy Gore <jeremy.gore@tessella.com>
Date: Fri, 5 Apr 2019 11:57:02 -0400
Subject: [PATCH 07/10] Document createObject

---
 README.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/README.md b/README.md
index ff51d22..3eddc3e 100644
--- a/README.md
+++ b/README.md
@@ -233,6 +233,12 @@ This function may be called at any time to load data. Well data should be passed
 }
 ```
 
+## createObject()
+Calling this function will return the current state of the plate-map, in the form as passed into `getPlates`.
+```js
+$("#my-plate-layout").plateLayOut("createObject")
+```
+
 ## isReadOnly()
 This function will disable editing of the plates, set `flag` to true for read only mode and set `flag` to false to disable read only mode
 ```js

From 18781f536286882cdbeb5c8aa9176413d6c4124f Mon Sep 17 00:00:00 2001
From: Jeremy Gore <jeremy.gore@tessella.com>
Date: Fri, 5 Apr 2019 11:54:53 -0400
Subject: [PATCH 08/10] Work with select2 v4

---
 gulpfile.js            |  21 ++----
 package-lock.json      |  22 +++++--
 package.json           |   2 +-
 src/js/add-tab-data.js |   6 +-
 src/js/create-field.js | 141 ++++++++++++++++-------------------------
 5 files changed, 80 insertions(+), 112 deletions(-)

diff --git a/gulpfile.js b/gulpfile.js
index 0025657..ade0fa5 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -21,19 +21,15 @@ const PATH = {
         dependencies: {
             css: [
                 'node_modules/bootstrap/dist/css/bootstrap.css',
-                'node_modules/select2/select2.css'
+                'node_modules/select2/dist/css/select2.css'
             ],
             js: [
                 'node_modules/jquery/dist/jquery.js',
                 'node_modules/jquery-ui-dist/jquery-ui.js',
                 'node_modules/bootstrap/dist/js/bootstrap.js',
-                'node_modules/select2/select2.js',
+                'node_modules/select2/dist/js/select2.js',
                 'node_modules/fabric/dist/fabric.js',
                 'node_modules/clipboard/dist/clipboard.js'
-            ],
-            img: [
-                'node_modules/select2/*.png',
-                'node_modules/select2/*.gif'
             ]
         },
     },
@@ -56,7 +52,7 @@ const PATH = {
     }
 };
 
-let config = {source: {css: '', js: '', img: '', html: '', json: ''}, destination: {css: '', js: '', root: ''}};
+let config = {source: {css: '', js: '', html: '', json: ''}, destination: {css: '', js: '', root: ''}};
 
 function concat_minify_css(name, source, destination) {
     return gulp.src(source, { sourcemaps: true })
@@ -79,7 +75,6 @@ function concat_uglify_js(name, source, destination) {
 function config_env(env) {
     config.source.css = PATH.source.dependencies.css.concat(PATH.source.app.css);
     config.source.js = PATH.source.dependencies.js.concat(PATH.source.app.js);
-    config.source.img = PATH.source.dependencies.img;
     config.source.html = PATH.source.app.html;
     config.destination.css = PATH.destination[env].css;
     config.destination.js = PATH.destination[env].js;
@@ -123,12 +118,6 @@ gulp.task('copy.src', () => {
     return mergeStream(css, js);
 });
 
-// Copy images of Select2 (v3.5.1) dependency to 'dist/prod/css'
-gulp.task('copy.img', () => {
-    return gulp.src(config.source.img)
-        .pipe(gulp.dest(config.destination.css));
-});
-
 gulp.task('inject.prod', () => {
     return gulp.src(config.source.html)
         .pipe(inject(gulp.src([`${config.destination.css}/*.min.css`, `${config.destination.js}/*.min.js`], {read: false}),
@@ -176,11 +165,11 @@ gulp.task('server.prod', async () => {
 
 gulp.task('build.dist', gulp.series('config.pack', 'clean', 'css', 'js'));
 
-gulp.task('build.dev', gulp.series('config.dev', 'clean', 'copy.src', 'copy.img', 'inject.dev'));
+gulp.task('build.dev', gulp.series('config.dev', 'clean', 'copy.src', 'inject.dev'));
 
 gulp.task('serve.dev', gulp.series('build.dev', 'server.dev'));
 
-gulp.task('build.prod', gulp.series('config.prod', 'clean', 'css', 'js', 'copy.img', 'inject.prod'));
+gulp.task('build.prod', gulp.series('config.prod', 'clean', 'css', 'js', 'inject.prod'));
 
 gulp.task('serve.prod', gulp.series('build.prod', 'server.prod'));
 
diff --git a/package-lock.json b/package-lock.json
index f3372bb..ca6eda6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "plate-map",
-  "version": "1.0.1",
+  "version": "1.0.2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -53,6 +53,11 @@
         "uri-js": "^4.2.2"
       }
     },
+    "almond": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz",
+      "integrity": "sha1-oOfJWsdiTWQXtElLHmi/9pMWiiA="
+    },
     "ansi-colors": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
@@ -3708,6 +3713,11 @@
       "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
       "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
     },
+    "jquery-mousewheel": {
+      "version": "3.1.13",
+      "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz",
+      "integrity": "sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU="
+    },
     "jquery-ui-dist": {
       "version": "1.12.1",
       "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.12.1.tgz",
@@ -5322,9 +5332,13 @@
       "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0="
     },
     "select2": {
-      "version": "3.5.1",
-      "resolved": "https://registry.npmjs.org/select2/-/select2-3.5.1.tgz",
-      "integrity": "sha1-8oGUibvGX9bTKL5yu+K5XdfofP4="
+      "version": "4.0.6-rc.1",
+      "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.6-rc.1.tgz",
+      "integrity": "sha1-qmwwOKfw8ukf+t448KIcFeGBMnY=",
+      "requires": {
+        "almond": "~0.3.1",
+        "jquery-mousewheel": "~3.1.13"
+      }
     },
     "semver": {
       "version": "5.6.0",
diff --git a/package.json b/package.json
index 4f0efc3..298dc7c 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,7 @@
     "jquery": "^3.3.1",
     "jquery-ui-dist": "^1.12.1",
     "popper.js": "^1.14.7",
-    "select2": "^3.5.1"
+    "select2": "^4.0.6-rc.1"
   },
   "devDependencies": {
     "browser-sync": "^2.26.3",
diff --git a/src/js/add-tab-data.js b/src/js/add-tab-data.js
index c08e86a..dc2dd82 100755
--- a/src/js/add-tab-data.js
+++ b/src/js/add-tab-data.js
@@ -226,11 +226,9 @@ var plateLayOutWidget = plateLayOutWidget || {};
         });
 
         field.getValue = function() {
-          var v = field.input.select2('data');
+          var v = field.input.val();
           if (v.length) {
-            return v.map(function(i) {
-              return i.id;
-            });
+            return v;
           }
           return null;
         };
diff --git a/src/js/create-field.js b/src/js/create-field.js
index 249cc8f..2e4ed37 100755
--- a/src/js/create-field.js
+++ b/src/js/create-field.js
@@ -3,7 +3,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
 (function($, fabric) {
 
   plateLayOutWidget.createField = function() {
-    // It create those fields in the tab , there is 4 types of them.
+    // It creates those fields in the tab , there is 4 types of them.
     return {
 
       _createField: function(field) {
@@ -90,17 +90,18 @@ var plateLayOutWidget = plateLayOutWidget || {};
           placeholder: "select",
           minimumResultsForSearch: 10
         };
+        var data_specified = false;
 
         if (config.options) {
           opts.data = config.options;
-        } else if (config.query) {
-          var query = config.query;
-          if (config.delay) {
-            query = this._debounce(config.delay, query);
-          }
-          opts.query = query;
-        } else {
-          throw "Must specify data or query";
+          data_specified = true;
+        }
+        if (config.ajax) {
+          opts.ajax = ajax;
+          data_specified = true;
+        }
+        if (!data_specified) {
+          throw "Must specify data or ajax";
         }
         return opts;
       },
@@ -108,7 +109,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
       _createSelectField: function(field) {
         var id = field.id;
         var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
+        var input = this._createElement("<select/>").attr("id", id)
           .addClass("plate-setup-tab-select-field");
 
         field.root.find(".plate-setup-tab-field-container").append(input);
@@ -143,21 +144,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
         };
 
         field.getValue = function() {
-          var v = input.select2('data');
-          return v ? v.id : null;
+          return input.val();
         };
 
         field.setValue = function(v) {
-          if (v) {
-            v = optMap[v];
-          }
-          input.select2('data', v);
-        };
-
-        field.setOpts = function(v) {
-          input.select2('data', {});
-          opts.data = v || [];
-          input.select2(opts);
+          input.val(v);
+          input.trigger("change.select2")
         };
 
         field.getText = function(v) {
@@ -193,7 +185,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
       _createMultiSelectField: function(field) {
         var id = field.id;
         var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
+        var input = this._createElement("<select/>").attr("id", id)
           .addClass("plate-setup-tab-multiselect-field");
         input.attr("multiple", "multiple");
 
@@ -229,36 +221,18 @@ var plateLayOutWidget = plateLayOutWidget || {};
           return v;
         };
 
-        field.setOpts = function(v) {
-          var allOpts = field.data.options;
-          var selectedVal = [];
-          for (var id in allOpts) {
-            var curOpts = allOpts[id];
-            if (v.indexOf(curOpts["id"]) >= 0) {
-              selectedVal.push(curOpts);
-            }
-          }
-
-          opts.data = selectedVal;
-          input.select2(opts);
-        };
-
         field.getValue = function() {
-          var v = input.select2('data');
+          var v = input.val();
           if (v.length) {
-            return v.map(function(i) {
-              return i.id;
-            });
+            return v;
           }
           return null;
         };
 
         field.setValue = function(v) {
           v = v || [];
-          v = v.map(function(i) {
-            return optMap[i];
-          });
-          input.select2('data', v);
+          input.val(v);
+          input.trigger("change.select2");
         };
 
         field.getText = function(v) {
@@ -306,11 +280,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
           return v;
         };
 
-        input.on("change", function(e, generated) {
-          var added = e.added;
-          var removed = e.removed;
-          //field.onChange();
-          field.multiOnChange(added, removed);
+        input.on("select2:select", function (e) {
+          field.multiOnChange(e.params.data, null);
+        });
+
+        input.on("select2:unselect", function (e) {
+          field.multiOnChange(null, e.params.data);
         });
 
         field.input = input;
@@ -355,7 +330,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             unitText.text(defaultUnit);
             field.root.find(".plate-setup-tab-field-container").append(unitText);
           } else {
-            unitInput = this._createElement("<input/>").attr("id", id)
+            unitInput = this._createElement("<select/>").attr("id", id)
               .addClass("plate-setup-tab-label-select-field");
 
             field.root.find(".plate-setup-tab-field-container").append(unitInput);
@@ -367,7 +342,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
                 text: unit
               };
               if (unit == defaultUnit) {
-                selected = o;
+                selected = unit;
               }
               return o;
             });
@@ -379,7 +354,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
             };
 
             unitInput.select2(opts);
-            unitInput.select2("data", selected);
+            unitInput.val(selected);
           }
         }
 
@@ -404,7 +379,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
                 text: curUnit
               };
               if (curUnit == field.defaultUnit) {
-                selected = cleanUnit;
+                selected = curUnit;
               }
               return cleanUnit;
             });
@@ -415,8 +390,11 @@ var plateLayOutWidget = plateLayOutWidget || {};
             allowClear: false,
             minimumResultsForSearch: 10
           };
+          unitInput.select2("destroy");
+          unitInput.val(null);
+          unitInput.empty();
           unitInput.select2(newOpts);
-          unitInput.select2("data", selected);
+          unitInput.val(selected);
         };
 
         field.parseValue = function(value) {
@@ -546,13 +524,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
         field.setUnit = function(unit) {
           if (unitInput) {
             unit = unit || field.defaultUnit;
-            if (unit != null) {
-              unit = {
-                id: unit,
-                text: unit
-              };
-            }
-            unitInput.select2("data", unit);
+            unitInput.val(unit);
+            unitInput.trigger("change.select2");
           }
         };
 
@@ -619,7 +592,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
       _createBooleanField: function(field) {
         var id = field.id;
         var that = this;
-        var input = this._createElement("<input/>").attr("id", id)
+        var input = this._createElement("<select/>").attr("id", id)
           .addClass("plate-setup-tab-select-field");
         that.defaultWell[id] = null;
 
@@ -636,14 +609,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
           data: [tval, fval],
           placeholder: "select",
           allowClear: true,
-          minimumResultsForSearch: -1,
-          initSelection: function(element, callback) {
-            var v = element.val();
-            callback({
-              id: v,
-              text: v
-            });
-          }
+          minimumResultsForSearch: -1
         };
 
         input.select2(opts);
@@ -683,13 +649,14 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         field.setValue = function(v) {
           if (v == true || v == "true") {
-            v = tval;
+            v = "true";
           } else if (v == false || v == "false") {
-            v = fval;
+            v = "false";
           } else {
             v = null;
           }
-          input.select2('data', v);
+          input.val(v);
+          input.trigger("change.select2");
         };
 
         field.getText = function(v) {
@@ -720,17 +687,13 @@ var plateLayOutWidget = plateLayOutWidget || {};
         var fieldContainer1 = that._createElement("<div></div>").addClass("plate-setup-tab-field-container-singleSelect");
         field.root.find(".plate-setup-tab-field-right-side").append(nameContainer1, fieldContainer1);
 
-        field.singleSelect = this._createElement("<input/>").attr("id", field.id + "SingleSelect")
+        field.singleSelect = this._createElement("<select/>").attr("id", field.id + "SingleSelect")
           .addClass("plate-setup-tab-multiplex-single-select-field");
 
         field.singleSelect.appendTo(fieldContainer1);
 
         field.singleSelectValue = function() {
-          var v = field.singleSelect.select2("data");
-          if (v != null) {
-            v = v.id;
-          }
-          return v;
+          return field.singleSelect.val();
         };
 
         var setSingleSelectOptions = function(v, selected_v) {
@@ -739,18 +702,24 @@ var plateLayOutWidget = plateLayOutWidget || {};
             placeholder: "select",
             minimumResultsForSearch: 10,
             data: v || []
-          }
+          };
           if (!selected_v) {
             if (opts.data.length) {
-              selected_v = opts.data[0];
+              selected_v = opts.data[0].id;
             } else {
               selected_v = null;
             }
           }
-          field.singleSelect.select2('data', []);
+          if (field.singleSelect.hasClass("select2-hidden-accessible")) {
+            field.singleSelect.select2("destroy");
+          }
+          field.singleSelect.val(null);
+          field.singleSelect.empty();
           field.singleSelect.select2(opts);
-          field.singleSelect.select2('data', selected_v);
+          field.singleSelect.val(selected_v);
           field.singleSelect.prop("disabled", opts.data.length == 0);
+          field.singleSelect.trigger("change.select2");
+          field.singleSelect.on("change.select2", singleSelectChange);
         };
 
         var singleSelectChange = function() {
@@ -783,8 +752,6 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         setSingleSelectOptions([]);
 
-        field.singleSelect.on("change", singleSelectChange);
-
         field._changeMultiFieldValue = function(added, removed) {
           var newSubFieldValue = {};
           for (var subFieldName in field.data.multiplexFields) {
@@ -971,7 +938,7 @@ var plateLayOutWidget = plateLayOutWidget || {};
               });
             });
             // set the newest selected to be the current obj
-            curOpt = selectList[v.length - 1];
+            curOpt = selectList[v.length - 1].id;
           }
 
           field.detailData = newMultiplexVal;

From bb2c7a5e4f6f328c002894cacd55191153cd67d5 Mon Sep 17 00:00:00 2001
From: Jeremy Gore <jeremy.gore@tessella.com>
Date: Fri, 5 Apr 2019 13:46:06 -0400
Subject: [PATCH 09/10] Prevent select2 v4.0.6rc1 from opening dropdown on
 unselect

---
 src/js/create-field.js | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/js/create-field.js b/src/js/create-field.js
index 2e4ed37..2b174e9 100755
--- a/src/js/create-field.js
+++ b/src/js/create-field.js
@@ -179,6 +179,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
           field.onChange();
         });
 
+
+        input.on('select2:unselect', function (evt) {
+            // Prevent select2 v4.0.6rc1 opening dropdown on unselect
+            input.one('select2:opening', function(e) { e.preventDefault(); });
+        });
+
         field.input = input;
       },
 
@@ -286,6 +292,8 @@ var plateLayOutWidget = plateLayOutWidget || {};
 
         input.on("select2:unselect", function (e) {
           field.multiOnChange(null, e.params.data);
+          // Prevent select2 v4.0.6rc1 opening dropdown on unselect
+          input.one('select2:opening', function(e) { e.preventDefault(); });
         });
 
         field.input = input;
@@ -672,6 +680,12 @@ var plateLayOutWidget = plateLayOutWidget || {};
           field.onChange();
         });
 
+
+        input.on('select2:unselect', function (evt) {
+          // Prevent select2 v4.0.6rc1 opening dropdown on unselect
+          input.one('select2:opening', function(e) { e.preventDefault(); });
+        });
+
         field.input = input;
       },
 

From 8ac7ca952ff5be813d0272b1c5309516d012eccd Mon Sep 17 00:00:00 2001
From: Jeremy Gore <jeremy.gore@tessella.com>
Date: Fri, 5 Apr 2019 14:02:55 -0400
Subject: [PATCH 10/10] Version 1.0.3

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 298dc7c..30ecb6d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "plate-map",
-  "version": "1.0.2",
+  "version": "1.0.3",
   "description": "JavaScript Plate Layout is an open source tool developed collaboratively by [Chai Biotechnologies](www.chaibio.com) and [New England Biolabs](www.neb.com) for visualizing and editing the layout of scientific assay plates.",
   "scripts": {
     "build.dist": "gulp build.dist",