Friday, August 30, 2019

Convert Pdf to images then extract Text from each Image


Tasks
1) Convert online pdf to images
2) Convert local pdf to images
3) Convert images to bytes and Base64
4) Extract text from each image Arabic/English
5) Save images to local HD

Ubuntu Packages

apt-get install python3

apt install linuxbrew-wrapper
brew install poppler
or
sudo add-apt-repository ppa:opencpu/poppler
sudo apt-get update
sudo apt-get install python-poppler
sudo apt-get install -y poppler-utils

pip3 install pdf2image

if you have problem with pip3 use
sudo apt-get install python3-setuptools
sudo easy_install3 pip

pip3 install pillow
sudo apt install python3-dev libpython3-dev
sudo apt install python3-mysqldb
sudo apt-get install tesseract-ocr
pip3 install pillow pytesseract

Download Arabic support for OCR

sudo apt-get install tesseract-ocr-eng
sudo apt-get install tesseract-ocr-ara

OR

seach for tessdata dir and download ara.traineddata lang inside it
find / -name tessdata
wget https://github.com/tesseract-ocr/tessdata/blob/master/ara.traineddata

Code

from pdf2image import convert_from_path,convert_from_bytes
import requests
def ConvertOnlinePdf2Images(pdfFileURL,outputPath):
    dpi=500
    output_folder=None
    first_page=None
    last_page=None
    fmt='ppm'
    thread_count=20
    userpw=None
    use_cropbox=False
    strict=False
    transparent=False
    single_file=False
    output_file=''
    poppler_path='/usr/local/bin/'

    pdfFileBytes = requests.get(pdfFileURL)
    pages = convert_from_bytes( pdfFileBytes.content , dpi, output_folder, first_page, last_page, fmt, thread_count, userpw, use_cropbox, strict, transparent, single_file, output_file, poppler_path)
    for i in range(len(pages)):
        OCR(pages[i])
        IMG_Base64(IMG_Bytes(pages[i]))
        newfilename = outputPath + str(i) + '.jpeg'
        pages[i].save(newfilename, 'JPEG')


def ConvertPdfFile2Image(PDFfileName):
    dpi=500
    output_folder=None
    first_page=None
    last_page=None
    fmt='ppm'
    thread_count=1
    userpw=None
    use_cropbox=False
    strict=False
    transparent=False
    single_file=False
    output_file=''
    poppler_path='/usr/local/bin/'

    pages = convert_from_path(PDFfileName, dpi, output_folder, first_page, last_page, fmt, thread_count, userpw, use_cropbox, strict, transparent, single_file, output_file, poppler_path)
    for i in range(len(pages)):
        OCR(pages[i])
        IMG_Base64(IMG_Bytes(pages[i]))
        newfilename = PDFfileName[:-4] + str(i) + '.jpeg'
        pages[i].save(newfilename, 'JPEG')



from PIL import Image
import pytesseract
def OCR(img):
    pytesseract.pytesseract.tesseract_cmd = '/usr/local/bin/tesseract'
    text = pytesseract.image_to_string(img,lang='ara+eng')
    print(text)
 

import io
def IMG_Bytes(pil_im):
    b = io.BytesIO()
    pil_im.save(b, 'jpeg')
    im_bytes = b.getvalue()
    return im_bytes
 
import base64
def IMG_Base64(img):
    encoded_string = base64.b64encode(img)
    print(encoded_string)
 



import os
#OCR + IMG Bytes from online pdf
url=r"http://localhost:8888/sg248226.pdf"
ConvertOnlinePdf2Images(url,"/temp")
#OCR + IMG Bytes from local pdf
ConvertPdfFile2Image("/Users/rafie/1.pdf")

Tuesday, August 27, 2019

Smart Grid Using VUE js support group by and filter and Use Template and Partial Template concept










SOURCE CODE



<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.18/vue.min.js"></script>
 
    <style>
@font-face {
  font-family: 'Material Icons';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/materialicons/v48/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2) format('woff2');
}

.material-icons {
  font-family: 'Material Icons';
  font-weight: normal;
  font-style: normal;
  font-size: 24px;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}
html {
  font-size: 14px;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}
*, *:before, *:after {
  -moz-box-sizing: inherit;
  -webkit-box-sizing: inherit;
  box-sizing: inherit;
}
body {
  font-family: "Open Sans", sans-serif;
  font-weight: 400;
  line-height: 1.45;
  color: #414550;
  background-color: #fff;
}
section, footer {
  margin-top: 64px;
}
a {
  color: #2196f3;
  text-decoration: none;
}
a:hover {
  color: #0c7cd5;
}
h1, h2, h3, h4, h5, h6 {
  margin: 0.75em 0;
  line-height: 1.45;
  font-weight: 600;
  color: #363942;
}
h1 {
  margin-top: 0;
  font-size: 34px;
}
h2 {
  font-size: 27px;
}
ul, ol {
  padding-left: 30px;
}
li {
  list-style: disc;
}
strong {
  font-weight: 600;
}
.text-centre {
  text-align: center;
}
/* Containers */
.container {
  width: 1160px;
  margin: 0 auto;
  padding: 0 15px;
}
.container.container-fluid {
  width: 100%;
}
.control-group {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: horizontal;
  -webkit-box-direction: normal;
  -webkit-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
  -webkit-flex-wrap: nowrap;
  -ms-flex-wrap: nowrap;
  flex-wrap: nowrap;
  -webkit-box-pack: start;
  -webkit-justify-content: flex-start;
  -ms-flex-pack: start;
  justify-content: flex-start;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
  align-items: center;
}
.control {
  -webkit-flex-shrink: 0;
  -ms-flex-negative: 0;
  flex-shrink: 0;
  -webkit-box-flex: 0;
  -webkit-flex-grow: 0;
  -ms-flex-positive: 0;
  flex-grow: 0;
  margin-left: 0;
  margin-right: 10px;
}
.control:last-child {
  margin-right: 0;
}
.control.control-right {
  margin-left: auto;
}
.control.control-right:first-child {
  margin-right: 0;
}
.control.control-fill {
  -webkit-box-flex: 1;
  -webkit-flex-grow: 1;
  -ms-flex-positive: 1;
  flex-grow: 1;
  -webkit-flex-shrink: 1;
  -ms-flex-negative: 1;
  flex-shrink: 1;
}
/* Icons */
.icon {
  display: inline-block;
  font-size: 18px;
  vertical-align: text-bottom;
}
.icon.icon-24 {
  font-size: 24px;
}
.icon.icon-36 {
  font-size: 36px;
}
.icon.icon-48 {
  font-size: 48px;
}
/* Buttons */
.icon-button {
  display: inline-block;
  margin: 0 5px;
  color: #6f7688;
  cursor: pointer;
  outline: none;
  background: none;
  border: none;
  text-align: center;
  line-height: 1em;
}
.icon-button:hover {
  color: #363942;
}
.icon-button.button-accent:hover {
  color: #0c7cd5;
}
.button-group {
  display: inline-block;
  position: relative;
  margin-right: 5px;
}
.button-group .button {
  margin: 0;
}
/* Inputs */
input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]), select, textarea {
  width: 100%;
  min-width: 150px;
  padding: 10px 12px;
  font-family: inherit;
  font-size: 14px;
  line-height: 1.45;
  color: #414550;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 2px;
  outline: none;
  -webkit-transition: border 150ms ease-out;
  -moz-transition: border 150ms ease-out;
  -o-transition: border 150ms ease-out;
  transition: border 150ms ease-out;
}
input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]):focus, select:focus, textarea:focus {
  border-color: #2196f3;
}
input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]):disabled, select:disabled, textarea:disabled {
  background-color: #fafafc;
  cursor: not-allowed;
}
input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]):invalid, select:invalid, textarea:invalid {
  border-color: #de6060;
}
input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]):invalid + .validation-message, select:invalid + .validation-message, textarea:invalid + .validation-message {
  display: block;
}
input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]), select {
  height: 42px;
}
input[type="checkbox"], input[type="radio"] {
  opacity: 0;
}
.toggle {
  display: inline-block;
  position: relative;
  margin-right: 5px;
  background-color: #fafafc;
  border: 1px solid #ddd;
  vertical-align: text-bottom;
}
.toggle label {
  position: absolute;
  display: block;
  content: " ";
  margin: 0;
  cursor: pointer;
}
.toggle + label {
  display: inline-block;
  margin: 0 15px 0 0;
  cursor: pointer;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.toggle-switch {
  width: 32px;
  height: 18px;
  border-radius: 12px;
}
.toggle-switch label {
  top: 0;
  left: 0;
  width: 32px;
  height: 18px;
}
.toggle-switch label:after {
  position: absolute;
  display: block;
  content: " ";
  width: 12px;
  height: 12px;
  top: 2px;
  left: 2px;
  background-color: #6f7688;
  border-radius: 50%;
  -webkit-transition: all 200ms ease-out;
  -moz-transition: all 200ms ease-out;
  -o-transition: all 200ms ease-out;
  transition: all 200ms ease-out;
}
.toggle-switch:hover label:after {
  background-color: #2196f3;
}
.toggle-switch input[type="checkbox"]:focus label:after {
  background-color: #2196f3;
}
.toggle-switch input[type="checkbox"]:checked + label:after {
  left: 16px;
  background-color: #2196f3;
}
.toggle-switch input[type="checkbox"]:disabled + label:after {
  background-color: #6f7688;
}
.toggle-checkbox {
  width: 18px;
  height: 18px;
  border: none;
}
.toggle-checkbox label {
  width: 18px;
  height: 18px;
  top: 0;
  left: 0;
  border: 1px solid #ddd;
  border-radius: 2px;
  -webkit-transition: border 150ms ease-out;
  -moz-transition: border 150ms ease-out;
  -o-transition: border 150ms ease-out;
  transition: border 150ms ease-out;
}
.toggle-checkbox label:after {
  position: absolute;
  display: block;
  content: " ";
  width: 6px;
  height: 12px;
  top: 1px;
  left: 5px;
  border-right: 3px solid transparent;
  border-bottom: 3px solid transparent;
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  transform: rotate(45deg);
  -webkit-transition: all 200ms ease-out;
  -moz-transition: all 200ms ease-out;
  -o-transition: all 200ms ease-out;
  transition: all 200ms ease-out;
}
.toggle-checkbox label:hover {
  border-color: #2196f3;
}
.toggle-checkbox input[type="checkbox"]:focus label {
  border-color: #2196f3;
}
.toggle-checkbox input[type="checkbox"]:checked + label {
  background-color: #2196f3;
  border-color: #2196f3;
}
.toggle-checkbox input[type="checkbox"]:checked + label:after {
  border-color: #fff;
}
.toggle-radio {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  -webkit-transition: border 150ms ease-out;
  -moz-transition: border 150ms ease-out;
  -o-transition: border 150ms ease-out;
  transition: border 150ms ease-out;
}
.toggle-radio label {
  top: 0;
  left: 0;
  width: 18px;
  height: 18px;
}
.toggle-radio label:after {
  position: absolute;
  display: block;
  content: " ";
  width: 10px;
  height: 10px;
  top: 3px;
  left: 3px;
  background-color: #6f7688;
  border-radius: 50%;
  -webkit-transition: all 200ms ease-out;
  -moz-transition: all 200ms ease-out;
  -o-transition: all 200ms ease-out;
  transition: all 200ms ease-out;
}
.toggle-radio:hover {
  border-color: #2196f3;
}
.toggle-radio input[type="radio"]:focus label:after {
  background-color: #2196f3;
}
.toggle-radio input[type="radio"]:checked + label:after {
  background-color: #2196f3;
}
/* Tables */
.table-wrapper {
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 2px;
}
.table-wrapper.table-wrapper-responsive {
  max-width: 100%;
  overflow-x: auto;
}
.table-wrapper.table-wrapper-responsive table, .table-wrapper.table-wrapper-responsive .table {
  table-layout: auto;
  width: auto;
  min-width: 100%;
}
.table-wrapper table, .table-wrapper .table {
  border: none;
}
table, .table {
  display: table;
  table-layout: fixed;
  border-collapse: collapse;
  border-spacing: 0;
  width: 100%;
  border: 1px solid #ddd;
}
.table-striped tbody tr:nth-child(odd) td, .table-striped .tbody tr:nth-child(odd) td, .table-striped tbody .tr:nth-child(odd) td, .table-striped .tbody .tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) .td, .table-striped .tbody tr:nth-child(odd) .td, .table-striped tbody .tr:nth-child(odd) .td, .table-striped .tbody .tr:nth-child(odd) .td {
  background-color: #fdfdfd;
}
thead, .thead {
  display: table-header-group;
}
tbody, .tbody {
  display: table-row-group;
}
tbody:last-of-type tr:last-child td, .tbody:last-of-type tr:last-child td, tbody:last-of-type tr:last-child .td, .tbody:last-of-type tr:last-child .td {
  border-bottom: none;
}
tbody td, .tbody td, tbody .td, .tbody .td {
  border-bottom: 1px solid #eee;
}
tbody td > input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]), .tbody td > input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]), tbody .td > input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]), .tbody .td > input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]) {
  background-color: transparent;
  border: none;
  height: auto;
  padding: 0;
}
tfoot, .tfoot {
  display: table-footer-group;
}
tfoot td, .tfoot td, tfoot .td, .tfoot .td {
  background-color: #fafafc;
  border-top: 1px solid #ddd;
}
th, .th, td, .td {
  display: table-cell;
  padding: 8px 15px;
  text-align: left;
  vertical-align: middle;
}
th:not(:last-of-type), .th:not(:last-of-type), td:not(:last-of-type), .td:not(:last-of-type) {
  border-right: 1px solid #ddd;
}
th, .th {
  padding: 15px;
  font-weight: 600;
  color: #363942;
  background-color: #fafafc;
  border-bottom: 1px solid #ddd;
  white-space: nowrap;
}
th .toggle, .th .toggle {
  background-color: #fff;
}
tr.table-group-header td, .tr.table-group-header td {
  font-weight: 600;
  background-color: #fafafc;
}
/* Dropdown */
.dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 150px;
  margin-top: 5px;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 2px;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15);
  -webkit-transform-origin: top left;
  -moz-transform-origin: top left;
  -ms-transform-origin: top left;
  -o-transform-origin: top left;
  transform-origin: top left;
  z-index: 98;
  overflow: hidden;
  overflow-y: auto;
}
.dropdown.dropdown-top-left, .dropdown.dropdown-bottom-left {
  left: auto;
  right: 0;
}
.dropdown.dropdown-bottom-left, .dropdown.dropdown-bottom-right {
  top: auto;
  bottom: 100%;
  margin-top: 0;
  margin-bottom: 5px;
}
.dropdown.dropdown-top-left {
  -webkit-transform-origin: top right;
  -moz-transform-origin: top right;
  -ms-transform-origin: top right;
  -o-transform-origin: top right;
  transform-origin: top right;
}
.dropdown.dropdown-bottom-left {
  left: auto;
  right: 0;
  -webkit-transform-origin: bottom right;
  -moz-transform-origin: bottom right;
  -ms-transform-origin: bottom right;
  -o-transform-origin: bottom right;
  transform-origin: bottom right;
}
.dropdown.dropdown-bottom-right {
  -webkit-transform-origin: bottom left;
  -moz-transform-origin: bottom left;
  -ms-transform-origin: bottom left;
  -o-transform-origin: bottom left;
  transform-origin: bottom left;
}
.dropdown .menu-item {
  padding: 10px 15px;
  cursor: pointer;
}
.dropdown .menu-item:hover {
  background-color: #f2f2f7;
}
.dropdown-transition {
  -webkit-transition: opacity 100ms ease-out, transform 100ms ease-out;
  -moz-transition: opacity 100ms ease-out, transform 100ms ease-out;
  -moz-transition: opacity 100ms ease-out, transform 100ms ease-out;
  -o-transition: opacity 100ms ease-out, transform 100ms ease-out;
  transition: opacity 100ms ease-out, transform 100ms ease-out;
  opacity: 1;
  -webkit-transform: translate(0, 0) scale(1);
  -moz-transform: translate(0, 0) scale(1);
  -ms-transform: translate(0, 0) scale(1);
  -o-transform: translate(0, 0) scale(1);
  transform: translate(0, 0) scale(1);
}
.dropdown-enter, .dropdown-leave {
  opacity: 0;
  -webkit-transform: translate(0, -15px) scale(0.85);
  -moz-transform: translate(0, -15px) scale(0.85);
  -ms-transform: translate(0, -15px) scale(0.85);
  -o-transform: translate(0, -15px) scale(0.85);
  transform: translate(0, -15px) scale(0.85);
}
/* Chips */
.chips {
  display: inline-block;
  margin: 0;
  padding: 0;
  list-style: none;
}
.chip {
  display: inline-block;
  position: relative;
  margin: 5px 5px 5px 0;
  padding: 5px 15px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.45;
  color: #363942;
  background-color: #fafafc;
  border: 1px solid #ddd;
  border-radius: 2px;
  vertical-align: middle;
}
.chip.chip-removable {
  padding-right: 48px;
}
.chip.chip-accent .chip-title, .chip.chip-business .chip-title, .chip.chip-danger .chip-title, .chip.chip-warning .chip-title, .chip.chip-success .chip-title, .chip.chip-accent .chip-subtitle, .chip.chip-business .chip-subtitle, .chip.chip-danger .chip-subtitle, .chip.chip-warning .chip-subtitle, .chip.chip-success .chip-subtitle {
  color: #fff;
}
.chip.chip-accent .chip-remove-button:before, .chip.chip-business .chip-remove-button:before, .chip.chip-danger .chip-remove-button:before, .chip.chip-warning .chip-remove-button:before, .chip.chip-success .chip-remove-button:before, .chip.chip-accent .chip-remove-button:after, .chip.chip-business .chip-remove-button:after, .chip.chip-danger .chip-remove-button:after, .chip.chip-warning .chip-remove-button:after, .chip.chip-success .chip-remove-button:after {
  background-color: #fff;
}
.chip.chip-accent {
  background-color: #2196f3;
  border-color: #2196f3;
}
.chip.chip-accent .chip-remove-button:hover {
  background-color: #0c7cd5;
}
.chip-title, .chip-subtitle {
  display: block;
}
.chip-title {
  font-size: 14px;
  font-weight: 600;
  color: #363942;
}
.chip-subtitle {
  font-size: 11px;
  font-weight: 400;
  color: #6f7688;
}
.chip-remove-button {
  position: absolute;
  top: 50%;
  right: 15px;
  width: 18px;
  height: 18px;
  margin-top: -9px;
  cursor: pointer;
  border-radius: 2px;
  -moz-transition: background 150ms ease-out;
  -o-transition: background 150ms ease-out;
  -webkit-transition: background 150ms ease-out;
  transition: background 150ms ease-out;
}
.chip-remove-button:before, .chip-remove-button:after {
  display: block;
  position: absolute;
  content: " ";
  top: 50%;
  left: 50%;
  width: 16px;
  height: 2px;
  margin-top: -1px;
  margin-left: -8px;
  background-color: #414550;
  -moz-transform-origin: center center;
  -ms-transform-origin: center center;
  -o-transform-origin: center center;
  -webkit-transform-origin: center center;
  transform-origin: center center;
  -moz-transition: background 150ms ease-out;
  -o-transition: background 150ms ease-out;
  -webkit-transition: background 150ms ease-out;
  transition: background 150ms ease-out;
}
.chip-remove-button:before {
  -moz-transform: rotate(-45deg);
  -ms-transform: rotate(-45deg);
  -o-transform: rotate(-45deg);
  -webkit-transform: rotate(-45deg);
  transform: rotate(-45deg);
}
.chip-remove-button:after {
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  -webkit-transform: rotate(45deg);
  transform: rotate(45deg);
}
.chip-remove-button:hover {
  background-color: #2196f3;
}
.chip-remove-button:hover:before, .chip-remove-button:hover:after {
  background-color: #fff;
}
.chip-transition {
  -webkit-transition: transform 100ms ease-out;
  -moz-transition: transform 100ms ease-out;
  -o-transition: transform 100ms ease-out;
  transition: transform 100ms ease-out;
  opacity: 1;
  -webkit-transform: scale(1);
  -moz-transform: scale(1);
  -ms-transform: scale(1);
  -o-transform: scale(1);
  transform: scale(1);
}
.chip-enter, .chip-leave {
  opacity: 0;
  -webkit-transform: scale(0);
  -moz-transform: scale(0);
  -ms-transform: scale(0);
  -o-transform: scale(0);
  transform: scale(0);
}
/* Datagrid */
.datagrid .chip {
  background-color: #fff;
}
.datagrid-header {
  cursor: pointer;
  -moz-user-select: none;
  -ms-user-select: none;
  -webkit-user-select: none;
  user-select: none;
}
.datagrid-toggle-column {
  width: 64px;
  text-align: center;
}
.datagrid-toggle-column .toggle {
  margin: 0;
}
.datagrid-options {
  padding: 15px;
}
.datagrid-options table, .datagrid-options .table {
  table-layout: auto;
}
.datagrid-options-row:not(:first-child) {
  margin-top: 15px;
}
#index {
  margin-bottom: 64px;
}
@media screen and (max-width: 1177px) {
  .container {
    width: 100% !important;
  }
}

    </style>             


<template type="text/x-template" id="dropdown-template">
    <div class="dropdown" v-show="show" v-bind:class="originClass" transition="dropdown">
        <slot>No dropdown content!</slot>
    </div>
</template>

<template type="text/x-template" id="datagrid-template">
    <input  type="text" placeholder="Filter this dataset" v-model="dataFilter" />
<br>
    <table id="{{ id }}" class="table-striped datagrid">
        <thead>
            <tr>
                <th class="datagrid-toggle-column" v-if="allowSelection">
                    <div class="toggle toggle-checkbox">
                        <input type="checkbox" id="allrows" name="allrows" v-model="selectAll">
                        <label for="allrows"></label>
                    </div>
                </th>
                <th v-for="(index, column) in columns" v-bind:style="{ width: getCellWidth(column) }">
                    <div class="control-group">
                        <div class="datagrid-header control control-fill" v-on:click="sortBy(column)">
                            <span>{{ column.name }}</span>
                            <span class="material-icons icon" v-show="sortingKey === column.key">{{ sortingDirection === 1 ? 'expand_more' : 'expand_less' }}</span>
                        </div>
                        <div class="button-group control" v-if="showOptions && index === (columns.length - 1)">
                            <a id="{{ id }}-options" class="icon-button">
                                <span class="material-icons icon">settings</span>
                            </a>
                            <dropdown v-bind:for="id + '-options'" origin="top left" v-bind:preserve-state="true">
                                <datagrid-options v-bind:grid-id="id" v-bind:columns="columns" v-bind:allow-selection.sync="allowSelection" v-bind:allow-edit.sync="allowEdit" v-bind:data-filter.sync="dataFilter" v-bind:grouping-column.sync="groupingColumn" v-bind:show-advanced-options="showAdvancedOptions">
                                </datagrid-options>
                            </dropdown>
                        </div>
                    </div>
                </th>
            </tr>
        </thead>
        <tbody v-for="(groupName, groupData) in data | filterBy dataFilter | orderBy sortingKey sortingDirection | groupBy groupingColumn.key">
            <tr v-if="groupData.length === 0">
                <td class="text-centre" colspan="{{ columnSpan }}"><strong>No Results</strong></td>
            </tr>
            <tr class="table-group-header" v-if="groupingColumn">
                <td colspan="{{ columnSpan }}">{{ formatData(groupingColumn, groupName) }}</td>
            </tr>
            <tr v-for="(index, row) in groupData">
                <td class="datagrid-toggle-column" v-if="allowSelection">
                    <div class="toggle toggle-checkbox">
                        <input type="checkbox" id="{{ getControlId(groupName, index) }}" name="{{ getControlId(groupName, index) }}" v-bind:value="row" v-model="selectedRows">
                        <label for="{{ getControlId(groupName, index) }}"></label>
                    </div>
                </td>
                <td v-for="column in columns">
                    <partial v-bind:name="getCellTemplate(column)"></partial>
                </td>
            </tr>
        </tbody>
        <tfoot v-if="showFooter">
            <tr>
                <td colspan="{{ columnSpan }}">
                    <ul class="chips">
                        <li class="chip chip-removable" v-show="selectedRows.length > 0" transition="chip">
                            <span class="chip-title">Selection</span>
                            <span class="chip-subtitle">{{ selectedRows.length }} rows selected</span>
                            <a class="chip-remove-button" v-on:click="resetSelection()"></a>
                        </li>
                        <li class="chip chip-removable" v-show="dataFilter" transition="chip">
                            <span class="chip-title">Filtering on</span>
                            <span class="chip-subtitle">{{ dataFilter }}</span>
                            <a class="chip-remove-button" v-on:click="resetFilter()"></a>
                        </li>
                        <li class="chip chip-removable" v-show="groupingColumn" transition="chip">
                            <span class="chip-title">Grouping on</span>
                            <span class="chip-subtitle">{{ groupingColumn.name }}</span>
                            <a class="chip-remove-button" v-on:click="resetGrouping()"></a>
                        </li>
                    </ul>
                </td>
            </tr>
        </tfoot>
    </table>
</template>

<template type="text/x-template" id="datagrid-options-template">
    <div class="datagrid-options">
        <!--div class="datagrid-options-row">
            <input type="search" placeholder="Filter this dataset" v-model="dataFilter" />
        </div-->
        <!--div class="datagrid-options-row" v-if="showAdvancedOptions">
            <div class="toggle toggle-switch">
                <input type="checkbox" id="{{ gridId }}-allow-selection" name="{{ gridId }}-allow-selection" value="" v-model="allowSelection">
                <label for="{{ gridId }}-allow-selection"></label>
            </div>
            <label for="{{ gridId }}-allow-selection">Allow Selection</label>
            <div class="toggle toggle-switch">
                <input type="checkbox" id="{{ gridId }}-allow-edit" name="{{ gridId }}-allow-edit" value="" v-model="allowEdit">
                <label for="{{ gridId }}-allow-edit"></label>
            </div>
            <label for="{{ gridId }}-allow-edit">Allow Edit</label>
        </div-->
        <div class="table-wrapper datagrid-options-row">
            <table>
                <thead>
                    <tr>
                        <th>Column</th>
                        <th>Group By</th>
                    </tr>
                </thead>
                <tbody>
                    <!--tr>
                        <td>All</td>
                        <td class="text-centre">
                            <div class="toggle toggle-radio">
                                <input type="radio" id="all" name="group-by" value="" v-model="groupingColumn">
                                <label for="all"></label>
                            </div>
                        </td>
                    </tr-->
                    <tr v-for="column in columns">
                        <td nowrap >{{ column.name }}</td>
                        <td class="text-centre">
                            <div class="toggle toggle-radio">
                                <input type="radio" id="{{ getControlName(column.key, 'grp') }}" name="group-by" v-bind:value="column" v-model="groupingColumn">
                                <label for="{{ getControlName(column.key, 'grp') }}"></label>
                            </div>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</template>




<div id="index" class="container">
        <div class="table-wrapper">
            <datagrid id="dataset-grid"
                v-bind:columns="dataset.columns"
                v-bind:data="dataset.data"
                v-bind:show-advanced-options="true">
            </datagrid>
        </div>
</div>





<script>
Vue.filter("groupBy", function(value, key) {
    var groups = {
        data: value
    };

    if (key) {
        groups = {};
        for (var i = 0; i < value.length; i++) {
            var row = value[i];
            var cell = row[key];

            if (!groups.hasOwnProperty(cell)) {
                groups[cell] = [];
            }

            groups[cell].push(row);
        }

    }
    return groups;
});

Vue.component("dropdown", {
    template: "#dropdown-template",
    props: {

        for: {
            type: String,
            required: true
        },

        origin: {
            type: String,
            default: "top right"
        },

        preserveState: {
            type: Boolean,
            default: false
        }

    },
    computed: {

        originClass: function() {
            switch (this.origin) {
                case "top left":
                    return "dropdown-top-left";
                case "bottom left":
                    return "dropdown-bottom-left";
                case "bottom right":
                    return "dropdown-bottom-right";
            }
        }

    },
    data: function() {
        return {
            show: false
        };
    },
    ready: function() {
        var _this = this;

        var element = document.getElementById(_this.for);

        var hide = function(event) {
            event.stopPropagation();

            if (!(_this.preserveState && _this.$el.contains(event.target))) {
                _this.show = false;
                document.body.removeEventListener("click", hide);
            }

        };

        var show = function(event) {
            event.preventDefault();
            event.stopPropagation();

            var dropdowns = [].slice.call(document.querySelectorAll(".dropdown"));

            dropdowns.forEach(function(dropdown) {
                dropdown.__vue__.show = false;
            });

            if (!_this.show) {
                _this.show = true;

                document.body.addEventListener("click", hide);
            }
        };

        element.addEventListener("click", show);
    }
});

Vue.component("datagridOptions", {
    template: "#datagrid-options-template",
    props: {

        gridId: {
            type: String,
            required: true
        },

        columns: {
            type: Array,
            required: true
        },

        allowSelection: {
            type: Boolean
        },

        allowEdit: {
            type: Boolean
        },

        groupingColumn: {
            type: Object,
            required: true
        },

        dataFilter: {
            type: String,
            required: true
        },

        showAdvancedOptions: {
            type: Boolean
        }

    },
    methods: {

        getControlName(columnKey, suffix) {
            return this.gridId + "-" + columnKey + "-" + suffix;
        }

    }
});

Vue.component("datagrid", {
    template: "#datagrid-template",
    components: ["datagridOptions"],
    props: {

        id: {
            type: String,
            required: true
        },

        columns: {
            type: Array,
            required: true
        },

        data: {
            type: Array
        },

        cellTemplate: {
            type: String,
            required: false,
            default: "defaultGridCell"
        },

        allowSelection: {
            type: Boolean,
            required: false,
    default: false
        },

        allowEdit: {
            type: Boolean,
            required: false,
            default: false
        },

        showDefaultOptions: {
            type: Boolean,
            required: false,
            default: true
        },

        showAdvancedOptions: {
            type: Boolean,
            required: false,
            default: false
        }

    },
    computed: {

        columnSpan: function() {
            return this.allowSelection ? this.columns.length + 1 : this.columns.length;
        },

        showOptions: function() {
            return this.showDefaultOptions || this.showAdvancedOptions;
        },

        showFooter: function() {
            return this.dataFilter || this.groupingColumn || this.selectedRows.length > 0;
        }

    },
    data: function() {

        return {
            sortingKey: null,
            sortingDirection: 1,
            groupingColumn: null,
            dataFilter: null,
            selectedRows: [],
            selectAll: false
        };

    },
    methods: {
callbackclick: function(selectedrow){alert(JSON.stringify(selectedrow));},
        getCellTemplate: function(column) {
            return this.allowEdit ? "editableGridCell" : (column.template || this.cellTemplate);
        },

        getCellWidth: function(column) {
            if (!column.width) {
                return;
            }

            return column.width + (isNaN(column.width) ? "" : "%");
        },

        getControlId: function(groupName, index, suffix) {
            return groupName + "-" + index + (suffix ? "-" + suffix : "");
        },

        sortBy: function(column) {
            if (column.key === this.sortingKey) {
                this.sortingDirection *= -1;
                return;
            }

            this.sortingKey = column.key;
            this.sortingDirection = 1;
        },

        groupBy: function(column) {
            this.groupingColumn = column;
        },

        resetFilter() {
            this.dataFilter = null;
        },

        resetGrouping() {
            this.groupingColumn = null;
        },

        resetSelection() {
            this.selectedRows = [];
            this.selectAll = false;
        },

        formatData: function(column, value) {
            if (column.hasOwnProperty("filter")) {
                var filter = Vue.filter(column.filter.name);
                var args = [].concat(value, column.filter.args);
                return filter.apply(this, args);
            }
            return value;
        }
    },
    watch: {

        "selectAll": function(value) {
            this.selectedRows = value ? [].concat(this.data) : [];
        }

    }
});

Vue.partial("defaultGridCell", "<span>{{ formatData(column, row[column.key]) }}</span>");
Vue.partial("editableGridCell", "<input style=\"border: 1px solid #999999;\" type=\"text\" v-model=\"row[column.key]\" lazy/>");
Vue.partial("linkedGridCell", "<span style=\"color:#336699;cursor:pointer\" v-on:click=\"callbackclick(row)\"><partial name=\"defaultGridCell\"></partial></a>");

var vue = new Vue({
    el: "#index",
delimiters: ['${', '}'],
    data: {
        dataset:{
                        columns:[
                            {
                                key:"GeneralNo",
                                name:"GeneralNo",
                                template:"linkedGridCell"
                            },
                            {
                                key:"Type",
                                name:"Type"
                            },
                            {
                                key:"quantity",
                                name:"quantity",
                                width:33
                            },
                            {
                                key:"AcceptedQuantity",
                                name:"AcceptedQuantity",
                                template:"editableGridCell"
                            },
                            {
                                key:"PriceEGP",
                                name:"PriceEGP",
                                template:"editableGridCell"
                            }
                            ],
                        data:[
                            {
                                "GeneralNo":570,
                                "PrivateNo":5,
                                "Type":"From Another Local Region",
                                "Date":"20190209",
                                "quantity":10,
                                "AcceptedQuantity":0,
                                "PriceEGP":0
                            },
                            {
                                "GeneralNo":600,
                                "PrivateNo":7,
                                "Type":"From Another Local Region",
                                "Date":"20190309",
                                "quantity":10,
                                "AcceptedQuantity":0,
                                "PriceEGP":0
                            },
                            {
                                "GeneralNo":800,
                                "PrivateNo":8,
                                "Type":"From Another Local Region",
                                "Date":"20190409",
                                "quantity":10,
                                "AcceptedQuantity":0,
                                "PriceEGP":0
                            },
                            {
                                "GeneralNo":50980,
                                "PrivateNo":9,
                                "Type":"From Another Local Region",
                                "Date":"20190609",
                                "quantity":10,
                                "AcceptedQuantity":0,
                                "PriceEGP":0
                            },
                     
                            ]
                        }
    }
});
</script>