diff --git a/fec/fec/static/js/pages/dom-datatableblock2.js b/fec/fec/static/js/pages/dom-datatableblock2.js new file mode 100644 index 0000000000..bbd38a0b79 --- /dev/null +++ b/fec/fec/static/js/pages/dom-datatableblock2.js @@ -0,0 +1,197 @@ +'use strict'; + +//TEMPORARY ESLINT FIXES +/* eslint-disable no-debugger, no-console */ +// $ not defined ERROR WITHOUT THIS GOBAL...NEED TO RESEARCH ALTERNATIVES +/* global $ */ + +//**IT IS ALSO PREFERRABLE TO `dom-datatableblock` BECAUE IT DOES NOT NEED THE TEMPLATETAG ADDED TO THE PAGE... +//...BECAUSE IT GET `sort_info` from `partials/tableblock_to_datatable.html` USING DJANGO {{}} TAGS... +//...AND CREATES `th_array` FROM EACH TABLES HEADERS ON THE PAGE. + +//var tables = require('../modules/tables'); +//require('../modules/import-dtables'); //ANOTHER OPTOION THAT COULD BE A SEPATATE IMPORT-SCRIPT + +//var $ = require('jquery'); + +//require('datatables.net'); +require('datatables.net-responsive'); + +var convert_for_sort = function(type, value) { +//function convert_for_sort(type, value) { + + if (type == 'date') { + //Assumes mm/dd/yyyy format is being supplied + //pattern = /\d{2}\/\d{2}\/\d{4}/i; //not using this line + var dateString = value.replace(/(\d{2})\/(\d{2})\/(\d{4})/, `$2/$1/$3` ); + console.log('dateString:'+ dateString); + + var dateParts = dateString.split('/'); + + // month is 0-based, that's why we need dataParts[1] - 1 + var date = new Date(+dateParts[2], dateParts[1] - 1, +dateParts[0]); + + //var timestampInMs = date.getTime(); + + var unixTimestamp = Math.floor(date.getTime() / 1000); + + console.log(unixTimestamp); // + + return unixTimestamp; + + } + + else if (type == 'currency') { + //Assumes format: '$1,234.56' + //pattern = /^\$|,/i //Remove $ and commas + var amount_converted = value.replace(/^\$|,/,''); + + //does this need to be a float or integer ot string? + return amount_converted; + } + + //type == 'numeric or alphabetical') + else { + + return value; + + } + + }; + +$(function() { + +//How `sort_info` comes from Python templatetag, but building it below (if exists) in JS instead, using Django {{}} in partials/tableblock_to_datatable.html +//sort_info = +// [ +// [{'column': 'Date', 'sort_format': 'date'}, {'column': 'Number of Pages', 'sort_format': 'numeric'}] +// , +// [{}], +// [{'column': 'Document Date', 'sort_format': 'date'}, {'column': 'Amount', 'sort_format': 'currency'}] +// ] + +//`sort_column_object` built below for each table using `sort_info` +//EXAMPLE: +// { +// "1": "numeric", +// "2": "date" +// } + +//{} + +// { +// "1": "date", +// "2": "currency" +// } + +// In jQuery , 'this' is the table, 'index' is the iterator (0, 1, 2 etc...) +$('.block-datatable_block table').each(function(index){ + + console.log ('index', index); + console.log ('(this):', this); + +//Create the `sort_info`` array of from the user-sumitted Sort fields for this table (if any was submutted). + let sort_info; + //Find the sort info script tag for this table, if exists + let sort_script = $(this).closest('.block-datatable_block').find('.sorting')[0]; + //If user submitted Sort fields in Wagtail... + if (sort_script) { + let sort_txt = sort_script.innerHTML; + sort_info = JSON.parse(sort_txt); + } + //...else just use an empty list + else { + sort_info= [{}]; + } + + console.log ('sort_info:', sort_info); + + let th_array = []; + //Iterate the cells in first row (header row) of current table, i.e. (this). + for(let c=0; c < (this).rows[0].cells.length; c++) { + + //Create an array the current tables header text + let th_text = this.rows[0].cells[c].innerText; + console.log ('th_text:', th_text); + th_array.push(th_text); + } + +/////////////////START APPLY HTML5 data-order ATTR TO CELLS USING `sort_info`//////////////// + +//***TODO: COULD JUST ITERATE ROWS[0].CELLS ONCE, FINDING A SORT INFO ITEME, MAKING THE CONVERSION AND SET DATA-ATTR... +//... THEN ITERATE THE NEXT ONE RATHER THAN ITERATING ROWS AGAIN BELOW ?? +let sort_columns_object = {}; +let initial_sort_column; +let initial_sort_order; + +//TODO: CAN I JUST ITERATE `th_array.length` HERE NOW INSTEAD OF `(this).rows[0].cells.length`` ? +//Iterate the cells in first row (headers) of current table (index) +for(let i=0; i < (this).rows[0].cells.length; i++) { + + //Now,iterate sort_info for current table to determine sort columns + for(let j=0; j < sort_info.length; j++) { + + //Create a sort_columns_object to use below to decide which cells get a converted data-order attr. + if ((this).rows[0].cells[i].innerText == sort_info[j].column) { + let column_index = th_array.indexOf(sort_info[j].column); + let sort_format = sort_info[j]['sort_format']; + sort_columns_object[column_index] = sort_format; + + } + } + +} +console.log( 'sort_columns_object:', sort_columns_object); + + //Determine the initial_sort column and initial sort order using sort_info object + + //Get the index position of column in the first item submitted by user in Wagtail Sort fields + let order_index = th_array.indexOf(sort_info[0]['column']); + //If the index is -1(non-existent), use default; otherwise, return it + initial_sort_column = order_index == -1 ? 0 : order_index; + console.log( 'initial_sort_column:', initial_sort_column); + //Get the initial sort order from order value in the first item submitted by user in Wagtail Sort fields + initial_sort_order = sort_info[0]['order'] || 'asc'; + console.log( 'initial_sort_order:', initial_sort_order); + +//TODO: COULD SET CURRENT CELL AS A VAR SO I DONT HAVE TO KEEP SAYING '(this).rows[k].cells[l]' + +//iterate all rows in current table +for(let k=0; k < (this).rows.length; k++) { + + //iterate all cells in current row + for(let l=0; l < (this).rows[k].cells.length; l++) { + + //If the number of the current iterator (l) is in the `sort_columns_object` + if(Object.prototype.hasOwnProperty.call(sort_columns_object, l)) { + //if (sort_columns_object.hasOwnProperty(l)) { //(This gets ESLINT error, so using above) + let sort_type = sort_columns_object[l]; + let sort_value = (this).rows[k].cells[l].innerText; //or use col_text var above? + let number_for_sort = convert_for_sort(sort_type, sort_value); + console.log('number_for_sort:', number_for_sort); + + //NOTE: THIS WAS BROKEN B/C OF (this) INSTEAD OF this (parens broke it) IF USING PARENS '(this)', ALWAYS US SEMICOLON ON PREV LINE + //Set the data-order(sort) attr for cells that require it in sort_columns_object + (this).rows[k].cells[l].setAttribute('data-order',number_for_sort); + + } + + } + +} + +/////////////////END APPLY HTML5 data-order ATTR TO CELLS USING `sort_info`//////////////// + + (this).id = `dtable-block-${index}`; + (this).classList.add('data-table', 'data-table--heading-borders', 'scrollX', 'simple-table' , 'u-no-border'); + + //THIS ONE JUST APPLIES jQuery datatables to the existing html table on page and give its intial ordering + + $(`#dtable-block-${index}`).DataTable({ + order: [[initial_sort_column ,initial_sort_order]] //from js above + }); + + }); // /end $('.block-datatable_block table').each(function + +}); //end $(document.ready function. + diff --git a/fec/fec/static/js/pages/legal-to-datatable.js b/fec/fec/static/js/pages/legal-to-datatable.js new file mode 100644 index 0000000000..cbe21b483a --- /dev/null +++ b/fec/fec/static/js/pages/legal-to-datatable.js @@ -0,0 +1,196 @@ +'use strict'; + +/* eslint-disable no-debugger, no-console */ +/* global $ */ + +//var $ = require('jquery'); +//var tables = require('../modules/tables');; + +//require('datatables.net'); +require('datatables.net-responsive'); + +//Sorting and ordering definitions for legal cononacal tables +const legal_docs_sorting = +{ + 'af-disposition': { + '1': 'currency', + '2': 'date', + ordering: { + column: '2', + direction: 'desc' + } + }, + 'af-documents': { + '0': 'date', + ordering: { + column: '0', + direction: 'desc' + } + }, + 'ao-final-opinion': { + '0': 'date', + ordering: { + column: '0', + direction: 'desc' + } + }, + 'ao-entities': { + ordering: { + column: '1', + direction: 'asc' + } + }, + //CAN'T DO THESE WITHOUT POSSIBLY USING THE ROW-GROUP PLUGIN + // 'archived-mur-documents': { + + // }, + // 'archived-mur-participants': { + + // }, + // 'current-mur-disposition': { + //1 : 'currency', + // 'ordering': { + // 'column': '1', + // 'direction':'asc' + // }, + //}, + //'current-mur-documents': { + //1:'date', + // 'ordering': { + // 'column': '1', + // 'direction':'asc' + // }, + //}, + // 'current-mur-participants': { + + // }, + // 'adr-disposition:': { + // 1 : 'currency', + // 'ordering': { + // 'column': '1', + // 'direction':'asc' + // }, + // }, + // 'adr-documents': { + + // }, + 'adr-participants': { + ordering: { + column: '1', + direction: 'asc' + } + + } +}; + +const covert_for_sort = function(type, value) { + + if (type == 'date') { + //Assumes mm/dd/yyyy format is being supplied + //pattern = /\d{2}\/\d{2}\/\d{4}/i; ne + var dateString = value.replace(/(\d{2})\/(\d{2})\/(\d{4})/, `$2/$1/$3` ); + console.log('dateString:'+ dateString); + + var dateParts = dateString.split('/'); + + // month is 0-based, that's why we need dataParts[1] - 1 + var date = new Date(+dateParts[2], dateParts[1] - 1, +dateParts[0]); + + //var timestampInMs = date.getTime(); + + var unixTimestamp = Math.floor(date.getTime() / 1000); + + console.log(unixTimestamp); // + + return unixTimestamp; + + } + + else if (type == 'currency') { + //Assumes format: '$1,234.56' + //pattern = /^\$|,/i //Remove $ and commas + var amount_converted = value.replace(/^\$|,/,''); + + //does this need to be a float or integer ot string? + return amount_converted; + } + + //type == 'numeric') + else { + + return value; + + } + + }; + +$(function() { + +///////////////START HTML5 DATE SORT SUPPORT//////////////// + +//THIS FUNCTION ONLY WORKS FOR APPLYING DATATABLES DIRECTLY TO TABLE) + +//const tables = $('table') + +const tables = document.getElementsByTagName('table'); +console.log ('Tables:', tables); + +let table_id; +//First iterate all tables on page: +Array.from(tables).forEach(table => { + //$('table').each(function(index, value){ + table_id = table.getAttribute('id'); + + console.log('table_id' + table_id); + + //****TO DO: SHOULD I DO AN IF ELSE RETURN SO IT DOES NOT HAVE TO ITERATE A TABLE WITHOUT SORT VALS? + if(Object.prototype.hasOwnProperty.call(legal_docs_sorting, table_id)) { + //if (legal_docs_sorting.hasOwnProperty(table_id)) { //(This gets ESLINT error, so using above) + + //Inside this iteration(table), now iterate all rows + for(let i=0; i < table.rows.length; i++) { + + for(let j=0; j < table.rows[i].cells.length; j++) { + //***TODO: COULD ALSO JUST LEAVE OUT TABLE IDS THAT DONT HAVE SORT IN ABOVE IF STMT, DO I NEED BOTH? + console.log ('legal_docs_sorting[table_id]:'+ legal_docs_sorting[table_id]); + if(Object.prototype.hasOwnProperty.call(legal_docs_sorting[table_id], j)) { + //if (legal_docs_sorting[table_id].hasOwnProperty(j)) { //(This gets ESLINT error, so using above) + + let sort_type = legal_docs_sorting[table_id][j]; + let sort_value = table.rows[i].cells[j].textContent; + let number_for_sort = covert_for_sort(sort_type,sort_value); + + table.rows[i].cells[j].setAttribute('data-order',number_for_sort); + } + + } + + } + + let order_col; + let order_dir; + if(Object.prototype.hasOwnProperty.call(legal_docs_sorting[table_id], 'ordering')) { + //if (legal_docs_sorting[table_id].hasOwnProperty('ordering')) { //(This gets ESLINT error, so using above) + order_col = legal_docs_sorting[table_id].ordering.column;//['ordering']['column'] + order_dir = legal_docs_sorting[table_id].ordering.direction;//['ordering']['direction'] + + } + else { + order_col = '0'; + order_dir = 'asc'; + } + + //$(myTable).addClass("data-table") + //myTable.classList.add("data-table", "data-table--heading-borders", "scrollX", "simple-table" , "u-no-border") + +//THIS ONE JUST APPLIES jQuery datatables to the existing table + $(`#${table_id}`).DataTable({ + order: [[order_col, order_dir]] + + }); + +//document.getElementsByClassName('block-table')[0].remove() + } //EMD if (legal_docs_sorting.hasOwnProperty(table_id))... + }); +});//end $(document.ready function. + diff --git a/fec/fec/static/js/pages/mutli-inplace-datatable.js b/fec/fec/static/js/pages/mutli-inplace-datatable.js new file mode 100644 index 0000000000..a138872522 --- /dev/null +++ b/fec/fec/static/js/pages/mutli-inplace-datatable.js @@ -0,0 +1,81 @@ +'use strict'; + +/* eslint-disable no-debugger, no-console */ +/* global $ */ + +//***NOTE: THIS ONE JUST CREATES A DATATABLE FROM ANY GENERIC `tableblocks` ON PAGE TARGETTED BY `$('.block-table table')`... +/// USED FOR FOR EXISTNNG TABLES ON audit-reports PAGES THAT HAVE SPECIFIC TABLE STRUCTURE. + +//var $ = require('jquery'); +require('datatables.net-responsive'); + +$(function() { + +/////////////////START HTML5 SORT SUPPORT//////////////// + +//Determine which col is the 'Date' col to add the `data-sort`` attr in next function +//TODO: This could be a named function that returns the index number of date col +var theTable = document.querySelector('.block-table table'); //gets only the first element +console.log ('theTable:', theTable); +$('.block-table table').each(function(index){ + +console.log ('index', index); + console.log ('(this):', this); + console.log ('(this):'+ this); + +let date_col; +for(let i=0; i < (this).rows[0].cells.length; i++) { + + if ((this).rows[0].cells[i].innerText == 'Date') { + date_col = i; + console.log ('date_col:'+ date_col); + + } +} + +//Set the data-order(sort) attr for the date cells with UNIX timestamp. Assumes mm/dd/yyyy format +for(let i=0; i < (this).rows.length; i++) { + + var dateText = (this).rows[i].cells[date_col].textContent; + + //Assumes mm/dd/yyyy format is being supplied + //Pattern = /\d{2}\/\d{2}\/\d{4}/i; //not using this line + var dateString = dateText.replace(/(\d{2})\/(\d{2})\/(\d{4})/, `$2/$1/$3` ); + console.log('dateString:'+ dateString); + + var dateParts = dateString.split('/'); + + // month is 0-based, that's why we need dataParts[1] - 1 + var date = new Date(+dateParts[2], dateParts[1] - 1, +dateParts[0]); + + //var timestampInMs = date.getTime(); + + var unixTimestamp = Math.floor(date.getTime() / 1000); + console.log(unixTimestamp); // + + (this).rows[i].cells[date_col].setAttribute('data-order',unixTimestamp); +} + + (this).id = `dtable-${index}`; + (this).classList.add('data-table', 'data-table--heading-borders', 'scrollX', 'simple-table' , 'u-no-border'); + +/////////////////END HTML5 DATE SUPPORT//////////////// + + // JUST APPLY jQuery datatables to the existing table + //$('.block-table table').DataTable({ + $(`#dtable-${index}`).DataTable({ + order: [[date_col, 'asc']] + }); + + }); // /end theTable.each(function(){ + +//This is a bit much, I think. Probably just add some CSS/SCSS to existing stylesheets +// Create an empty "constructed" stylesheet +const sheet = new CSSStyleSheet(); +// Apply a rule to the sheet +sheet.replaceSync(' .dataTables_length { width: 20%; display: inline-block; float: left; padding: 1rem 1rem 2rem 0 !important;} .dataTables_filter { width: 80%; float: left; display: inline-block; padding: 1rem 0rem 4.5rem 0 !important; }'); + +// Apply the stylesheet to a document +document.adoptedStyleSheets = [sheet]; + +}); //end $(document.ready function. diff --git a/fec/home/blocks.py b/fec/home/blocks.py index 81d6fcf119..2b3e5c5b06 100644 --- a/fec/home/blocks.py +++ b/fec/home/blocks.py @@ -187,6 +187,49 @@ class Meta: icon = 'table' +class DataTableBlock(blocks.StructBlock): + """A Datatable built with Wagtail TableBlock + """ + datatable_options = { + 'startRows': 7, + 'startCols': 4, + 'colHeaders': True, + 'rowHeaders': False, + 'height': 108, + 'language': 'en', + 'renderer': 'html' + } + + # TODO: MAKE SORT FIELDS REQUIRED, OR FIND WAY TO MAKE SURE AN EMPTY SORT FIELDS BLOCK DOES NOT BREAK AS IT DOES NOW + data_table = blocks.StreamBlock([ + ('title', blocks.CharBlock(required=False, icon='title')), + ('table', TableBlock(table_options=datatable_options)), + ('sort_fields', blocks.ListBlock(blocks.StructBlock([ + ('column', blocks.CharBlock(required=True, help_text="Put text exactly as it appears in the column head")), + ('sort_format', blocks.ChoiceBlock(choices=[ + ('date', 'Date (mm/dd/yyyy)'), + ('numeric', 'Numeric'), + ('currency', 'Currency($1,2345.67, no spaces between commas)'), + ('alphabetical', 'Alphabetical'), + ], required=True, help_text='Set custom sorting for a pecific column. If no sort fields are specified, \ + table defaults to ordering by first column/alphabetically.')), + ('order', blocks.ChoiceBlock(choices=[ + ('asc', 'Ascending'), + ('desc', 'Descending')], required=True, help_text='Ascending is largest to smallest. \ + Descending is smallest to largest')), + ]), required=True, help_text='')) + ], block_counts={ + 'table': {'max_num': 1}, + 'sort_fields': {'max_num': 1}} + ) + + class Meta: + template = 'blocks/data-table-block.html' + icon = 'table' + + class ExampleImage(blocks.StructBlock): """Creates an example module with an image and a caption, side-by-side Typically used for showing reporting Examples @@ -249,6 +292,7 @@ class ResourceBlock(blocks.StructBlock): ('image', ImageChooserBlock()), ('example_image', ExampleImage()), ('example_paragraph', ExampleParagraph()), + ('datatable_block', DataTableBlock()), ]) aside = blocks.StreamBlock([ diff --git a/fec/home/templates/blocks/data-table-block.html b/fec/home/templates/blocks/data-table-block.html new file mode 100644 index 0000000000..ceff38f6c9 --- /dev/null +++ b/fec/home/templates/blocks/data-table-block.html @@ -0,0 +1,49 @@ +{% load wagtailcore_tags %} + +{% for block in self.data_table %} + {% if block.block_type == "title" %} +

{{ block }}

+ + {% elif block.block_type == "table" %} + {{ block }} + + {% elif block.block_type == "sort_fields" %} + + + {% endif %} + +{% endfor %} + + + + + + + diff --git a/fec/home/templates/home/resource_page.html b/fec/home/templates/home/resource_page.html index 92bd2c400a..6cb17b9ab3 100644 --- a/fec/home/templates/home/resource_page.html +++ b/fec/home/templates/home/resource_page.html @@ -1,6 +1,7 @@ {% extends "long_page.html" %} {% load wagtailcore_tags %} {% load static %} +{% load filters %} {% block body_class %}template-{{ self.get_verbose_name | slugify }}{% endblock %} {% block breadcrumbs %} @@ -97,3 +98,12 @@

Related topics

{% endfor %} {% endblock %} + +{% block extra_js %} +{% if 'audit-reports' in request.path %} + + {% endif %} + + + +{% endblock %} diff --git a/fec/legal/templates/legal-admin_fine.jinja b/fec/legal/templates/legal-admin_fine.jinja index 7fb685a3e8..d8db149366 100644 --- a/fec/legal/templates/legal-admin_fine.jinja +++ b/fec/legal/templates/legal-admin_fine.jinja @@ -64,7 +64,7 @@

Disposition

- +
@@ -92,9 +92,9 @@
Disposition
-
+

Documents

- +
@@ -119,3 +119,8 @@ {% endblock %} +{% block scripts %} + +{% endblock %} + + diff --git a/fec/legal/templates/legal-advisory-opinion.jinja b/fec/legal/templates/legal-advisory-opinion.jinja index b858dfe12d..de12521a09 100644 --- a/fec/legal/templates/legal-advisory-opinion.jinja +++ b/fec/legal/templates/legal-advisory-opinion.jinja @@ -12,6 +12,35 @@ {% block css %} + + {% endblock %}
@@ -46,7 +75,7 @@ Final opinion {{ final_opinion.date | date(fmt='%B %d, %Y') }}
{% endif %} -
Date
+
@@ -67,7 +96,7 @@

Entities

-
Date
+
@@ -159,3 +188,6 @@ {% endblock %} +{% block scripts %} + +{% endblock %} diff --git a/tasks.py b/tasks.py index 25ccd9adf6..b9fa4c8cb3 100644 --- a/tasks.py +++ b/tasks.py @@ -76,6 +76,7 @@ def _detect_space(repo, branch=None, yes=False): ('stage', lambda _, branch: branch.startswith('release')), ('dev', lambda _, branch: branch == 'develop'), # Uncomment below and adjust branch name to deploy desired feature branch to the feature space + ('feature', lambda _, branch: branch == 'innovaton/datatables-for-legal-canonical'), # ('feature', lambda _, branch: branch == '[BRANCH NAME]'), )
Role