From 8f899c6c89d76d250869ed334b7042c28104836c Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 19 May 2025 11:21:45 -0400 Subject: [PATCH] Initial commit --- add_dataset.php | 42 + create_table.php | 29 + db.php | 17 + delete_dataset.php | 31 + delete_table.php | 25 + edit.php | 66 + fetchData.php | 45 + gestor_dataset.php | 118 + includes/footer.php | 7 + includes/header.php | 31 + index.php | 60 + save_dataset.php | 30 + scripts/dtaTables.css | 817 ++ scripts/dtaTables.js | 14047 ++++++++++++++++++++++++++++++++ scripts/jquery.js | 10716 ++++++++++++++++++++++++ scripts/server_processing.php | 64 + scripts/ssp.class.php | 557 ++ server_side/index.php | 83 + server_side/server_side.php | 69 + server_side/ssp.class.php | 554 ++ test_connection.php | 35 + 21 files changed, 27443 insertions(+) create mode 100644 add_dataset.php create mode 100644 create_table.php create mode 100755 db.php create mode 100755 delete_dataset.php create mode 100644 delete_table.php create mode 100755 edit.php create mode 100644 fetchData.php create mode 100644 gestor_dataset.php create mode 100755 includes/footer.php create mode 100755 includes/header.php create mode 100755 index.php create mode 100755 save_dataset.php create mode 100644 scripts/dtaTables.css create mode 100644 scripts/dtaTables.js create mode 100644 scripts/jquery.js create mode 100644 scripts/server_processing.php create mode 100644 scripts/ssp.class.php create mode 100644 server_side/index.php create mode 100644 server_side/server_side.php create mode 100644 server_side/ssp.class.php create mode 100755 test_connection.php diff --git a/add_dataset.php b/add_dataset.php new file mode 100644 index 0000000..f50fdc6 --- /dev/null +++ b/add_dataset.php @@ -0,0 +1,42 @@ + + + + + +
+
+
+
+
Agregar Dataset a la tabla:
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/create_table.php b/create_table.php new file mode 100644 index 0000000..46b2403 --- /dev/null +++ b/create_table.php @@ -0,0 +1,29 @@ +alert('Tabla creada exitosamente.'); window.location.href = 'index.php';"; + } else { + die("Error al crear la tabla: " . mysqli_error($conn)); + } +} diff --git a/db.php b/db.php new file mode 100755 index 0000000..794a2b3 --- /dev/null +++ b/db.php @@ -0,0 +1,17 @@ + + diff --git a/delete_dataset.php b/delete_dataset.php new file mode 100755 index 0000000..b1350ce --- /dev/null +++ b/delete_dataset.php @@ -0,0 +1,31 @@ +alert('Registro eliminado exitosamente.'); window.location.href = 'gestor_dataset.php?table=$table_name';"; +} else { + die("Error al eliminar el registro: " . mysqli_error($conn)); +} diff --git a/delete_table.php b/delete_table.php new file mode 100644 index 0000000..6061e8c --- /dev/null +++ b/delete_table.php @@ -0,0 +1,25 @@ +alert('Tabla eliminada exitosamente.'); window.location.href = 'index.php';"; +} else { + die("Error al eliminar la tabla: " . mysqli_error($conn)); +} diff --git a/edit.php b/edit.php new file mode 100755 index 0000000..e509c93 --- /dev/null +++ b/edit.php @@ -0,0 +1,66 @@ + + + + +
+
+
+
+
+
+ +
+
+ +
+
+ +
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/fetchData.php b/fetchData.php new file mode 100644 index 0000000..3300da2 --- /dev/null +++ b/fetchData.php @@ -0,0 +1,45 @@ + 'localhost', + 'user' => 'root', + 'pass' => 'XmRTSMQ9', + 'db' => 'php_crud' +); + + +$table = 'general'; + +$primaryKey = 'id'; + + +$columns = array( + array('db' => 'id', 'dt' => 0), + array('db' => 'instruction', 'dt' => 1), + array('db' => 'input', 'dt' => 2), + array('db' => 'output', 'dt' => 3), + array( + 'db' => 'created_at', + 'dt' => 4, + 'formatter' => function ($d, $row) { + return date('js M Y', strtotime($d)); + } + ), + array( + 'db' => 'id', + 'dt' => 5, + 'formatter' => function ($d, $row) { + return 'Editar + Eliminar'; + } + ) +); + + +require('ssp.class.php'); + + +// Output data as json format +echo json_encode( + SSP::simple($_GET, $dbDetails, $table, $primaryKey, $columns) +); diff --git a/gestor_dataset.php b/gestor_dataset.php new file mode 100644 index 0000000..69fb188 --- /dev/null +++ b/gestor_dataset.php @@ -0,0 +1,118 @@ + + + + + + + +
+
+ + + + +
+
Datos en la tabla:
+ + + + + + + + + + + + + + + + + + + + + + +
InstructionInputOutputCreated AtActions
+ + Editar + + + Eliminar + +
+ + +
+ +
+
+
+
+ + \ No newline at end of file diff --git a/includes/footer.php b/includes/footer.php new file mode 100755 index 0000000..efc4ef8 --- /dev/null +++ b/includes/footer.php @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/includes/header.php b/includes/header.php new file mode 100755 index 0000000..e6dabb2 --- /dev/null +++ b/includes/header.php @@ -0,0 +1,31 @@ + + + + + + + GESTOR DATASET + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.php b/index.php new file mode 100755 index 0000000..aeaf5a2 --- /dev/null +++ b/index.php @@ -0,0 +1,60 @@ + + + +
+
+ +
+
Tablas Existentes
+ + + + + + + + + + + + + + + +
Nombre de la TablaAcciones
+ + + Editar + + + + Eliminar + +
+
+ + +
+
+
Crear Tabla
+
+
+ +
+
+ +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/save_dataset.php b/save_dataset.php new file mode 100755 index 0000000..dc18940 --- /dev/null +++ b/save_dataset.php @@ -0,0 +1,30 @@ +alert('Dataset guardado exitosamente.'); window.location.href = 'gestor_dataset.php?table=$table_name';"; +} diff --git a/scripts/dtaTables.css b/scripts/dtaTables.css new file mode 100644 index 0000000..63b7148 --- /dev/null +++ b/scripts/dtaTables.css @@ -0,0 +1,817 @@ +:root { + --dt-row-selected: 13, 110, 253; + --dt-row-selected-text: 255, 255, 255; + --dt-row-selected-link: 9, 10, 11; + --dt-row-stripe: 0, 0, 0; + --dt-row-hover: 0, 0, 0; + --dt-column-ordering: 0, 0, 0; + --dt-html-background: white; + } + :root.dark { + --dt-html-background: rgb(33, 37, 41); + } + + table.dataTable td.dt-control { + text-align: center; + cursor: pointer; + } + table.dataTable td.dt-control:before { + display: inline-block; + box-sizing: border-box; + content: ""; + border-top: 5px solid transparent; + border-left: 10px solid rgba(0, 0, 0, 0.5); + border-bottom: 5px solid transparent; + border-right: 0px solid transparent; + } + table.dataTable tr.dt-hasChild td.dt-control:before { + border-top: 10px solid rgba(0, 0, 0, 0.5); + border-left: 5px solid transparent; + border-bottom: 0px solid transparent; + border-right: 5px solid transparent; + } + table.dataTable tfoot:empty { + display: none; + } + + html.dark table.dataTable td.dt-control:before, + :root[data-bs-theme=dark] table.dataTable td.dt-control:before, + :root[data-theme=dark] table.dataTable td.dt-control:before { + border-left-color: rgba(255, 255, 255, 0.5); + } + html.dark table.dataTable tr.dt-hasChild td.dt-control:before, + :root[data-bs-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before, + :root[data-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before { + border-top-color: rgba(255, 255, 255, 0.5); + border-left-color: transparent; + } + + div.dt-scroll { + width: 100%; + } + + div.dt-scroll-body thead tr, + div.dt-scroll-body tfoot tr { + height: 0; + } + div.dt-scroll-body thead tr th, div.dt-scroll-body thead tr td, + div.dt-scroll-body tfoot tr th, + div.dt-scroll-body tfoot tr td { + height: 0 !important; + padding-top: 0px !important; + padding-bottom: 0px !important; + border-top-width: 0px !important; + border-bottom-width: 0px !important; + } + div.dt-scroll-body thead tr th div.dt-scroll-sizing, div.dt-scroll-body thead tr td div.dt-scroll-sizing, + div.dt-scroll-body tfoot tr th div.dt-scroll-sizing, + div.dt-scroll-body tfoot tr td div.dt-scroll-sizing { + height: 0 !important; + overflow: hidden !important; + } + + table.dataTable thead > tr > th:active, + table.dataTable thead > tr > td:active { + outline: none; + } + table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, + table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before, + table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before { + position: absolute; + display: block; + bottom: 50%; + content: "\25B2"; + content: "\25B2"/""; + } + table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after, + table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:after, + table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after { + position: absolute; + display: block; + top: 50%; + content: "\25BC"; + content: "\25BC"/""; + } + table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order, + table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order, + table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order, + table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order, + table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order { + position: relative; + width: 12px; + height: 20px; + } + table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after, + table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before, + table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:after, + table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:before, + table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:after, + table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before, + table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:after, + table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:before, + table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after { + left: 0; + opacity: 0.125; + line-height: 9px; + font-size: 0.8em; + } + table.dataTable thead > tr > th.dt-orderable-asc, table.dataTable thead > tr > th.dt-orderable-desc, + table.dataTable thead > tr > td.dt-orderable-asc, + table.dataTable thead > tr > td.dt-orderable-desc { + cursor: pointer; + } + table.dataTable thead > tr > th.dt-orderable-asc:hover, table.dataTable thead > tr > th.dt-orderable-desc:hover, + table.dataTable thead > tr > td.dt-orderable-asc:hover, + table.dataTable thead > tr > td.dt-orderable-desc:hover { + outline: 2px solid rgba(0, 0, 0, 0.05); + outline-offset: -2px; + } + table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after, + table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before, + table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after { + opacity: 0.6; + } + table.dataTable thead > tr > th.sorting_desc_disabled span.dt-column-order:after, table.dataTable thead > tr > th.sorting_asc_disabled span.dt-column-order:before, + table.dataTable thead > tr > td.sorting_desc_disabled span.dt-column-order:after, + table.dataTable thead > tr > td.sorting_asc_disabled span.dt-column-order:before { + display: none; + } + table.dataTable thead > tr > th:active, + table.dataTable thead > tr > td:active { + outline: none; + } + + table.dataTable thead > tr > th div.dt-column-header, + table.dataTable thead > tr > th div.dt-column-footer, + table.dataTable thead > tr > td div.dt-column-header, + table.dataTable thead > tr > td div.dt-column-footer, + table.dataTable tfoot > tr > th div.dt-column-header, + table.dataTable tfoot > tr > th div.dt-column-footer, + table.dataTable tfoot > tr > td div.dt-column-header, + table.dataTable tfoot > tr > td div.dt-column-footer { + display: flex; + justify-content: space-between; + align-items: center; + gap: 4px; + } + table.dataTable thead > tr > th div.dt-column-header span.dt-column-title, + table.dataTable thead > tr > th div.dt-column-footer span.dt-column-title, + table.dataTable thead > tr > td div.dt-column-header span.dt-column-title, + table.dataTable thead > tr > td div.dt-column-footer span.dt-column-title, + table.dataTable tfoot > tr > th div.dt-column-header span.dt-column-title, + table.dataTable tfoot > tr > th div.dt-column-footer span.dt-column-title, + table.dataTable tfoot > tr > td div.dt-column-header span.dt-column-title, + table.dataTable tfoot > tr > td div.dt-column-footer span.dt-column-title { + flex-grow: 1; + } + table.dataTable thead > tr > th div.dt-column-header span.dt-column-title:empty, + table.dataTable thead > tr > th div.dt-column-footer span.dt-column-title:empty, + table.dataTable thead > tr > td div.dt-column-header span.dt-column-title:empty, + table.dataTable thead > tr > td div.dt-column-footer span.dt-column-title:empty, + table.dataTable tfoot > tr > th div.dt-column-header span.dt-column-title:empty, + table.dataTable tfoot > tr > th div.dt-column-footer span.dt-column-title:empty, + table.dataTable tfoot > tr > td div.dt-column-header span.dt-column-title:empty, + table.dataTable tfoot > tr > td div.dt-column-footer span.dt-column-title:empty { + display: none; + } + + div.dt-scroll-body > table.dataTable > thead > tr > th, + div.dt-scroll-body > table.dataTable > thead > tr > td { + overflow: hidden; + } + + :root.dark table.dataTable thead > tr > th.dt-orderable-asc:hover, :root.dark table.dataTable thead > tr > th.dt-orderable-desc:hover, + :root.dark table.dataTable thead > tr > td.dt-orderable-asc:hover, + :root.dark table.dataTable thead > tr > td.dt-orderable-desc:hover, + :root[data-bs-theme=dark] table.dataTable thead > tr > th.dt-orderable-asc:hover, + :root[data-bs-theme=dark] table.dataTable thead > tr > th.dt-orderable-desc:hover, + :root[data-bs-theme=dark] table.dataTable thead > tr > td.dt-orderable-asc:hover, + :root[data-bs-theme=dark] table.dataTable thead > tr > td.dt-orderable-desc:hover { + outline: 2px solid rgba(255, 255, 255, 0.05); + } + + div.dt-processing { + position: absolute; + top: 50%; + left: 50%; + width: 200px; + margin-left: -100px; + margin-top: -22px; + text-align: center; + padding: 2px; + z-index: 10; + } + div.dt-processing > div:last-child { + position: relative; + width: 80px; + height: 15px; + margin: 1em auto; + } + div.dt-processing > div:last-child > div { + position: absolute; + top: 0; + width: 13px; + height: 13px; + border-radius: 50%; + background: rgb(13, 110, 253); + background: rgb(var(--dt-row-selected)); + animation-timing-function: cubic-bezier(0, 1, 1, 0); + } + div.dt-processing > div:last-child > div:nth-child(1) { + left: 8px; + animation: datatables-loader-1 0.6s infinite; + } + div.dt-processing > div:last-child > div:nth-child(2) { + left: 8px; + animation: datatables-loader-2 0.6s infinite; + } + div.dt-processing > div:last-child > div:nth-child(3) { + left: 32px; + animation: datatables-loader-2 0.6s infinite; + } + div.dt-processing > div:last-child > div:nth-child(4) { + left: 56px; + animation: datatables-loader-3 0.6s infinite; + } + + @keyframes datatables-loader-1 { + 0% { + transform: scale(0); + } + 100% { + transform: scale(1); + } + } + @keyframes datatables-loader-3 { + 0% { + transform: scale(1); + } + 100% { + transform: scale(0); + } + } + @keyframes datatables-loader-2 { + 0% { + transform: translate(0, 0); + } + 100% { + transform: translate(24px, 0); + } + } + table.dataTable.nowrap th, table.dataTable.nowrap td { + white-space: nowrap; + } + table.dataTable th, + table.dataTable td { + box-sizing: border-box; + } + table.dataTable th.dt-type-numeric, table.dataTable th.dt-type-date, + table.dataTable td.dt-type-numeric, + table.dataTable td.dt-type-date { + text-align: right; + } + table.dataTable th.dt-type-numeric div.dt-column-header, + table.dataTable th.dt-type-numeric div.dt-column-footer, table.dataTable th.dt-type-date div.dt-column-header, + table.dataTable th.dt-type-date div.dt-column-footer, + table.dataTable td.dt-type-numeric div.dt-column-header, + table.dataTable td.dt-type-numeric div.dt-column-footer, + table.dataTable td.dt-type-date div.dt-column-header, + table.dataTable td.dt-type-date div.dt-column-footer { + flex-direction: row-reverse; + } + table.dataTable th.dt-left, + table.dataTable td.dt-left { + text-align: left; + } + table.dataTable th.dt-center, + table.dataTable td.dt-center { + text-align: center; + } + table.dataTable th.dt-right, + table.dataTable td.dt-right { + text-align: right; + } + table.dataTable th.dt-right div.dt-column-header, + table.dataTable th.dt-right div.dt-column-footer, + table.dataTable td.dt-right div.dt-column-header, + table.dataTable td.dt-right div.dt-column-footer { + flex-direction: row-reverse; + } + table.dataTable th.dt-justify, + table.dataTable td.dt-justify { + text-align: justify; + } + table.dataTable th.dt-nowrap, + table.dataTable td.dt-nowrap { + white-space: nowrap; + } + table.dataTable th.dt-empty, + table.dataTable td.dt-empty { + text-align: center; + vertical-align: top; + } + table.dataTable thead th, + table.dataTable thead td, + table.dataTable tfoot th, + table.dataTable tfoot td { + text-align: left; + } + table.dataTable thead th.dt-head-left, + table.dataTable thead td.dt-head-left, + table.dataTable tfoot th.dt-head-left, + table.dataTable tfoot td.dt-head-left { + text-align: left; + } + table.dataTable thead th.dt-head-center, + table.dataTable thead td.dt-head-center, + table.dataTable tfoot th.dt-head-center, + table.dataTable tfoot td.dt-head-center { + text-align: center; + } + table.dataTable thead th.dt-head-right, + table.dataTable thead td.dt-head-right, + table.dataTable tfoot th.dt-head-right, + table.dataTable tfoot td.dt-head-right { + text-align: right; + } + table.dataTable thead th.dt-head-right div.dt-column-header, + table.dataTable thead th.dt-head-right div.dt-column-footer, + table.dataTable thead td.dt-head-right div.dt-column-header, + table.dataTable thead td.dt-head-right div.dt-column-footer, + table.dataTable tfoot th.dt-head-right div.dt-column-header, + table.dataTable tfoot th.dt-head-right div.dt-column-footer, + table.dataTable tfoot td.dt-head-right div.dt-column-header, + table.dataTable tfoot td.dt-head-right div.dt-column-footer { + flex-direction: row-reverse; + } + table.dataTable thead th.dt-head-justify, + table.dataTable thead td.dt-head-justify, + table.dataTable tfoot th.dt-head-justify, + table.dataTable tfoot td.dt-head-justify { + text-align: justify; + } + table.dataTable thead th.dt-head-nowrap, + table.dataTable thead td.dt-head-nowrap, + table.dataTable tfoot th.dt-head-nowrap, + table.dataTable tfoot td.dt-head-nowrap { + white-space: nowrap; + } + table.dataTable tbody th.dt-body-left, + table.dataTable tbody td.dt-body-left { + text-align: left; + } + table.dataTable tbody th.dt-body-center, + table.dataTable tbody td.dt-body-center { + text-align: center; + } + table.dataTable tbody th.dt-body-right, + table.dataTable tbody td.dt-body-right { + text-align: right; + } + table.dataTable tbody th.dt-body-justify, + table.dataTable tbody td.dt-body-justify { + text-align: justify; + } + table.dataTable tbody th.dt-body-nowrap, + table.dataTable tbody td.dt-body-nowrap { + white-space: nowrap; + } + + :root { + --dt-row-hover-alpha: 0.035; + --dt-row-stripe-alpha: 0.023; + --dt-column-ordering-alpha: 0.019; + --dt-row-selected-stripe-alpha: 0.923; + --dt-row-selected-column-ordering-alpha: 0.919; + } + + /* + * Table styles + */ + table.dataTable { + width: 100%; + margin: 0 auto; + border-spacing: 0; + /* + * Header and footer styles + */ + /* + * Body styles + */ + } + table.dataTable thead th, + table.dataTable tfoot th { + font-weight: bold; + } + table.dataTable > thead > tr > th, + table.dataTable > thead > tr > td { + padding: 10px; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + } + table.dataTable > thead > tr > th:active, + table.dataTable > thead > tr > td:active { + outline: none; + } + table.dataTable > tfoot > tr > th, + table.dataTable > tfoot > tr > td { + border-top: 1px solid rgba(0, 0, 0, 0.3); + padding: 10px 10px 6px 10px; + } + table.dataTable > tbody > tr { + background-color: transparent; + } + table.dataTable > tbody > tr:first-child > * { + border-top: none; + } + table.dataTable > tbody > tr:last-child > * { + border-bottom: none; + } + table.dataTable > tbody > tr.selected > * { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.9); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.9); + color: rgb(255, 255, 255); + color: rgb(var(--dt-row-selected-text)); + } + table.dataTable > tbody > tr.selected a { + color: rgb(9, 10, 11); + color: rgb(var(--dt-row-selected-link)); + } + table.dataTable > tbody > tr > th, + table.dataTable > tbody > tr > td { + padding: 8px 10px; + } + table.dataTable.row-border > tbody > tr > *, table.dataTable.display > tbody > tr > * { + border-top: 1px solid rgba(0, 0, 0, 0.15); + } + table.dataTable.row-border > tbody > tr:first-child > *, table.dataTable.display > tbody > tr:first-child > * { + border-top: none; + } + table.dataTable.row-border > tbody > tr.selected + tr.selected > td, table.dataTable.display > tbody > tr.selected + tr.selected > td { + border-top-color: rgba(13, 110, 253, 0.65); + border-top-color: rgba(var(--dt-row-selected), 0.65); + } + table.dataTable.cell-border > tbody > tr > * { + border-top: 1px solid rgba(0, 0, 0, 0.15); + border-right: 1px solid rgba(0, 0, 0, 0.15); + } + table.dataTable.cell-border > tbody > tr > *:first-child { + border-left: 1px solid rgba(0, 0, 0, 0.15); + } + table.dataTable.cell-border > tbody > tr:first-child > * { + border-top: 1px solid rgba(0, 0, 0, 0.3); + } + table.dataTable.stripe > tbody > tr:nth-child(odd) > *, table.dataTable.display > tbody > tr:nth-child(odd) > * { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.023); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-stripe), var(--dt-row-stripe-alpha)); + } + table.dataTable.stripe > tbody > tr:nth-child(odd).selected > *, table.dataTable.display > tbody > tr:nth-child(odd).selected > * { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.923); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), var(--dt-row-selected-stripe-alpha)); + } + table.dataTable.hover > tbody > tr:hover > *, table.dataTable.display > tbody > tr:hover > * { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.035); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), var(--dt-row-hover-alpha)); + } + table.dataTable.hover > tbody > tr.selected:hover > *, table.dataTable.display > tbody > tr.selected:hover > * { + box-shadow: inset 0 0 0 9999px #0d6efd !important; + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 1) !important; + } + table.dataTable.order-column > tbody tr > .sorting_1, + table.dataTable.order-column > tbody tr > .sorting_2, + table.dataTable.order-column > tbody tr > .sorting_3, table.dataTable.display > tbody tr > .sorting_1, + table.dataTable.display > tbody tr > .sorting_2, + table.dataTable.display > tbody tr > .sorting_3 { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.019); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), var(--dt-column-ordering-alpha)); + } + table.dataTable.order-column > tbody tr.selected > .sorting_1, + table.dataTable.order-column > tbody tr.selected > .sorting_2, + table.dataTable.order-column > tbody tr.selected > .sorting_3, table.dataTable.display > tbody tr.selected > .sorting_1, + table.dataTable.display > tbody tr.selected > .sorting_2, + table.dataTable.display > tbody tr.selected > .sorting_3 { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.919); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), var(--dt-row-selected-column-ordering-alpha)); + } + table.dataTable.display > tbody > tr:nth-child(odd) > .sorting_1, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd) > .sorting_1 { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.054); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), calc(var(--dt-row-stripe-alpha) + var(--dt-column-ordering-alpha))); + } + table.dataTable.display > tbody > tr:nth-child(odd) > .sorting_2, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd) > .sorting_2 { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.047); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), calc(var(--dt-row-stripe-alpha) + var(--dt-column-ordering-alpha) - 0.007)); + } + table.dataTable.display > tbody > tr:nth-child(odd) > .sorting_3, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd) > .sorting_3 { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.039); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), calc(var(--dt-row-stripe-alpha) + var(--dt-column-ordering-alpha) - 0.015)); + } + table.dataTable.display > tbody > tr:nth-child(odd).selected > .sorting_1, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd).selected > .sorting_1 { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.954); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), calc(var(--dt-row-selected-stripe-alpha) + var(--dt-column-ordering-alpha))); + } + table.dataTable.display > tbody > tr:nth-child(odd).selected > .sorting_2, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd).selected > .sorting_2 { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.947); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), calc(var(--dt-row-selected-stripe-alpha) + var(--dt-column-ordering-alpha) - 0.007)); + } + table.dataTable.display > tbody > tr:nth-child(odd).selected > .sorting_3, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd).selected > .sorting_3 { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.939); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), calc(var(--dt-row-selected-stripe-alpha) + var(--dt-column-ordering-alpha) - 0.015)); + } + table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.082); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), calc(var(--dt-row-stripe-alpha) + var(--dt-column-ordering-alpha) + var(--dt-row-hover-alpha))); + } + table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.074); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), calc(var(--dt-row-stripe-alpha) + var(--dt-column-ordering-alpha) + var(--dt-row-hover-alpha) - 0.007)); + } + table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 { + box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.062); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), calc(var(--dt-row-stripe-alpha) + var(--dt-column-ordering-alpha) + var(--dt-row-hover-alpha) - 0.015)); + } + table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.982); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), calc(var(--dt-row-selected-stripe-alpha) + var(--dt-column-ordering-alpha))); + } + table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.974); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), calc(var(--dt-row-selected-stripe-alpha) + var(--dt-column-ordering-alpha) + var(--dt-row-hover-alpha) - 0.007)); + } + table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 { + box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.962); + box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), calc(var(--dt-row-selected-stripe-alpha) + var(--dt-column-ordering-alpha) + var(--dt-row-hover-alpha) - 0.015)); + } + table.dataTable.compact thead th, + table.dataTable.compact thead td, + table.dataTable.compact tfoot th, + table.dataTable.compact tfoot td, + table.dataTable.compact tbody th, + table.dataTable.compact tbody td { + padding: 4px; + } + + div.dt-container div.dt-layout-row { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + margin: 0.75em 0; + } + div.dt-container div.dt-layout-row div.dt-layout-cell { + display: flex; + justify-content: space-between; + align-items: center; + } + div.dt-container div.dt-layout-row div.dt-layout-cell.dt-layout-start { + justify-content: flex-start; + margin-right: auto; + } + div.dt-container div.dt-layout-row div.dt-layout-cell.dt-layout-end { + justify-content: flex-end; + margin-left: auto; + } + div.dt-container div.dt-layout-row div.dt-layout-cell:empty { + display: none; + } + + @media screen and (max-width: 767px) { + div.dt-container div.dt-layout-row:not(.dt-layout-table) { + display: block; + } + div.dt-container div.dt-layout-row:not(.dt-layout-table) div.dt-layout-cell { + display: block; + text-align: center; + } + div.dt-container div.dt-layout-row:not(.dt-layout-table) div.dt-layout-cell > * { + margin: 0.5em 0; + } + div.dt-container div.dt-layout-row:not(.dt-layout-table) div.dt-layout-cell.dt-layout-start { + margin-right: 0; + } + div.dt-container div.dt-layout-row:not(.dt-layout-table) div.dt-layout-cell.dt-layout-end { + margin-left: 0; + } + } + div.dt-container div.dt-layout-start > *:not(:last-child) { + margin-right: 1em; + } + div.dt-container div.dt-layout-end > *:not(:first-child) { + margin-left: 1em; + } + div.dt-container div.dt-layout-full { + width: 100%; + } + div.dt-container div.dt-layout-full > *:only-child { + margin-left: auto; + margin-right: auto; + } + div.dt-container div.dt-layout-table > div { + display: block !important; + } + + @media screen and (max-width: 767px) { + div.dt-container div.dt-layout-start > *:not(:last-child) { + margin-right: 0; + } + div.dt-container div.dt-layout-end > *:not(:first-child) { + margin-left: 0; + } + } + /* + * Control feature layout + */ + div.dt-container { + position: relative; + clear: both; + } + div.dt-container .dt-search input { + border: 1px solid #aaa; + border-radius: 3px; + padding: 5px; + background-color: transparent; + color: inherit; + margin-left: 3px; + } + div.dt-container .dt-input { + border: 1px solid #aaa; + border-radius: 3px; + padding: 5px; + background-color: transparent; + color: inherit; + } + div.dt-container select.dt-input { + padding: 4px; + } + div.dt-container .dt-paging .dt-paging-button { + box-sizing: border-box; + display: inline-block; + min-width: 1.5em; + padding: 0.5em 1em; + margin-left: 2px; + text-align: center; + text-decoration: none !important; + cursor: pointer; + color: inherit !important; + border: 1px solid transparent; + border-radius: 2px; + background: transparent; + } + div.dt-container .dt-paging .dt-paging-button.current, div.dt-container .dt-paging .dt-paging-button.current:hover { + color: inherit !important; + border: 1px solid rgba(0, 0, 0, 0.3); + background-color: rgba(0, 0, 0, 0.05); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.05)), color-stop(100%, rgba(0, 0, 0, 0.05))); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* FF3.6+ */ + background: -ms-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* IE10+ */ + background: -o-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* Opera 11.10+ */ + background: linear-gradient(to bottom, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* W3C */ + } + div.dt-container .dt-paging .dt-paging-button.disabled, div.dt-container .dt-paging .dt-paging-button.disabled:hover, div.dt-container .dt-paging .dt-paging-button.disabled:active { + cursor: default; + color: rgba(0, 0, 0, 0.5) !important; + border: 1px solid transparent; + background: transparent; + box-shadow: none; + } + div.dt-container .dt-paging .dt-paging-button:hover { + color: white !important; + border: 1px solid #111; + background-color: #111; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #585858 0%, #111 100%); /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, #585858 0%, #111 100%); /* FF3.6+ */ + background: -ms-linear-gradient(top, #585858 0%, #111 100%); /* IE10+ */ + background: -o-linear-gradient(top, #585858 0%, #111 100%); /* Opera 11.10+ */ + background: linear-gradient(to bottom, #585858 0%, #111 100%); /* W3C */ + } + div.dt-container .dt-paging .dt-paging-button:active { + outline: none; + background-color: #0c0c0c; + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); /* Chrome10+,Safari5.1+ */ + background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); /* FF3.6+ */ + background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); /* IE10+ */ + background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); /* Opera 11.10+ */ + background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%); /* W3C */ + box-shadow: inset 0 0 3px #111; + } + div.dt-container .dt-paging .ellipsis { + padding: 0 1em; + } + div.dt-container .dt-length, + div.dt-container .dt-search, + div.dt-container .dt-info, + div.dt-container .dt-processing, + div.dt-container .dt-paging { + color: inherit; + } + div.dt-container .dataTables_scroll { + clear: both; + } + div.dt-container .dataTables_scroll div.dt-scroll-body { + -webkit-overflow-scrolling: touch; + } + div.dt-container .dataTables_scroll div.dt-scroll-body > table > thead > tr > th, div.dt-container .dataTables_scroll div.dt-scroll-body > table > thead > tr > td, div.dt-container .dataTables_scroll div.dt-scroll-body > table > tbody > tr > th, div.dt-container .dataTables_scroll div.dt-scroll-body > table > tbody > tr > td { + vertical-align: middle; + } + div.dt-container .dataTables_scroll div.dt-scroll-body > table > thead > tr > th > div.dataTables_sizing, + div.dt-container .dataTables_scroll div.dt-scroll-body > table > thead > tr > td > div.dataTables_sizing, div.dt-container .dataTables_scroll div.dt-scroll-body > table > tbody > tr > th > div.dataTables_sizing, + div.dt-container .dataTables_scroll div.dt-scroll-body > table > tbody > tr > td > div.dataTables_sizing { + height: 0; + overflow: hidden; + margin: 0 !important; + padding: 0 !important; + } + div.dt-container.dt-empty-footer tbody > tr:last-child > * { + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + } + div.dt-container.dt-empty-footer .dt-scroll-body { + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + } + div.dt-container.dt-empty-footer .dt-scroll-body tbody > tr:last-child > * { + border-bottom: none; + } + + html.dark { + --dt-row-hover: 255, 255, 255; + --dt-row-stripe: 255, 255, 255; + --dt-column-ordering: 255, 255, 255; + } + html.dark table.dataTable > thead > tr > th, + html.dark table.dataTable > thead > tr > td { + border-bottom: 1px solid rgb(89, 91, 94); + } + html.dark table.dataTable > thead > tr > th:active, + html.dark table.dataTable > thead > tr > td:active { + outline: none; + } + html.dark table.dataTable > tfoot > tr > th, + html.dark table.dataTable > tfoot > tr > td { + border-top: 1px solid rgb(89, 91, 94); + } + html.dark table.dataTable.row-border > tbody > tr > *, html.dark table.dataTable.display > tbody > tr > * { + border-top: 1px solid rgb(64, 67, 70); + } + html.dark table.dataTable.row-border > tbody > tr:first-child > *, html.dark table.dataTable.display > tbody > tr:first-child > * { + border-top: none; + } + html.dark table.dataTable.row-border > tbody > tr.selected + tr.selected > td, html.dark table.dataTable.display > tbody > tr.selected + tr.selected > td { + border-top-color: rgba(13, 110, 253, 0.65); + border-top-color: rgba(var(--dt-row-selected), 0.65); + } + html.dark table.dataTable.cell-border > tbody > tr > th, + html.dark table.dataTable.cell-border > tbody > tr > td { + border-top: 1px solid rgb(64, 67, 70); + border-right: 1px solid rgb(64, 67, 70); + } + html.dark table.dataTable.cell-border > tbody > tr > th:first-child, + html.dark table.dataTable.cell-border > tbody > tr > td:first-child { + border-left: 1px solid rgb(64, 67, 70); + } + html.dark .dt-container.dt-empty-footer table.dataTable { + border-bottom: 1px solid rgb(89, 91, 94); + } + html.dark .dt-container .dt-search input, + html.dark .dt-container .dt-length select { + border: 1px solid rgba(255, 255, 255, 0.2); + background-color: var(--dt-html-background); + } + html.dark .dt-container .dt-paging .dt-paging-button.current, html.dark .dt-container .dt-paging .dt-paging-button.current:hover { + border: 1px solid rgb(89, 91, 94); + background: rgba(255, 255, 255, 0.15); + } + html.dark .dt-container .dt-paging .dt-paging-button.disabled, html.dark .dt-container .dt-paging .dt-paging-button.disabled:hover, html.dark .dt-container .dt-paging .dt-paging-button.disabled:active { + color: #666 !important; + } + html.dark .dt-container .dt-paging .dt-paging-button:hover { + border: 1px solid rgb(53, 53, 53); + background: rgb(53, 53, 53); + } + html.dark .dt-container .dt-paging .dt-paging-button:active { + background: #3a3a3a; + } + + /* + * Overrides for RTL support + */ + *[dir=rtl] table.dataTable thead th, + *[dir=rtl] table.dataTable thead td, + *[dir=rtl] table.dataTable tfoot th, + *[dir=rtl] table.dataTable tfoot td { + text-align: right; + } + *[dir=rtl] table.dataTable th.dt-type-numeric, *[dir=rtl] table.dataTable th.dt-type-date, + *[dir=rtl] table.dataTable td.dt-type-numeric, + *[dir=rtl] table.dataTable td.dt-type-date { + text-align: left; + } + *[dir=rtl] div.dt-container div.dt-layout-cell.dt-start { + text-align: right; + } + *[dir=rtl] div.dt-container div.dt-layout-cell.dt-end { + text-align: left; + } + *[dir=rtl] div.dt-container div.dt-search input { + margin: 0 3px 0 0; + } + \ No newline at end of file diff --git a/scripts/dtaTables.js b/scripts/dtaTables.js new file mode 100644 index 0000000..0fc445e --- /dev/null +++ b/scripts/dtaTables.js @@ -0,0 +1,14047 @@ +/*! DataTables 2.3.0 + * © SpryMedia Ltd - datatables.net/license + */ + +(function( factory ) { + "use strict"; + + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + // jQuery's factory checks for a global window - if it isn't present then it + // returns a factory function that expects the window object + var jq = require('jquery'); + + if (typeof window === 'undefined') { + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = jq( root ); + } + + return factory( $, root, root.document ); + }; + } + else { + module.exports = factory( jq, window, window.document ); + } + } + else { + // Browser + window.DataTable = factory( jQuery, window, document ); + } +}(function( $, window, document ) { + "use strict"; + + + var DataTable = function ( selector, options ) + { + // Check if called with a window or jQuery object for DOM less applications + // This is for backwards compatibility + if (DataTable.factory(selector, options)) { + return DataTable; + } + + // When creating with `new`, create a new DataTable, returning the API instance + if (this instanceof DataTable) { + return $(selector).DataTable(options); + } + else { + // Argument switching + options = selector; + } + + var _that = this; + var emptyInit = options === undefined; + var len = this.length; + + if ( emptyInit ) { + options = {}; + } + + // Method to get DT API instance from jQuery object + this.api = function () + { + return new _Api( this ); + }; + + this.each(function() { + // For each initialisation we want to give it a clean initialisation + // object that can be bashed around + var o = {}; + var oInit = len > 1 ? // optimisation for single table case + _fnExtend( o, options, true ) : + options; + + + var i=0, iLen; + var sId = this.getAttribute( 'id' ); + var defaults = DataTable.defaults; + var $this = $(this); + + // Sanity check + if ( this.nodeName.toLowerCase() != 'table' ) + { + _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); + return; + } + + // Special case for options + if (oInit.on && oInit.on.options) { + _fnListener($this, 'options', oInit.on.options); + } + + $this.trigger( 'options.dt', oInit ); + + /* Backwards compatibility for the defaults */ + _fnCompatOpts( defaults ); + _fnCompatCols( defaults.column ); + + /* Convert the camel-case defaults to Hungarian */ + _fnCamelToHungarian( defaults, defaults, true ); + _fnCamelToHungarian( defaults.column, defaults.column, true ); + + /* Setting up the initialisation object */ + _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true ); + + + + /* Check to see if we are re-initialising a table */ + var allSettings = DataTable.settings; + for ( i=0, iLen=allSettings.length ; i').prependTo(this), + fastData: function (row, column, type) { + return _fnGetCellData(oSettings, row, column, type); + } + } ); + oSettings.nTable = this; + oSettings.oInit = oInit; + + allSettings.push( oSettings ); + + // Make a single API instance available for internal handling + oSettings.api = new _Api( oSettings ); + + // Need to add the instance after the instance after the settings object has been added + // to the settings array, so we can self reference the table instance if more than one + oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); + + // Backwards compatibility, before we apply all the defaults + _fnCompatOpts( oInit ); + + // If the length menu is given, but the init display length is not, use the length menu + if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) + { + oInit.iDisplayLength = Array.isArray(oInit.aLengthMenu[0]) + ? oInit.aLengthMenu[0][0] + : $.isPlainObject( oInit.aLengthMenu[0] ) + ? oInit.aLengthMenu[0].value + : oInit.aLengthMenu[0]; + } + + // Apply the defaults and init options to make a single init object will all + // options defined from defaults and instance options. + oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); + + + // Map the initialisation options onto the settings object + _fnMap( oSettings.oFeatures, oInit, [ + "bPaginate", + "bLengthChange", + "bFilter", + "bSort", + "bSortMulti", + "bInfo", + "bProcessing", + "bAutoWidth", + "bSortClasses", + "bServerSide", + "bDeferRender" + ] ); + _fnMap( oSettings, oInit, [ + "ajax", + "fnFormatNumber", + "sServerMethod", + "aaSorting", + "aaSortingFixed", + "aLengthMenu", + "sPaginationType", + "iStateDuration", + "bSortCellsTop", + "iTabIndex", + "sDom", + "fnStateLoadCallback", + "fnStateSaveCallback", + "renderer", + "searchDelay", + "rowId", + "caption", + "layout", + "orderDescReverse", + "orderIndicators", + "orderHandler", + "titleRow", + "typeDetect", + [ "iCookieDuration", "iStateDuration" ], // backwards compat + [ "oSearch", "oPreviousSearch" ], + [ "aoSearchCols", "aoPreSearchCols" ], + [ "iDisplayLength", "_iDisplayLength" ] + ] ); + _fnMap( oSettings.oScroll, oInit, [ + [ "sScrollX", "sX" ], + [ "sScrollXInner", "sXInner" ], + [ "sScrollY", "sY" ], + [ "bScrollCollapse", "bCollapse" ] + ] ); + _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); + + /* Callback functions which are array driven */ + _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback ); + _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams ); + _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams ); + _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded ); + _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback ); + _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow ); + _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback ); + _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback ); + _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete ); + _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback ); + + oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId ); + + // Add event listeners + if (oInit.on) { + Object.keys(oInit.on).forEach(function (key) { + _fnListener($this, key, oInit.on[key]); + }); + } + + /* Browser support detection */ + _fnBrowserDetect( oSettings ); + + var oClasses = oSettings.oClasses; + + $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); + $this.addClass( oClasses.table ); + + if (! oSettings.oFeatures.bPaginate) { + oInit.iDisplayStart = 0; + } + + if ( oSettings.iInitDisplayStart === undefined ) + { + /* Display start point, taking into account the save saving */ + oSettings.iInitDisplayStart = oInit.iDisplayStart; + oSettings._iDisplayStart = oInit.iDisplayStart; + } + + var defer = oInit.iDeferLoading; + if ( defer !== null ) + { + oSettings.deferLoading = true; + + var tmp = Array.isArray(defer); + oSettings._iRecordsDisplay = tmp ? defer[0] : defer; + oSettings._iRecordsTotal = tmp ? defer[1] : defer; + } + + /* + * Columns + * See if we should load columns automatically or use defined ones + */ + var columnsInit = []; + var thead = this.getElementsByTagName('thead'); + var initHeaderLayout = _fnDetectHeader( oSettings, thead[0] ); + + // If we don't have a columns array, then generate one with nulls + if ( oInit.aoColumns ) { + columnsInit = oInit.aoColumns; + } + else if ( initHeaderLayout.length ) { + for ( i=0, iLen=initHeaderLayout[0].length ; i').appendTo( $this ); + } + + caption.html( oSettings.caption ); + } + + // Store the caption side, so we can remove the element from the document + // when creating the element + if (caption.length) { + caption[0]._captionSide = caption.css('caption-side'); + oSettings.captionNode = caption[0]; + } + + if ( thead.length === 0 ) { + thead = $('').appendTo($this); + } + oSettings.nTHead = thead[0]; + + var tbody = $this.children('tbody'); + if ( tbody.length === 0 ) { + tbody = $('').insertAfter(thead); + } + oSettings.nTBody = tbody[0]; + + var tfoot = $this.children('tfoot'); + if ( tfoot.length === 0 ) { + // If we are a scrolling table, and no footer has been given, then we need to create + // a tfoot element for the caption element to be appended to + tfoot = $('').appendTo($this); + } + oSettings.nTFoot = tfoot[0]; + + // Copy the data index array + oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); + + // Initialisation complete - table can be drawn + oSettings.bInitialised = true; + + // Language definitions + var oLanguage = oSettings.oLanguage; + $.extend( true, oLanguage, oInit.oLanguage ); + + if ( oLanguage.sUrl ) { + // Get the language definitions from a file + $.ajax( { + dataType: 'json', + url: oLanguage.sUrl, + success: function ( json ) { + _fnCamelToHungarian( defaults.oLanguage, json ); + $.extend( true, oLanguage, json, oSettings.oInit.oLanguage ); + + _fnCallbackFire( oSettings, null, 'i18n', [oSettings], true); + _fnInitialise( oSettings ); + }, + error: function () { + // Error occurred loading language file + _fnLog( oSettings, 0, 'i18n file loading error', 21 ); + + // Continue on as best we can + _fnInitialise( oSettings ); + } + } ); + } + else { + _fnCallbackFire( oSettings, null, 'i18n', [oSettings], true); + _fnInitialise( oSettings ); + } + } ); + _that = null; + return this; + }; + + + + /** + * DataTables extensions + * + * This namespace acts as a collection area for plug-ins that can be used to + * extend DataTables capabilities. Indeed many of the build in methods + * use this method to provide their own capabilities (sorting methods for + * example). + * + * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy + * reasons + * + * @namespace + */ + DataTable.ext = _ext = { + /** + * DataTables build type (expanded by the download builder) + * + * @type string + */ + builder: "-source-", + + /** + * Buttons. For use with the Buttons extension for DataTables. This is + * defined here so other extensions can define buttons regardless of load + * order. It is _not_ used by DataTables core. + * + * @type object + * @default {} + */ + buttons: {}, + + + /** + * ColumnControl buttons and content + * + * @type object + */ + ccContent: {}, + + + /** + * Element class names + * + * @type object + * @default {} + */ + classes: {}, + + + /** + * Error reporting. + * + * How should DataTables report an error. Can take the value 'alert', + * 'throw', 'none' or a function. + * + * @type string|function + * @default alert + */ + errMode: "alert", + + + /** + * Legacy so v1 plug-ins don't throw js errors on load + */ + feature: [], + + /** + * Feature plug-ins. + * + * This is an object of callbacks which provide the features for DataTables + * to be initialised via the `layout` option. + */ + features: {}, + + + /** + * Row searching. + * + * This method of searching is complimentary to the default type based + * searching, and a lot more comprehensive as it allows you complete control + * over the searching logic. Each element in this array is a function + * (parameters described below) that is called for every row in the table, + * and your logic decides if it should be included in the searching data set + * or not. + * + * Searching functions have the following input parameters: + * + * 1. `{object}` DataTables settings object: see + * {@link DataTable.models.oSettings} + * 2. `{array|object}` Data for the row to be processed (same as the + * original format that was passed in as the data source, or an array + * from a DOM data source + * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which + * can be useful to retrieve the `TR` element if you need DOM interaction. + * + * And the following return is expected: + * + * * {boolean} Include the row in the searched result set (true) or not + * (false) + * + * Note that as with the main search ability in DataTables, technically this + * is "filtering", since it is subtractive. However, for consistency in + * naming we call it searching here. + * + * @type array + * @default [] + * + * @example + * // The following example shows custom search being applied to the + * // fourth column (i.e. the data[3] index) based on two input values + * // from the end-user, matching the data in a certain range. + * $.fn.dataTable.ext.search.push( + * function( settings, data, dataIndex ) { + * var min = document.getElementById('min').value * 1; + * var max = document.getElementById('max').value * 1; + * var version = data[3] == "-" ? 0 : data[3]*1; + * + * if ( min == "" && max == "" ) { + * return true; + * } + * else if ( min == "" && version < max ) { + * return true; + * } + * else if ( min < version && "" == max ) { + * return true; + * } + * else if ( min < version && version < max ) { + * return true; + * } + * return false; + * } + * ); + */ + search: [], + + + /** + * Selector extensions + * + * The `selector` option can be used to extend the options available for the + * selector modifier options (`selector-modifier` object data type) that + * each of the three built in selector types offer (row, column and cell + + * their plural counterparts). For example the Select extension uses this + * mechanism to provide an option to select only rows, columns and cells + * that have been marked as selected by the end user (`{selected: true}`), + * which can be used in conjunction with the existing built in selector + * options. + * + * Each property is an array to which functions can be pushed. The functions + * take three attributes: + * + * * Settings object for the host table + * * Options object (`selector-modifier` object type) + * * Array of selected item indexes + * + * The return is an array of the resulting item indexes after the custom + * selector has been applied. + * + * @type object + */ + selector: { + cell: [], + column: [], + row: [] + }, + + + /** + * Legacy configuration options. Enable and disable legacy options that + * are available in DataTables. + * + * @type object + */ + legacy: { + /** + * Enable / disable DataTables 1.9 compatible server-side processing + * requests + * + * @type boolean + * @default null + */ + ajax: null + }, + + + /** + * Pagination plug-in methods. + * + * Each entry in this object is a function and defines which buttons should + * be shown by the pagination rendering method that is used for the table: + * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the + * buttons are displayed in the document, while the functions here tell it + * what buttons to display. This is done by returning an array of button + * descriptions (what each button will do). + * + * Pagination types (the four built in options and any additional plug-in + * options defined here) can be used through the `paginationType` + * initialisation parameter. + * + * The functions defined take two parameters: + * + * 1. `{int} page` The current page index + * 2. `{int} pages` The number of pages in the table + * + * Each function is expected to return an array where each element of the + * array can be one of: + * + * * `first` - Jump to first page when activated + * * `last` - Jump to last page when activated + * * `previous` - Show previous page when activated + * * `next` - Show next page when activated + * * `{int}` - Show page of the index given + * * `{array}` - A nested array containing the above elements to add a + * containing 'DIV' element (might be useful for styling). + * + * Note that DataTables v1.9- used this object slightly differently whereby + * an object with two functions would be defined for each plug-in. That + * ability is still supported by DataTables 1.10+ to provide backwards + * compatibility, but this option of use is now decremented and no longer + * documented in DataTables 1.10+. + * + * @type object + * @default {} + * + * @example + * // Show previous, next and current page buttons only + * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { + * return [ 'previous', page, 'next' ]; + * }; + */ + pager: {}, + + + renderer: { + pageButton: {}, + header: {} + }, + + + /** + * Ordering plug-ins - custom data source + * + * The extension options for ordering of data available here is complimentary + * to the default type based ordering that DataTables typically uses. It + * allows much greater control over the the data that is being used to + * order a column, but is necessarily therefore more complex. + * + * This type of ordering is useful if you want to do ordering based on data + * live from the DOM (for example the contents of an 'input' element) rather + * than just the static string that DataTables knows of. + * + * The way these plug-ins work is that you create an array of the values you + * wish to be ordering for the column in question and then return that + * array. The data in the array much be in the index order of the rows in + * the table (not the currently ordering order!). Which order data gathering + * function is run here depends on the `dt-init columns.orderDataType` + * parameter that is used for the column (if any). + * + * The functions defined take two parameters: + * + * 1. `{object}` DataTables settings object: see + * {@link DataTable.models.oSettings} + * 2. `{int}` Target column index + * + * Each function is expected to return an array: + * + * * `{array}` Data for the column to be ordering upon + * + * @type array + * + * @example + * // Ordering using `input` node values + * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) + * { + * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { + * return $('input', td).val(); + * } ); + * } + */ + order: {}, + + + /** + * Type based plug-ins. + * + * Each column in DataTables has a type assigned to it, either by automatic + * detection or by direct assignment using the `type` option for the column. + * The type of a column will effect how it is ordering and search (plug-ins + * can also make use of the column type if required). + * + * @namespace + */ + type: { + /** + * Automatic column class assignment + */ + className: {}, + + /** + * Type detection functions. + * + * The functions defined in this object are used to automatically detect + * a column's type, making initialisation of DataTables super easy, even + * when complex data is in the table. + * + * The functions defined take two parameters: + * + * 1. `{*}` Data from the column cell to be analysed + * 2. `{settings}` DataTables settings object. This can be used to + * perform context specific type detection - for example detection + * based on language settings such as using a comma for a decimal + * place. Generally speaking the options from the settings will not + * be required + * + * Each function is expected to return: + * + * * `{string|null}` Data type detected, or null if unknown (and thus + * pass it on to the other type detection functions. + * + * @type array + * + * @example + * // Currency type detection plug-in: + * $.fn.dataTable.ext.type.detect.push( + * function ( data, settings ) { + * // Check the numeric part + * if ( ! data.substring(1).match(/[0-9]/) ) { + * return null; + * } + * + * // Check prefixed by currency + * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { + * return 'currency'; + * } + * return null; + * } + * ); + */ + detect: [], + + /** + * Automatic renderer assignment + */ + render: {}, + + + /** + * Type based search formatting. + * + * The type based searching functions can be used to pre-format the + * data to be search on. For example, it can be used to strip HTML + * tags or to de-format telephone numbers for numeric only searching. + * + * Note that is a search is not defined for a column of a given type, + * no search formatting will be performed. + * + * Pre-processing of searching data plug-ins - When you assign the sType + * for a column (or have it automatically detected for you by DataTables + * or a type detection plug-in), you will typically be using this for + * custom sorting, but it can also be used to provide custom searching + * by allowing you to pre-processing the data and returning the data in + * the format that should be searched upon. This is done by adding + * functions this object with a parameter name which matches the sType + * for that target column. This is the corollary of afnSortData + * for searching data. + * + * The functions defined take a single parameter: + * + * 1. `{*}` Data from the column cell to be prepared for searching + * + * Each function is expected to return: + * + * * `{string|null}` Formatted string that will be used for the searching. + * + * @type object + * @default {} + * + * @example + * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { + * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); + * } + */ + search: {}, + + + /** + * Type based ordering. + * + * The column type tells DataTables what ordering to apply to the table + * when a column is sorted upon. The order for each type that is defined, + * is defined by the functions available in this object. + * + * Each ordering option can be described by three properties added to + * this object: + * + * * `{type}-pre` - Pre-formatting function + * * `{type}-asc` - Ascending order function + * * `{type}-desc` - Descending order function + * + * All three can be used together, only `{type}-pre` or only + * `{type}-asc` and `{type}-desc` together. It is generally recommended + * that only `{type}-pre` is used, as this provides the optimal + * implementation in terms of speed, although the others are provided + * for compatibility with existing Javascript sort functions. + * + * `{type}-pre`: Functions defined take a single parameter: + * + * 1. `{*}` Data from the column cell to be prepared for ordering + * + * And return: + * + * * `{*}` Data to be sorted upon + * + * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort + * functions, taking two parameters: + * + * 1. `{*}` Data to compare to the second parameter + * 2. `{*}` Data to compare to the first parameter + * + * And returning: + * + * * `{*}` Ordering match: <0 if first parameter should be sorted lower + * than the second parameter, ===0 if the two parameters are equal and + * >0 if the first parameter should be sorted height than the second + * parameter. + * + * @type object + * @default {} + * + * @example + * // Numeric ordering of formatted numbers with a pre-formatter + * $.extend( $.fn.dataTable.ext.type.order, { + * "string-pre": function(x) { + * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); + * return parseFloat( a ); + * } + * } ); + * + * @example + * // Case-sensitive string ordering, with no pre-formatting method + * $.extend( $.fn.dataTable.ext.order, { + * "string-case-asc": function(x,y) { + * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + * }, + * "string-case-desc": function(x,y) { + * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + * } + * } ); + */ + order: {} + }, + + /** + * Unique DataTables instance counter + * + * @type int + * @private + */ + _unique: 0, + + + // + // Depreciated + // The following properties are retained for backwards compatibility only. + // The should not be used in new projects and will be removed in a future + // version + // + + /** + * Version check function. + * @type function + * @depreciated Since 1.10 + */ + fnVersionCheck: DataTable.fnVersionCheck, + + + /** + * Index for what 'this' index API functions should use + * @type int + * @deprecated Since v1.10 + */ + iApiIndex: 0, + + + /** + * Software version + * @type string + * @deprecated Since v1.10 + */ + sVersion: DataTable.version + }; + + + // + // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts + // + $.extend( _ext, { + afnFiltering: _ext.search, + aTypes: _ext.type.detect, + ofnSearch: _ext.type.search, + oSort: _ext.type.order, + afnSortData: _ext.order, + aoFeatures: _ext.feature, + oStdClasses: _ext.classes, + oPagination: _ext.pager + } ); + + + $.extend( DataTable.ext.classes, { + container: 'dt-container', + empty: { + row: 'dt-empty' + }, + info: { + container: 'dt-info' + }, + layout: { + row: 'dt-layout-row', + cell: 'dt-layout-cell', + tableRow: 'dt-layout-table', + tableCell: '', + start: 'dt-layout-start', + end: 'dt-layout-end', + full: 'dt-layout-full' + }, + length: { + container: 'dt-length', + select: 'dt-input' + }, + order: { + canAsc: 'dt-orderable-asc', + canDesc: 'dt-orderable-desc', + isAsc: 'dt-ordering-asc', + isDesc: 'dt-ordering-desc', + none: 'dt-orderable-none', + position: 'sorting_' + }, + processing: { + container: 'dt-processing' + }, + scrolling: { + body: 'dt-scroll-body', + container: 'dt-scroll', + footer: { + self: 'dt-scroll-foot', + inner: 'dt-scroll-footInner' + }, + header: { + self: 'dt-scroll-head', + inner: 'dt-scroll-headInner' + } + }, + search: { + container: 'dt-search', + input: 'dt-input' + }, + table: 'dataTable', + tbody: { + cell: '', + row: '' + }, + thead: { + cell: '', + row: '' + }, + tfoot: { + cell: '', + row: '' + }, + paging: { + active: 'current', + button: 'dt-paging-button', + container: 'dt-paging', + disabled: 'disabled', + nav: '' + } + } ); + + + /* + * It is useful to have variables which are scoped locally so only the + * DataTables functions can access them and they don't leak into global space. + * At the same time these functions are often useful over multiple files in the + * core and API, so we list, or at least document, all variables which are used + * by DataTables as private variables here. This also ensures that there is no + * clashing of variable names and that they can easily referenced for reuse. + */ + + + // Defined else where + // _selector_run + // _selector_opts + // _selector_row_indexes + + var _ext; // DataTable.ext + var _Api; // DataTable.Api + var _api_register; // DataTable.Api.register + var _api_registerPlural; // DataTable.Api.registerPlural + + var _re_dic = {}; + var _re_new_lines = /[\r\n\u2028]/g; + var _re_html = /<([^>]*>)/g; + var _max_str_len = Math.pow(2, 28); + + // This is not strict ISO8601 - Date.parse() is quite lax, although + // implementations differ between browsers. + var _re_date = /^\d{2,4}[./-]\d{1,2}[./-]\d{1,2}([T ]{1}\d{1,2}[:.]\d{2}([.:]\d{2})?)?$/; + + // Escape regular expression special characters + var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); + + // https://en.wikipedia.org/wiki/Foreign_exchange_market + // - \u20BD - Russian ruble. + // - \u20a9 - South Korean Won + // - \u20BA - Turkish Lira + // - \u20B9 - Indian Rupee + // - R - Brazil (R$) and South Africa + // - fr - Swiss Franc + // - kr - Swedish krona, Norwegian krone and Danish krone + // - \u2009 is thin space and \u202F is narrow no-break space, both used in many + // - Ƀ - Bitcoin + // - Ξ - Ethereum + // standards as thousands separators. + var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi; + + + var _empty = function ( d ) { + return !d || d === true || d === '-' ? true : false; + }; + + + var _intVal = function ( s ) { + var integer = parseInt( s, 10 ); + return !isNaN(integer) && isFinite(s) ? integer : null; + }; + + // Convert from a formatted number with characters other than `.` as the + // decimal place, to a Javascript number + var _numToDecimal = function ( num, decimalPoint ) { + // Cache created regular expressions for speed as this function is called often + if ( ! _re_dic[ decimalPoint ] ) { + _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); + } + return typeof num === 'string' && decimalPoint !== '.' ? + num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : + num; + }; + + + var _isNumber = function ( d, decimalPoint, formatted, allowEmpty ) { + var type = typeof d; + var strType = type === 'string'; + + if ( type === 'number' || type === 'bigint') { + return true; + } + + // If empty return immediately so there must be a number if it is a + // formatted string (this stops the string "k", or "kr", etc being detected + // as a formatted number for currency + if ( allowEmpty && _empty( d ) ) { + return true; + } + + if ( decimalPoint && strType ) { + d = _numToDecimal( d, decimalPoint ); + } + + if ( formatted && strType ) { + d = d.replace( _re_formatted_numeric, '' ); + } + + return !isNaN( parseFloat(d) ) && isFinite( d ); + }; + + + // A string without HTML in it can be considered to be HTML still + var _isHtml = function ( d ) { + return _empty( d ) || typeof d === 'string'; + }; + + // Is a string a number surrounded by HTML? + var _htmlNumeric = function ( d, decimalPoint, formatted, allowEmpty ) { + if ( allowEmpty && _empty( d ) ) { + return true; + } + + // input and select strings mean that this isn't just a number + if (typeof d === 'string' && d.match(/<(input|select)/i)) { + return null; + } + + var html = _isHtml( d ); + return ! html ? + null : + _isNumber( _stripHtml( d ), decimalPoint, formatted, allowEmpty ) ? + true : + null; + }; + + + var _pluck = function ( a, prop, prop2 ) { + var out = []; + var i=0, ien=a.length; + + // Could have the test in the loop for slightly smaller code, but speed + // is essential here + if ( prop2 !== undefined ) { + for ( ; i _max_str_len) { + throw new Error('Exceeded max str len'); + } + + var previous; + + input = input.replace(_re_html, ''); // Complete tags + + // Safety for incomplete script tag - use do / while to ensure that + // we get all instances + do { + previous = input; + input = input.replace(/ + + + + +
+

Datatables server side processing with PHP and MYSQL

+
+
+ + + + + + + + + + + +
instructioninputoutputCreated AtActions
+
+ + + + + + + + + \ No newline at end of file diff --git a/server_side/server_side.php b/server_side/server_side.php new file mode 100644 index 0000000..b775e0c --- /dev/null +++ b/server_side/server_side.php @@ -0,0 +1,69 @@ + 'instruction', 'dt' => 0), + array('db' => 'input', 'dt' => 1), + array('db' => 'output', 'dt' => 2), + array('db' => 'created_ad', 'dt' => 3), + array('db' => 'id', 'dt' => 4) + /** if use date format */ + // array( + // 'db' => 'date', + // 'dt' => 3, + // 'formatter' => function( $d, $row ) { + // return '$'.number_format($d); + // } + // ) + ); + + // SQL server connection information + $sql_details = array( + 'user' => 'root', + 'pass' => 'XmRTSMQ9', + 'db' => 'php_crud', + 'host' => 'localhost' + ); + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * If you just want to use the basic configuration for DataTables with PHP + * server-side, there is no need to edit below this line. + */ + + require('ssp.class.php'); + + echo json_encode( + SSP::simple($_GET, $sql_details, $table, $primaryKey, $columns) + ); + ?> + + diff --git a/server_side/ssp.class.php b/server_side/ssp.class.php new file mode 100644 index 0000000..1374df8 --- /dev/null +++ b/server_side/ssp.class.php @@ -0,0 +1,554 @@ + isset ( $request['draw'] ) ? + intval( $request['draw'] ) : + 0, + "recordsTotal" => intval( $recordsTotal ), + "recordsFiltered" => intval( $recordsFiltered ), + "data" => self::data_output( $columns, $data ) + ); + } + + + /** + * The difference between this method and the `simple` one, is that you can + * apply additional `where` conditions to the SQL queries. These can be in + * one of two forms: + * + * * 'Result condition' - This is applied to the result set, but not the + * overall paging information query - i.e. it will not effect the number + * of records that a user sees they can have access to. This should be + * used when you want apply a filtering condition that the user has sent. + * * 'All condition' - This is applied to all queries that are made and + * reduces the number of records that the user can access. This should be + * used in conditions where you don't want the user to ever have access to + * particular records (for example, restricting by a login id). + * + * @param array $request Data sent to server by DataTables + * @param array|PDO $conn PDO connection resource or connection parameters array + * @param string $table SQL table to query + * @param string $primaryKey Primary key of the table + * @param array $columns Column information array + * @param string $whereResult WHERE condition to apply to the result set + * @param string $whereAll WHERE condition to apply to all queries + * @return array Server-side processing response array + */ + static function complex ( $request, $conn, $table, $primaryKey, $columns, $whereResult=null, $whereAll=null ) + { + $bindings = array(); + $db = self::db( $conn ); + $localWhereResult = array(); + $localWhereAll = array(); + $whereAllSql = ''; + + // Build the SQL query string from the request + $limit = self::limit( $request, $columns ); + $order = self::order( $request, $columns ); + $where = self::filter( $request, $columns, $bindings ); + + $whereResult = self::_flatten( $whereResult ); + $whereAll = self::_flatten( $whereAll ); + + if ( $whereResult ) { + $where = $where ? + $where .' AND '.$whereResult : + 'WHERE '.$whereResult; + } + + if ( $whereAll ) { + $where = $where ? + $where .' AND '.$whereAll : + 'WHERE '.$whereAll; + + $whereAllSql = 'WHERE '.$whereAll; + } + + // Main query to actually get the data + $data = self::sql_exec( $db, $bindings, + "SELECT `".implode("`, `", self::pluck($columns, 'db'))."` + FROM `$table` + $where + $order + $limit" + ); + + // Data set length after filtering + $resFilterLength = self::sql_exec( $db, $bindings, + "SELECT COUNT(`{$primaryKey}`) + FROM `$table` + $where" + ); + $recordsFiltered = $resFilterLength[0][0]; + + // Total data set length + $resTotalLength = self::sql_exec( $db, $bindings, + "SELECT COUNT(`{$primaryKey}`) + FROM `$table` ". + $whereAllSql + ); + $recordsTotal = $resTotalLength[0][0]; + + /* + * Output + */ + return array( + "draw" => isset ( $request['draw'] ) ? + intval( $request['draw'] ) : + 0, + "recordsTotal" => intval( $recordsTotal ), + "recordsFiltered" => intval( $recordsFiltered ), + "data" => self::data_output( $columns, $data ) + ); + } + + + /** + * Connect to the database + * + * @param array $sql_details SQL server connection details array, with the + * properties: + * * host - host name + * * db - database name + * * user - user name + * * pass - user password + * @return resource Database connection handle + */ + static function sql_connect ( $sql_details ) + { + try { + $db = @new PDO( + "mysql:host={$sql_details['host']};dbname={$sql_details['db']}", + $sql_details['user'], + $sql_details['pass'], + array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ) + ); + } + catch (PDOException $e) { + self::fatal( + "An error occurred while connecting to the database. ". + "The error reported by the server was: ".$e->getMessage() + ); + } + + return $db; + } + + + /** + * Execute an SQL query on the database + * + * @param resource $db Database handler + * @param array $bindings Array of PDO binding values from bind() to be + * used for safely escaping strings. Note that this can be given as the + * SQL query string if no bindings are required. + * @param string $sql SQL query to execute. + * @return array Result from the query (all rows) + */ + static function sql_exec ( $db, $bindings, $sql=null ) + { + // Argument shifting + if ( $sql === null ) { + $sql = $bindings; + } + + $stmt = $db->prepare( $sql ); + //echo $sql; + + // Bind parameters + if ( is_array( $bindings ) ) { + for ( $i=0, $ien=count($bindings) ; $i<$ien ; $i++ ) { + $binding = $bindings[$i]; + $stmt->bindValue( $binding['key'], $binding['val'], $binding['type'] ); + } + } + + // Execute + try { + $stmt->execute(); + } + catch (PDOException $e) { + self::fatal( "An SQL error occurred: ".$e->getMessage() ); + } + + // Return all + return $stmt->fetchAll( PDO::FETCH_BOTH ); + } + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Internal methods + */ + + /** + * Throw a fatal error. + * + * This writes out an error message in a JSON string which DataTables will + * see and show to the user in the browser. + * + * @param string $msg Message to send to the client + */ + static function fatal ( $msg ) + { + echo json_encode( array( + "error" => $msg + ) ); + + exit(0); + } + + /** + * Create a PDO binding key which can be used for escaping variables safely + * when executing a query with sql_exec() + * + * @param array &$a Array of bindings + * @param * $val Value to bind + * @param int $type PDO field type + * @return string Bound key to be used in the SQL where this parameter + * would be used. + */ + static function bind ( &$a, $val, $type ) + { + $key = ':binding_'.count( $a ); + + $a[] = array( + 'key' => $key, + 'val' => $val, + 'type' => $type + ); + + return $key; + } + + + /** + * Pull a particular property from each assoc. array in a numeric array, + * returning and array of the property values from each item. + * + * @param array $a Array to get data from + * @param string $prop Property to read + * @return array Array of property values + */ + static function pluck ( $a, $prop ) + { + $out = array(); + + for ( $i=0, $len=count($a) ; $i<$len ; $i++ ) { + if(empty($a[$i][$prop])){ + continue; + } + //removing the $out array index confuses the filter method in doing proper binding, + //adding it ensures that the array data are mapped correctly + $out[$i] = $a[$i][$prop]; + } + + return $out; + } + + + /** + * Return a string from an array or a string + * + * @param array|string $a Array to join + * @param string $join Glue for the concatenation + * @return string Joined string + */ + static function _flatten ( $a, $join = ' AND ' ) + { + if ( ! $a ) { + return ''; + } + else if ( $a && is_array($a) ) { + return implode( $join, $a ); + } + return $a; + } +} + + + + diff --git a/test_connection.php b/test_connection.php new file mode 100755 index 0000000..0631a8f --- /dev/null +++ b/test_connection.php @@ -0,0 +1,35 @@ +Error de conexión: " . mysqli_connect_error()); +} else { + echo "

¡Conexión exitosa!

"; + echo "

Información del servidor:

"; + echo "Versión MySQL: " . mysqli_get_server_info($conn); +} + +// Probar consulta simple +$query = "SELECT 1+1 AS result"; +$result = mysqli_query($conn, $query); +if ($result) { + $row = mysqli_fetch_assoc($result); + echo "

Prueba de consulta:

1 + 1 = " . $row['result']; +} else { + echo "

Error en consulta:

" . mysqli_error($conn); +} + +mysqli_close($conn); +?> \ No newline at end of file