diff --git a/README.md b/README.md index 997e7c3..905f61f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ ### Development Installation django-admin startproject languagestrings -cd languagestrings sudo docker-compose up -d sudo docker exec -it web_1 python manage.py startapp strings sudo chown -R $USER:$USER . @@ -13,3 +12,4 @@ sudo chown -R $USER:$USER . docker exec -it languagestrings_web_1 python manage.py createsuperuser 2. Create Group with WebApp via Admin 3. Import any gaap data using import from Web + diff --git a/src/languagestrings/settings.py b/src/languagestrings/settings.py index b1b43dc..73bd227 100644 --- a/src/languagestrings/settings.py +++ b/src/languagestrings/settings.py @@ -29,7 +29,7 @@ ALLOWED_HOSTS = ['*'] # Application definition -APP_NAME = 'BETAGO' +APP_NAME = 'SPREADSHEET' VERSION = "1.8.0-dev" DESCRIPTION = "Localization Text Management Application" @@ -217,4 +217,4 @@ ''' Uploaded Excel Files ''' -MEDIA_ROOT = '/data/uploads' \ No newline at end of file +MEDIA_ROOT = '/data/uploads' diff --git a/src/strings/templates/strings/js/commonFunction.js b/src/strings/templates/strings/js/commonFunction.js index 538d7fb..641bec6 100644 --- a/src/strings/templates/strings/js/commonFunction.js +++ b/src/strings/templates/strings/js/commonFunction.js @@ -5,21 +5,22 @@ var active=false; var hTables = {}; var tempData = {}; var title; +var confirmResetHandsonTable; var confirmHandsonTable; var badHtmlHandsonTable; var savedHandsonTable; -var mainPanel; -var confirmPanel; -var badHtmlPanel; -var savedPanel; -var notSavedPanel; +var hotNotSavedTable; var productId; var save; var confirm; var cancel; var days; var language; -var hotConfirm; +var hotBadElem; +var hotConfirmElem; +var hotResetElem; +var hotSavedElem; +var hotNotSavedElem; function getCookie(name) { var cookieValue = null; @@ -38,20 +39,22 @@ function getCookie(name) { } function confirm() { // save all cell's data - var tablename = $("#tablename").val(); - var url = '/localtext/products/'+$("#productId").val()+'/confirm'; + const tablename = $("#tablename").val(); + const url = '/localtext/products/'+$("#productId").val()+'/confirm'; + const save = hotConfirmElem.getData(); + const reset = hotResetElem.getData(); $.ajax({ url, type: 'POST', - data: JSON.stringify(hotConfirm.getData()), + data: JSON.stringify(save.concat(reset)), "beforeSend": function(xhr, settings) { $.ajaxSettings.beforeSend(xhr, settings); }, success: function (results) { showTab(document.getElementById('tab-review')); // update page loads - hotSavedTable.loadData(results.saved); - hotNotSavedTable.loadData(results.notSaved); + hotSavedElem.loadData(results.saved); + hotNotSavedElem.loadData(results.notSaved); }, error: function(error) { alert("Error: " + error.statusText); @@ -71,14 +74,15 @@ function save(elem, pk, product, category) { $.ajaxSettings.beforeSend(xhr, settings); }, success: function (results) { - var tab = document.getElementById('tab-saving'); - showTab(tab); - hotConfirm.loadData(results.data); - if (!results.data.length) { + if (!results.data.length && !results.reset.length) { $("#confirm").hide(); } + var tab = document.getElementById('tab-saving'); + showTab(tab); // 4. errors - hotBadHtml.loadData(results.error); + hotConfirmElem.loadData(results.data); + hotResetElem.loadData(results.reset); + hotBadElem.loadData(results.error); $("#productId").val(results.product); $("#tablename").val(category); }, @@ -271,15 +275,16 @@ function editedCellRenderer(instance, td, row, col, prop, value, cellProperties) Handsontable.renderers.registerRenderer('editedCellRenderer', editedCellRenderer); function customCellRenderer(instance, td, row, col, prop, value, cellProperties) { Handsontable.renderers.TextRenderer.apply(this, arguments); - if (col === 5 && {% if editEnglish %}false{% else %}true{%endif %}) { - return; - } if (!value || value === '') { - td.style.background = '#EEEEEE'; + td.style.background = 'silver'; return; } if (col > 4 && !hiddenColumns.includes(col) && new Date(instance.getDataAtCell(row, col + 1)) <= new Date(instance.getDataAtCell(row, 4)) ) { - td.style.background = '#FF0000'; + td.style.background = 'red'; + } + if (cellProperties.isModified === true) { + td.style.background = 'blue'; + td.style.color = 'white'; } }; Handsontable.renderers.registerRenderer('customCellRenderer', customCellRenderer); @@ -288,7 +293,15 @@ function plainRenderer(instance, td, row, col, prop, value, cellProperties) { td.className = 'plain'; }; Handsontable.renderers.registerRenderer('plainRenderer', plainRenderer); - +function scrubRenderer(instance, td, row, col, prop, value, cellProperties) { + Handsontable.renderers.TextRenderer.apply(this, arguments); + const pattern = new RegExp(/(\w+)_modified_at/, 'i'); + const m = pattern.exec(value); + if (m) { + td.innerHTML = m[1]; + } +}; +Handsontable.renderers.registerRenderer('scrubRenderer', scrubRenderer); function encodeQueryData(data) { var ret = []; for (let d in data) diff --git a/src/strings/templates/strings/js/handsonTables.js b/src/strings/templates/strings/js/handsonTables.js index f4f5164..7b6582e 100644 --- a/src/strings/templates/strings/js/handsonTables.js +++ b/src/strings/templates/strings/js/handsonTables.js @@ -4,15 +4,11 @@ var $$ = function(id) { title = $$('title'), // handson tables confirmHandsonTable = $$('confirmHandsonTable'), +confirmResetHandsonTable = $$('confirmResetHandsonTable'), badHtmlHandsonTable = $$('badHtmlHandsonTable'), savedHandsonTable = $$('savedHandsonTable'), notSavedHandsonTable = $$('notSavedHandsonTable'), -// panels -mainPanel = $$('mainPanel'), -confirmPanel = $$('confirmPanel'), -badHtmlPanel = $$('badHtmlPanel'), -savedPanel = $$('savedPanel'), -notSavedPanel = $$('notSavedPanel'), + productId = $$('productId'), save = $$('save'), confirm = $$('confirm'), @@ -26,7 +22,7 @@ $('input:file').change(function(){ } }); -hotSavedTable = new Handsontable(savedHandsonTable, { +hotSavedElem = new Handsontable(savedHandsonTable, { colHeaders: ['ID', 'Language', 'Before', 'After'], rowHeaders: true, manualColumnResize: [300, 100, 300, 300], @@ -56,8 +52,7 @@ hotSavedTable = new Handsontable(savedHandsonTable, { }, ] }); - -hotNotSavedTable = new Handsontable(notSavedHandsonTable, { +hotNotSavedElem = new Handsontable(notSavedHandsonTable, { colHeaders: ['ID', 'Language', 'Before', 'After', 'Errors'], rowHeaders: true, manualColumnResize: [300, 100, 200, 200, 200], @@ -93,7 +88,7 @@ hotNotSavedTable = new Handsontable(notSavedHandsonTable, { ] }); -hotBadHtml = new Handsontable(badHtmlHandsonTable, { +hotBadElem = new Handsontable(badHtmlHandsonTable, { colHeaders: ['ID', 'Language', 'Before', 'After', 'Reason'], rowHeaders: true, manualColumnResize: [300, 100, 200, 200, 200], @@ -128,8 +123,37 @@ hotBadHtml = new Handsontable(badHtmlHandsonTable, { } ] }); +hotResetElem = new Handsontable(confirmResetHandsonTable, { + colHeaders: ['ID', 'Language', 'Previous', 'Timestamp'], + rowHeaders: true, + manualColumnResize: [300, 100, 300], + manualRowResize: true, + fixedColumnsLeft: 1, + stretchH: 'last', + preventOverflow: 'horizontal', + currentRowClassName: 'currentRow', + columns: [ + { + data: 'stringid', + readOnly: true, + }, + { + data: 'field', + readOnly: true, + renderer: 'scrubRenderer' + }, + { + data: 'before', + readOnly: true, + }, + { + data: 'after', + readOnly: true, + } + ] +}); -hotConfirm = new Handsontable(confirmHandsonTable, { +hotConfirmElem = new Handsontable(confirmHandsonTable, { colHeaders: ['ID', 'Language', 'Before', 'After'], rowHeaders: true, manualColumnResize: true, @@ -206,19 +230,7 @@ hTables["{{ product.category }}"] = new Handsontable($$('handsonTable_'+ "{{ pro preventOverflow: 'both', currentRowClassName: 'currentRow', columnSorting: true, - beforeColumnSort: function (col, order) { - sortTable('{{ product.category }}', col, order, function() { - return false; - }); - }, sortIndicator: true, - cells: function (row, col, prop) { - var cellProperties = {}; - if (col > 2) { - cellProperties.renderer = "customCellRenderer"; - } - return cellProperties; - }, columns: [ { data: 'stringid', @@ -234,14 +246,16 @@ hTables["{{ product.category }}"] = new Handsontable($$('handsonTable_'+ "{{ pro }, { data: 'Korea', - {% if not editKorea %}readOnly: true{% endif %} + {% if editKorea %}renderer: "customCellRenderer" + {% else %}readOnly: true{% endif %} }, { data: 'Korea_modified_at' }, { data: 'English', - {% if not editEnglish %}readOnly: true{% endif %} + {% if editEnglish %}renderer: "customCellRenderer" + {% else %}readOnly: true{% endif %} }, { data: 'English_modified_at' @@ -249,38 +263,56 @@ hTables["{{ product.category }}"] = new Handsontable($$('handsonTable_'+ "{{ pro {% for name in publishers %} ,{ data: '{{ name }}', + renderer: "customCellRenderer" }, { data: '{{ name }}_modified_at' } {% endfor %} ], - afterChange: function (change, source) { + afterSelection: function(row, col, row2, col2) { + const instance = this; + const skip = instance.propToCol('Korea'); + const after = new Date().toISOString(); + for (let i = row; i <= row2; i++) { + for (let j = col; j <= col2; j+=2) { + if (skip >= j) continue; + const field = instance.colToProp(j+1); + const stringid = instance.getDataAtCell(i, 0); + const before = instance.getDataAtCell(i, j+1); + instance.setDataAtCell(i, j+1, after); + if (instance.getDataAtCell(i, j) !== '') { + tempData["{{ product.category }}"][`${stringid}.${field}`] = { stringid, field, before, after }; + } + } + } + }, + afterChange: function(changes, source) { if (source === 'loadData') { return; //don't save this change } - if (change !== null) { - var instance = this; - $(change).each(function () { - // change the color of edited cell - // changedData = [row, col, before, after] - var changedData = this; - if (changedData[2] === changedData[3]) { - return; // don't do anything is no change - } - var cell = instance.getCell(changedData[0], instance.propToCol(changedData[1])); - if (cell) { - cell.style.color = '#0000FF'; - } - // replace the row with stringid - var stringid = instance.getDataAtCell(changedData[0], 0); - if (tempData["{{ product.category }}"][stringid+'.'+changedData[1]]) { - changedData[2] = tempData["{{ product.category }}"][stringid+'.'+changedData[1]]['before']; - } - // should change the color of cell??? - tempData["{{ product.category }}"][stringid+'.'+changedData[1]] = { 'stringid': stringid, 'field': changedData[1], 'before': changedData[2], 'after': changedData[3] }; - }); - } + //"changes" is a 2D array + const instance = this; + changes.forEach(([row, prop, before, after]) => { + const col = instance.propToCol(prop); + if (hiddenColumns.includes(col)) { + return; + } + if (before === after) { + return; // don't do anything is no change + } + //mark cell as modified + const cellProperties = instance.getCellMeta(row, col); + cellProperties.isModified = true; + // store changed data + const stringid = instance.getDataAtCell(row, 0); + if (tempData["{{ product.category }}"][`${stringid}.${prop}`]) { + before = tempData["{{ product.category }}"][`${stringid}.${prop}`]['before']; + } + // should change the color of cell??? + tempData["{{ product.category }}"][`${stringid}.${prop}`] = { stringid, field: prop, before, after }; + }); + instance.render(); } }); {% endfor %} diff --git a/src/strings/templates/strings/save.html b/src/strings/templates/strings/save.html index 32b5ea3..4d45885 100644 --- a/src/strings/templates/strings/save.html +++ b/src/strings/templates/strings/save.html @@ -28,6 +28,20 @@ +