Beluga

Members
  • Content Count

    482
  • Joined

  • Last visited

  • Days Won

    4

Beluga last won the day on September 30 2018

Beluga had the most liked content!

Community Reputation

403 Excellent

About Beluga

  • Rank
    Sr. Member

Recent Profile Visitors

7,374 profile views
  1. Well, RockGrid and RockFinder are still essential to make it work with PW no matter which JS lib we use I will look into donating to Tabulator next to cover all bases. Regarding the earlier discussion about creating a module that makes RockGrid and Apex Charts talk to each other: I might look into it after my plate is cleared of various stuff (such as launching this proverb project).
  2. Sorry and thanks. Fixed the semantic ui blunder (feel free to use any of the themes offered by Tabulator and hack the .module.php accordingly). Added example to readme. The example references variables and functions that you do not have access to (codesObj, afterFilter). It is not meant to be used as-is, but as a reference. I can clarify this later in the example comments. https://github.com/mestaritonttu/FieldtypeRockGrid/tree/tabulator As said, this is a hack-in-progress and the start of a discussion, so I am ignoring the plugin errors right now. Regarding your questions on server-side validation and buttons, I do not have answers. I can only point you to http://tabulator.info/docs/4.1/validate http://tabulator.info/docs/4.1/update Perhaps you can build a custom validator that does what you want. See the last entry "Delete Row" in the Update section.
  3. Pinging the grid heads: @bernhard @jmartsch @mel47 @dragan @szabesz In short, I have modified RockGrid to work with Tabulator instead of ag-Grid. I left out ajax and plugins for now. I fully understand, if Bernhard is not interested in switching the "engine" of RockGrid, but at least it is food for thought and a proven alternate solution The "HackGrid" can be found here: https://github.com/mestaritonttu/FieldtypeRockGrid/tree/tabulator Longer story: During the last week of November I ran into Tabulator by accident. It occurred to me "someone in the early days of RockGrid suggested some other solution". I searched the PW forums and found out that someone was szabesz and the solution was Tabulator! Now, the important thing here is that since the PW forum discussion (April 2018), Tabulator has seen significant changes. It got rid of jQuery & jQuery UI dependencies and added a ton of features. Why have I decided to switch to Tabulator? Lately ag-Grid has left a bad taste in my mouth - the performance of its row autoheight sucks, so I had to work around it - inside the autoheight workaround I had to add another workaround to avoid an infinite event triggering/listening loop - the closed nature is showing its bad sides more and more, like not being able to see the content in their enterprise bug tracker So what do we get with Tabulator? - row autoheight that just works - dropdown filter out of the box, so I don't need my awkward external filter - features matching the enterprise version of ag-Grid, such as http://tabulator.info/docs/4.1/select#setup-range http://tabulator.info/docs/4.1/group http://tabulator.info/docs/4.1/download#xlsx http://tabulator.info/docs/4.1/tree http://tabulator.info/examples/4.1#nested-tables http://tabulator.info/docs/4.1/clipboard What are the philosophical differences? In the words of the Tabulator main dev, ag-Grid focuses on being a fully functional spreadsheet while Tabulator goes more down the route of interactive table. I would have announced this already nearly 3 weeks ago, but caught pneumonia Use on the RockGrid side is really not much different. Mostly just using col.title instead of col.headerName. For some reason the grid.js stuff is lost (to get the field titles), but I did not have time to investigate.
  4. I just now went looking in their issue trackers and found this in their enterprise support tracker (in category tab "Standard Feature Requests): AG-1202 Allow rendering rows dynamically adapting their height to their content That does sound like what I want, but thanks to their closed system, we have no way of knowing the exact contents of the issue! There is also this, which would only be for paying customers: Enterprise Row Model AG-1039 Allow dynamic row heights and maxBlocksInCache This is in Parked category: AG-2228 Allow lazy loading of rows when using autoHeight, ie on scroll to configured amount of rows, append n more rows at the bottom So looks like this stuff is on their radar (which I would have assumed based on how they acknowledge the pain point in their docs). Let's wait and see and for now enjoy my hack All this hacking does have the effect of improving my self-confidence and wanting to learn JS more deeply
  5. Earlier in this topic I asked about autoHeight for rows. Now I have created a nice and only slightly hacky solution for it (no hacks in libs, just working around stuff). The existing simple option is not acceptable in our use case, because even the official docs say: When using autoHeight for 35k rows, I got twice the message "the web page seems to be running slow, do you want to stop it". I don't even dare to imagine what would happen on an old smartphone. The obvious (to me) solution was to calculate automatic height on demand only for the handful of rows displayed at a time. This has to happen on page load, on filtering and on pagination navigation. Due how pagination is implemented, a hoop had to be jumped through with it as well (to avoid an infinite loop). To be clear: the ag-Grid API offered no immediately useful event I could listen to! viewportChanged sounded like it would work, but in practice it failed to cover page navigation. var paginationAttached = false; var paginationHandler = function (event) { rowHeighter(grid, event); } function rowHeighter(grid, event) { // calculate row height for displayed rows to wrap text var cols = [ grid.gridOptions.columnApi.getColumn("code"), grid.gridOptions.columnApi.getColumn("variation") ]; grid.gridOptions.api.getRenderedNodes().forEach(function(node) { node.columnController.isAutoRowHeightActive = function() { return true; }; node.columnController.getAllAutoRowHeightCols = function() { return cols; }; node.setRowHeight(grid.gridOptions.api.gridOptionsWrapper.getRowHeightForNode(node)); }); // if listening to paginationChange, onRowHeightChanged creates an infinite loop, so work around it if(paginationAttached === false) { grid.gridOptions.api.onRowHeightChanged(); grid.gridOptions.api.addEventListener('paginationChanged', paginationHandler); paginationAttached = true; } else { grid.gridOptions.api.removeEventListener('paginationChanged', paginationHandler); grid.gridOptions.api.onRowHeightChanged(); grid.gridOptions.api.addEventListener('paginationChanged', paginationHandler); } } You can see here that I had to brute-force overwrite a couple of functions in the ag-Grid row height calculation logic. I define the columns I want to target for the auto height and trick the getAllAutoRowHeightCols to just provide them. My filter event listener in RockGridItemAfterInit is grid.gridOptions.api.addEventListener('filterChanged', function(event) { rowHeighter(grid, event); }); A CSS rule is also required: div[col-id="variation"].ag-cell, div[col-id="code"].ag-cell { white-space: normal; } Using automatic row heights brought about an issue with the default fixed height grid: a wild scrollbar appeared! I found out I can make the grid height adapt, putting this into RockGridItemBeforeInit: // pagination with a fixed number of rows and adapting grid height grid.gridOptions.paginationAutoPageSize = false; grid.gridOptions.paginationPageSize = 15; grid.gridOptions.domLayout = 'autoHeight'; Then I decided the pagination controls should live above the grid, because otherwise their position will change annoyingly whenever the grid height changes. Putting this into RockGridItemAfterInit: // move the pagination panel to the top, because the dynamic row heights would change its position at the bottom var pagingPanel = document.querySelector('.ag-paging-panel'); var rootWrapper = document.querySelector('.ag-root-wrapper'); rootWrapper.prepend(pagingPanel);
  6. Beluga

    GD supports webp: http://php.net/manual/en/image.installation.php
  7. Beluga

    Firefox 65 will support WebP. Will be out in January 2019.
  8. Beluga

    Another possibility: https://wodby.com/docs/stacks/php/local/ I use one of their containers for my more exotic Docker setup. I like to keep my PW files (and MariaDB database) on my host so everything is clearer.
  9. Beluga

    Great, then installing gutenprint package should be enough! http://gimp-print.sourceforge.net/p_Supported_Printers.php
  10. Beluga

    Can you reveal the model? I have wrestled with a couple of Canons. One was easy as just installing gutenprint package did the trick. Another printer-related annoyance in Manjaro is that the user is not in "sys" group by default and thus is prevented access to fiddling with the printer in the CUPS admin. This does the trick: usermod -a -G sys yourusername
  11. Beluga

    I use Arch Linux myself and have installed Manjaro for various family members & friends. KDE for desktop environment. Even though Arch/Manjaro is the bleeding edge, breakage is rare. Most problems are related to printers and that is just a fact of life no matter which operating system we use. I use Arch for a couple of servers as well.
  12. I am using ApexCharts.js, which is kind of a spiritual successor to Chartist.js in that they both produce SVG charts. I am experimenting with what is possible, trying to figure out visualisations of the data that would be useful and attractive. Here is a screenshot of ApexCharts playing together in real time with RockGrid filtering (edit: nevermind the incorrect/repeating data labels, I only noticed and corrected later): We see a stacked bar chart representation of the number of literature references per filtered proverb type. I intend to split the thing into separate charts for each of the 13 top level categories (ApexCharts unfortunately does not support multiple series of stacked bars in a single chart). This will make it readable even with the unfiltered view of all 325 proverb types. It was quite convoluted to get the libraries to play together - grid.gridOptions.api.getModel().rootNode.childrenAfterFilter did not want to yield its contents, but guarded it like a jealous dragon. To get access to the data, I had to brute-force dispatch an input event like so: var inputTarget = document.querySelector('.ag-floating-filter-full-body:first-child input'); var inputEvent = new Event('input', {'bubbles': true, 'cancelable': true}); // have to use delta timing to delay the input event - in // case of big existing CPU load, it will fire too soon! var start = new Date().getTime(); setTimeout(function() { var now = new Date().getTime(), delta = now-start; inputTarget.dispatchEvent(inputEvent); },500); Then, to initialise the Apex chart in proper order, I had to wrap its stuff into a function. I called the function from my afterFilter: function afterFilter(grid) { var filterKids = grid.gridOptions.api.getModel().rootNode.childrenAfterFilter; var mapCodes = filterKids.map(x => x.data.code); var countedCodes = mapCodes.reduce((r,k)=>{r[k]=1+r[k]||1;return r},{}); apexseries = Object.entries(countedCodes).map(([p, v]) => ({'name':p, 'data':[v]})); var apexdiv = document.querySelector("#chart"); if(!apexdiv.hasChildNodes()) { apexi(); } else { ApexCharts.exec('proverbs', 'updateSeries', apexseries); } }
  13. Thanks for the free support I got it working with the syntax grid.gridOptions.api.addEventListener('filterChanged', function() { afterFilter() }); This allows me to pass the grid object to afterFilter and then do interesting stuff with grid.gridOptions.api.getModel().rootNode.childrenAfterFilter I am going to mess around with dynamic charting!!
  14. I am having trouble with events. In my RockGridItemAfterInit block I have grid.gridOptions.onFilterChanged = afterFilter(); Then outside it the function function afterFilter() { console.info("filter changed"); } The function fires exactly once - when the grid is initialised. It does not fire when the filters are changed. If I instead use grid.gridOptions.api.addEventListener('filterChanged', afterFilter()); It fires when the grid is initialised and when I change a filter, I get this in the console (the first time, on further tries I get nothing): TypeError: t is not a function ag-grid.min.js:26:2395 p</e.prototype.dispatchToListeners/</< http://0.0.0.0/site/modules/FieldtypeRockGrid/lib/ag-grid.min.js:26:2395 p</e.prototype.flushAsyncQueue/< http://0.0.0.0/site/modules/FieldtypeRockGrid/lib/ag-grid.min.js:26:2814 forEach self-hosted:262:13 p</e.prototype.flushAsyncQueue http://0.0.0.0/site/modules/FieldtypeRockGrid/lib/ag-grid.min.js:26:2785 <anonymous> self-hosted:973:17 What am I doing wrong?
  15. Not really, so I guess my solution is perfect for my case