diff --git a/composer.json b/composer.json index 884b1d6..7692f41 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "doctrine/doctrine-bundle": "^2.12", "doctrine/doctrine-migrations-bundle": "^3.3", "doctrine/mongodb-odm": "^2.7", - "doctrine/mongodb-odm-bundle": "^5.*", + "doctrine/mongodb-odm-bundle": "5.*", "doctrine/orm": "^3.1", "mongodb/mongodb": "^1.18", "phpdocumentor/reflection-docblock": "^5.3", diff --git a/composer.lock b/composer.lock index ffb75a6..e7631c7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "46a368f6c1680011c0f2e135980f8df9", + "content-hash": "169597cc948acc7f627ecd4ff309138e", "packages": [ { "name": "doctrine/cache", diff --git a/public/scripts/edit_graph.js b/public/scripts/edit_graph.js new file mode 100755 index 0000000..89ed17f --- /dev/null +++ b/public/scripts/edit_graph.js @@ -0,0 +1,234 @@ +let canvas, parent, legend, dataDiv, table; +const urlParams = new URLSearchParams(window.location.search); +const graph_code = urlParams.get('code'); +validateUser(graph_code); +let rcTarget = {}; + +$(document).ready( function () { + canvas = document.getElementById("graphCanvas"); + parent = document.getElementById("graphDiv"); + legend = document.getElementById("graphLegend"); + dataDiv = document.getElementById("dataDiv"); + table = new Table(document.getElementById("dataTable")); + + document.getElementById('upload').addEventListener('change', handleFileSelect, false); + + load_data(); + table.reloadEvLi(); + reloadShares(); + + //Click + document.addEventListener('mousemove', (e) => { + const pos = { + x: e.clientX - canvas.offsetLeft, + y: e.clientY - canvas.offsetTop + }; + let obj = checkHit(pos); + + //show point value + if (obj !== null) { + dataDiv.style.left = pos.x + canvas.offsetLeft + "px"; + dataDiv.style.top = pos.y + canvas.offsetTop + "px"; + dataDiv.style.display = "block"; + dataDiv.innerHTML = "" + obj.name + "

" + obj.value + "

"; + } else { + dataDiv.style.display = "none"; + } + }); + + $("#exportBtn").on('click', function (e) { + table.reloadData(); + exportData('tableData'); + }); + + $("#saveBtn").on('click', function (e) { + table.reloadData(); + save_data(); + }); + + $("#drawBtn").on('click', function (e) { + table.reloadData(); + submitData(); + }); + + //RIGHT CLICK menu + $(document).bind("click", function(event) { + document.getElementById("rcMenu").style.display = "none"; + }); + + //odebere řádek + $("#rcDelRow").on('click', function (e) { + e.preventDefault(); + if (rcTarget.parentElement.parentElement.tagName === "THEAD") + return; + table.removeRow(rcTarget.parentElement); + }); + + //přidá řádek + $("#rcAddRow").on('click', function (e) { + e.preventDefault(); + table.addRow(table, rcTarget); + }); + + //odebere sloupec + $('#rcDelCol').on('click', function (e) { + e.preventDefault(); + + table.removeCol(getCellIndex(rcTarget)); + }); + + //přidá sloupec + $('#rcAddCol').on('click', function (e) { + e.preventDefault(); + + table.addCol(getCellIndex(rcTarget)); + }); + + //Sharing + $('#shareBtn').on('click', function (e) { + e.preventDefault(); + + let username = document.getElementById("shareUsername").value; + addShare(username); + }); +}); + +//Resize +$(window).on('resize', function () { + resizeCanvas(canvas, parent); + table.reloadData(); + drawChart(getSettings(), table.data); +}); + +function handleFileSelect(evt) { + let files = evt.target.files; + table.importData(files[0], table); +} + +function submitData() { + table.reloadData(); + drawChart(getSettings(), table.data); +} + +function save_data() { + table.reloadData(); + let settings = getSettings(); + $.ajax({ + url: "php/save_data.php", + type: "post", + dataType: "text", + data: {code: graph_code, data: JSON.stringify(table.data), settings: JSON.stringify(settings), name:settings.title}, + success: function (result) { + //alert("Saved successfully " + result); + } + }); +} + +function load_data() { + $.ajax({ + url: "php/load_data.php", + type: "post", + dataType: "json", + data: {code: graph_code}, + success: function (result) { + if (result.data == null) { + alert("Error: no data found"); + return; + } + table.data = JSON.parse(result.data); + table.updateTable(); + if (result.settings == null) { + alert("Error: no graph settings found"); + } else { + loadSettings(JSON.parse(result.settings)); + } + drawChart(getSettings(), table.data); + } + }) +} + +function getCellIndex(cell) { + let parent = cell.parentElement; + + let children = Array.from(parent.children); + for (let i = 0; i < children.length; i++){ + if (children[i] === cell) { + return i; + } + } +} + +//Nastavení grafu +function getSettings() { + return { + type: document.getElementById('graph_types').value, + y_step: parseFloat(document.getElementById('y_step').value), + b_color: ((document.getElementById('enableBgColor').checked) ? document.getElementById('graphBgColor').value : null), + display_legend: document.getElementById("displayLegend").checked, + display_points: document.getElementById("displayPoints").checked, + display_support_lines: document.getElementById("displaySupportLines").checked, + title: document.getElementById("graphTitle").value, + display_title: document.getElementById("displayTitle").checked, + margin: parseFloat(document.getElementById("graphMargin").value), + custom_x_values: document.getElementById('customXValues').value, + x_label: document.getElementById('xLabel').value, + y_label: document.getElementById('yLabel').value, + }; +} + +function loadSettings(new_settings) { + document.getElementById('graph_types').value = new_settings.type; + document.getElementById('y_step').value = new_settings.y_step; + if (new_settings.b_color !== null) { + document.getElementById('graphBgColor').value = new_settings.b_color; + document.getElementById('enableBgColor').checked = true; + } + document.getElementById("displayLegend").checked = new_settings.display_legend; + document.getElementById("displayPoints").checked = new_settings.display_points; + document.getElementById("displaySupportLines").checked = new_settings.display_support_lines; + document.getElementById("graphTitle").value = new_settings.title; + document.getElementById("displayTitle").checked = new_settings.display_title; + document.getElementById("graphMargin").value = new_settings.margin; + document.getElementById('customXValues').value = new_settings.custom_x_values; + document.getElementById('xLabel').value = new_settings.x_label; + document.getElementById('yLabel').value = new_settings.y_label; +} + +//Sdílení grafu +function reloadShares() { + $.ajax({ + url: "php/load_shares.php", + type: "post", + dataType: "text", + data: {code: graph_code}, + success: function(result) { + document.getElementById("shareList").innerHTML = result; + } + }); +} + +function removeShare(username) { + $.ajax({ + url: "php/remove_share.php", + type: "post", + dataType: "text", + data: {username: username, code: graph_code}, + success: function(result) { + reloadShares(); + } + }); +} + +function addShare(username) { + $.ajax({ + url: "php/add_share.php", + type: "post", + dataType: "text", + data: {username: username, code: graph_code}, + success: function(result) { + //alert(result); + validateUser(graph_code); + reloadShares(); + } + }); +} \ No newline at end of file diff --git a/public/styles/edit_chart.css b/public/styles/edit_chart.css new file mode 100755 index 0000000..6d4abb4 --- /dev/null +++ b/public/styles/edit_chart.css @@ -0,0 +1,105 @@ +main { + display: block; +} + +#mainDiv { + width: 100%; + display: flex; + padding: 10px; +} + +#graphDiv { + width: 75%; + height: 450px; +} + +#mainDiv form { + width: 25%; +} + +#settings_div { + text-align: center; + width: 100%; +} + +#tableDiv { + padding: 0; + overflow: auto; + flex-basis: 75%; +} + +#shareDiv { + padding: 5px; + flex-basis: 25%; + margin-left: 5px; +} + +#secondaryDiv { + display: flex; +} + +#dataTable tr, +#dataTable td, +#dataTable th { + padding: 0; +} + +#dataTable td, +#dataTable th { + height: 2em; +} + +#dataTable th input { + font-weight: bold; +} + +#dataTable input, +#dataTable div { + margin: 0; + width: 100%; + height: 100%; + border: 0; + padding: 0; +} + +#dataTable input { + text-align: center; + background-color: transparent; +} + + +#shareUsername { + width: 100px; + height: 35px; +} + +#shareHeader { + text-align: center; +} + +@media (max-width: 950px) { + #mainDiv { + display: block + } + + #graphDiv { + width: 100%; + } + + #settings_div { + width: 100%; + display: block + } + + #tableDiv { + width: 100% + } + + #shareDiv { + width: 100% + } + + #secondaryDiv { + display: block + } +} \ No newline at end of file diff --git a/public/styles/edit_graph.css b/public/styles/edit_graph.css deleted file mode 100755 index ea84d9d..0000000 --- a/public/styles/edit_graph.css +++ /dev/null @@ -1,53 +0,0 @@ -main { - display: block; -} - -#mainDiv { - width: 100%; - display: flex; - padding: 10px; -} - -#graphDiv { - width: 75%; - height: 450px; -} - -#settings_div { - text-align: center; - width: 25%; -} - -#tableDiv { - padding: 0; - overflow: auto; - flex-basis: 75%; -} - -#shareDiv { - padding: 5px; - flex-basis: 25%; - margin-left: 5px; -} - -#secondaryDiv { - display: flex; -} - -#shareUsername { - width: 100px; - height: 35px; -} - -#shareHeader { - text-align: center; -} - -@media (max-width: 950px) { - #mainDiv {display: block} - #graphDiv {width: 100%;} - #settings_div {width: 100%; display: block} - #tableDiv {width: 100%} - #shareDiv {width: 100%} - #secondaryDiv {display: block} -} \ No newline at end of file diff --git a/src/Controller/ChartController.php b/src/Controller/ChartController.php new file mode 100644 index 0000000..15738e8 --- /dev/null +++ b/src/Controller/ChartController.php @@ -0,0 +1,56 @@ +createForm(RegistrationType::class, new Registration()); + + return $this->render('.html.twig', []); + }*/ + + #[Route('/charts/{id}', name: 'edit_chart', requirements: ['id' => '\d+'])] + public function editAction(DocumentManager $dm, Request $request, int $id) + { + $chart = ($id !== null) ? $this->findOrFail($dm, $id) : new Chart(); + + $form = $this->createForm(ChartType::class, $chart); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $chart = $form->getData(); + + $dm->persist($chart); + $dm->flush(); + + //return $this->redirect('/'); + } + + return $this->render('edit.html.twig', [ + 'form' => $form->createView() + ]); + } + + private function findOrFail(DocumentManager $dm, int $id): Chart + { + $chart = $dm->getRepository(Chart::class)->findOneBy(['code' => $id]); + //$chart = $dm->getRepository(Chart::class)->findAll(); + if ($chart === null) { + throw $this->createNotFoundException(); + } + + return $chart; + } +} diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 9acf7c6..192fb7c 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -2,8 +2,8 @@ namespace App\Controller; -use App\Form\Model\Registration; -use App\Form\Type\RegistrationType; +use App\Document\User; +use App\Form\Type\UserType; use Doctrine\ODM\MongoDB\DocumentManager; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; @@ -16,7 +16,7 @@ class UserController extends AbstractController #[Route('/register', name: 'register')] public function registerAction(): Response { - $form = $this->createForm(RegistrationType::class, new Registration()); + $form = $this->createForm(UserType::class, new User()); return $this->render('register.html.twig', [ 'form' => $form->createView() @@ -26,14 +26,14 @@ class UserController extends AbstractController #[Route('/create', name: 'create')] public function createAction(DocumentManager $dm, Request $request) { - $form = $this->createForm(RegistrationType::class, new Registration()); + $form = $this->createForm(UserType::class, new User()); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $registration = $form->getData(); + $user = $form->getData(); - $dm->persist($registration->getUser()); + $dm->persist($user); $dm->flush(); return $this->redirect('/'); @@ -43,4 +43,4 @@ class UserController extends AbstractController 'form' => $form->createView() ]); } - } \ No newline at end of file +} diff --git a/src/Document/Chart.php b/src/Document/Chart.php index c920299..86eea11 100644 --- a/src/Document/Chart.php +++ b/src/Document/Chart.php @@ -24,16 +24,20 @@ class Chart #[Assert\NotBlank] protected ?string $code = null; - #[MongoDB\Field(type: 'object')] + #[MongoDB\Field(type: 'raw')] #[Assert\NotBlank] - protected ?string $metadata = null; + protected $metadata = null; + + #[MongoDB\Field(type: 'hash')] + //#[Assert\NotBlank] + protected ?array $table = null; public function getId(): string { return $this->id; } - public function getNamel(): ?string + public function getName(): ?string { return $this->name; } @@ -53,13 +57,28 @@ class Chart $this->code = $code; } - public function getMetadata(): ?string + public function getMetadata() { return $this->metadata; } - public function setMetadata(?string $metadata): void + public function setMetadata($metadata): void { $this->metadata = $metadata; } + + public function getTable(): ?array + { + /*$decoded = []; + foreach ($this->table as $key => $value) { + $decoded += json_decode($value); + } + return $decoded;*/ + return $this->table; + } + + public function setTable(?array $table): void + { + $this->table = $table; + } } \ No newline at end of file diff --git a/src/Form/Model/Registration.php b/src/Form/Model/Registration.php deleted file mode 100644 index 5eb5923..0000000 --- a/src/Form/Model/Registration.php +++ /dev/null @@ -1,41 +0,0 @@ -user = $user; - } - - public function getUser() - { - return $this->user; - } - - public function getTermsAccepted() - { - return $this->termsAccepted; - } - - public function setTermsAccepted($termsAccepted) - { - $this->termsAccepted = (bool) $termsAccepted; - } -} \ No newline at end of file diff --git a/src/Form/Type/CellType.php b/src/Form/Type/CellType.php new file mode 100644 index 0000000..145c5c9 --- /dev/null +++ b/src/Form/Type/CellType.php @@ -0,0 +1,14 @@ +add('name', TextType::class) + ->add('code', TextType::class) + ->add('metadata', MetadataType::class) + ->add('table', CollectionType::class, [ + 'entry_type' => ColumnType::class, + 'allow_add' => true, + /*'prototype' => true, + 'prototype_data' => 'Placeholder'*/ + ]); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Chart::class, + ]); + } +} \ No newline at end of file diff --git a/src/Form/Type/ColumnType.php b/src/Form/Type/ColumnType.php new file mode 100644 index 0000000..94813cb --- /dev/null +++ b/src/Form/Type/ColumnType.php @@ -0,0 +1,36 @@ +add('col_name', TextType::class, [ + 'label' => false, + ]) + ->add('values', CollectionType::class, [ + 'entry_type' => TextType::class, + 'allow_add' => true, + 'prototype' => true, + 'prototype_data' => 'Placeholder', + 'entry_options' => [ + 'label' => false, + ] + ]); + } + + /*public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Chart::class, + ]); + }*/ +} \ No newline at end of file diff --git a/src/Form/Type/MetadataType.php b/src/Form/Type/MetadataType.php new file mode 100644 index 0000000..8be500e --- /dev/null +++ b/src/Form/Type/MetadataType.php @@ -0,0 +1,68 @@ +add('type', ChoiceType::class, [ + 'choices' => [ + 'Point' => 'point', + 'Line' => 'line', + 'Area' => 'area', + 'Pie' => 'pie', + 'Bar' => 'bar', + 'Stacked' => 'stacked', + ], + 'label' => 'Chart type', + ]) + ->add('margin', NumberType::class, [ + 'label' => 'Margin', + 'required' => false, + ]) + ->add('xLabel', TextType::class, [ + 'label' => 'X label', + 'required' => false, + ]) + ->add('yLabel', TextType::class, [ + 'label' => 'Y label', + 'required' => false, + ]) + ->add('displayLegend', CheckboxType::class, [ + 'label' => 'Display legend', + 'required' => false, + ]) + ->add('displayPoints', CheckboxType::class, [ + 'label' => 'Display points', + 'required' => false, + ]) + ->add('displaySupport', CheckboxType::class, [ + 'label' => 'Display support lines', + 'required' => false, + ]) + ->add('backgroundColor', ColorType::class, [ + 'label' => 'Background color', + 'required' => false, + ]) + ->add('submit', SubmitType::class, ['label' => 'Provést']); + } + + /*public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => User::class, + ]); + }*/ +} \ No newline at end of file diff --git a/src/Form/Type/RegistrationType.php b/src/Form/Type/RegistrationType.php deleted file mode 100644 index 1bb965e..0000000 --- a/src/Form/Type/RegistrationType.php +++ /dev/null @@ -1,17 +0,0 @@ -add('user', UserType::class); - $builder->add('terms', CheckboxType::class, ['property_path' => 'termsAccepted']); - } -} \ No newline at end of file diff --git a/src/Repository/ChartRepository.php b/src/Repository/ChartRepository.php index 0430061..a185d8f 100644 --- a/src/Repository/ChartRepository.php +++ b/src/Repository/ChartRepository.php @@ -2,7 +2,7 @@ namespace App\Repository; -use App\Entity\Chart; +use App\Document\Chart; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index 3767526..34f21b6 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -2,7 +2,7 @@ namespace App\Repository; -use App\Entity\User; +use App\Document\User; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; diff --git a/templates/edit.html.twig b/templates/edit.html.twig new file mode 100644 index 0000000..a1e990e --- /dev/null +++ b/templates/edit.html.twig @@ -0,0 +1,75 @@ +{% extends 'base.html.twig' %} + +{% block stylesheets %} + {{ parent() }} + + +{% endblock %} + +{% block javascripts %} + {{ parent() }} + +{% endblock %} + +{% block title %} + Edit chart +{% endblock %} + +{% block body %} +
+
+
+ +
+
+
+ + {{ form_start(form) }} +
+ {{ form_row(form.metadata) }} + + +
+ +
+ + +
+ +
+
+ + + {% for col in form.table %} + + {% endfor %} + + {% for i in 0..form.table[0].values|length-1 %} + + {% for col in form.table %} + + {% endfor %} + + {% endfor %} +
{{ form_row(col.col_name) }}
{{ form_row(col.values[i]) }}
+
+ {{ form_end(form) }} +
+
+ +
+
+{% endblock %} diff --git a/templates/header.html.twig b/templates/header.html.twig index 4199d18..25d47b7 100644 --- a/templates/header.html.twig +++ b/templates/header.html.twig @@ -1,11 +1,11 @@
- Login + Login
diff --git a/templates/login.html.twig b/templates/login.html.twig new file mode 100644 index 0000000..83699c4 --- /dev/null +++ b/templates/login.html.twig @@ -0,0 +1,13 @@ +{% extends 'base.html.twig' %} + +{% block title %} + Login +{% endblock %} + +{% block body %} +
+
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/register.html.twig b/templates/register.html.twig index 58b6242..d5897ce 100644 --- a/templates/register.html.twig +++ b/templates/register.html.twig @@ -1,6 +1,17 @@ -{# templates/egister.html.twig #} -{{ form_start(form, {'action': path('create'), 'method': 'POST'}) }} - {{ form_widget(form) }} +{% extends 'base.html.twig' %} - -{{ form_end(form) }} \ No newline at end of file +{% block title %} + Register +{% endblock %} + +{% block body %} +
+
+ {{ form_start(form, {'action': path('create'), 'method': 'POST'}) }} + {{ form_widget(form) }} + + + {{ form_end(form) }} +
+
+{% endblock %} diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index f67f922..5c123e0 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -7,8 +7,12 @@ $baseDir = dirname($vendorDir); return array( 'App\\Controller\\IndexController' => $baseDir . '/src/Controller/IndexController.php', - 'App\\Entity\\Chart' => $baseDir . '/src/Entity/Chart.php', - 'App\\Entity\\User' => $baseDir . '/src/Entity/User.php', + 'App\\Controller\\UserController' => $baseDir . '/src/Controller/UserController.php', + 'App\\Document\\Chart' => $baseDir . '/src/Document/Chart.php', + 'App\\Document\\User' => $baseDir . '/src/Document/User.php', + 'App\\Form\\Model\\Registration' => $baseDir . '/src/Form/Model/Registration.php', + 'App\\Form\\Type\\RegistrationType' => $baseDir . '/src/Form/Type/RegistrationType.php', + 'App\\Form\\Type\\UserType' => $baseDir . '/src/Form/Type/UserType.php', 'App\\Kernel' => $baseDir . '/src/Kernel.php', 'App\\Repository\\ChartRepository' => $baseDir . '/src/Repository/ChartRepository.php', 'App\\Repository\\UserRepository' => $baseDir . '/src/Repository/UserRepository.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 4ffffc4..051384e 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -597,8 +597,12 @@ class ComposerStaticInit4fe506277082b063a84f05968212cec8 public static $classMap = array ( 'App\\Controller\\IndexController' => __DIR__ . '/../..' . '/src/Controller/IndexController.php', - 'App\\Entity\\Chart' => __DIR__ . '/../..' . '/src/Entity/Chart.php', - 'App\\Entity\\User' => __DIR__ . '/../..' . '/src/Entity/User.php', + 'App\\Controller\\UserController' => __DIR__ . '/../..' . '/src/Controller/UserController.php', + 'App\\Document\\Chart' => __DIR__ . '/../..' . '/src/Document/Chart.php', + 'App\\Document\\User' => __DIR__ . '/../..' . '/src/Document/User.php', + 'App\\Form\\Model\\Registration' => __DIR__ . '/../..' . '/src/Form/Model/Registration.php', + 'App\\Form\\Type\\RegistrationType' => __DIR__ . '/../..' . '/src/Form/Type/RegistrationType.php', + 'App\\Form\\Type\\UserType' => __DIR__ . '/../..' . '/src/Form/Type/UserType.php', 'App\\Kernel' => __DIR__ . '/../..' . '/src/Kernel.php', 'App\\Repository\\ChartRepository' => __DIR__ . '/../..' . '/src/Repository/ChartRepository.php', 'App\\Repository\\UserRepository' => __DIR__ . '/../..' . '/src/Repository/UserRepository.php',