Thursday, January 10, 2019

CSS: frequently used selectors

Basic selectors 

Wildcard selector: selects all elements
* {}
Type selector: selects all elements of the given type
div {}
Attribute selector ([]): selects all elements that has the given attribute
[src] {}
ID selector (#): selects the element with the given ID attribute
#menu {} /* or [id="menu"] {} */
Class selector (.): selects all elements with the given class attribute
.centered {} /* or [class~="centered"] {} */

Selector grouping

selector grouping (,): enables to specify common values in one place
div, #menu, .centered {}

Selector chaining

Selector chaining
div.#menu.centered[name="Menu"]:first-child::first-letter {}

Attribute value selectors

[attribute="value"] selector: selects all elements with the specified attribute and value
[target="_blank"] {}
[attribute~="value"] selector: selects all elements whose attribute value contains the specified whole word.
[title~="flower"] {}
[attribute|="value"] selector: selects all elements whose attribute value starts with the specified value, the value being a whole word or the first part of a hyphenated word.
[class|="top"] {}
[attribute^="value"] selector: selects all elements whose attribute value begins with the specified value. (like in regex)
[class^="top"] {}
[attribute$="value"] selector: selects all elements whose attribute value ends with the specified value. (like in regex)
[class$="test"] {}
[attribute*="value"] selector: selects all elements whose attribute value contains the specified value.
[class*="te"] {}

Selector combination

Descendant selector (space): matches all elements that are descendants of a specified element
div p {}
Child selector (>): selects all elements that are the immediate children of a specified element
div > p {}
Adjacent sibling selector (+): selects all elements that are the adjacent siblings of a specified element
div + p {}
General sibling selector (~): selects all elements that are siblings of a specified element
div ~ p {}

Monday, October 8, 2018

Migrating from Dragula to Shopify/Draggable/Sortable

In the following code snippets the variable draggable refers to a Draggable.Sortable instance.
You can also check out the fiddle.

Add revertOnSpill functionality to Sortable

var outContainer;
draggable.on('drag:out:container', (e) => {
 outContainer = e.data.overContainer;
});
draggable.on('sortable:stop', (e) => {
 var newContainer = e.data.newContainer;
  var spill = outContainer && outContainer === newContainer;
  if (spill) {
    var oldContainer = e.data.oldContainer;
    var oldContainerChildren = draggable.getDraggableElementsForContainer(oldContainer);
    var emptyOldContainer = !oldContainerChildren.length;
    var source = e.data.dragEvent.data.source;
    if (emptyOldContainer) {
     oldContainer.appendChild(source);
    } else {
      var oldIndex = e.data.oldIndex;
     oldContainer.insertBefore(source, oldContainer.children[oldIndex]);
    }    
  }
});

Figuring out Dragula library usage

The library in use: https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.js
plus its CSS: https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.css

Default configuration

HTML body content

<ul class="container">
<li class="draggable">1</li>
<li class="draggable">2</li>
<li class="draggable">3</li>
</ul>
<ul class="container">
<li class="draggable">1</li>
<li class="draggable">2</li>
<li class="draggable">3</li>
</ul>
<ul class="container">
<li class="draggable">1</li>
<li class="draggable">2</li>
<li class="draggable">3</li>
</ul>

JavaScript content

var containers = Array.prototype.slice.call(document.querySelectorAll('.container'));
var drake = window.dragula(containers);

How it looks like

With its CSSWithout its CSS
See the fiddle for yourself!

Figuring out Shopify/Draggable/Sortable library usage

The library in use: https://cdn.jsdelivr.net/npm/@shopify/draggable@1.0.0-beta.8/lib/draggable.bundle.js

Default configuration

The following plugins come with Draggable by default:
  • Announcement - announcing draggable events for a screenreader.
  • Focusable - adds tabindex to all draggable and container elements and thus makes them focusable
  • Mirror - creates a similar element to the original that will follow the cursor
  • Scrollable - scrolls the container while dragging when container edge is reached
Sortable is built on top of Draggable, so it has also all of this.

HTML body content

<ul class="container">
<li class="draggable">1</li>
<li class="draggable">2</li>
<li class="draggable">3</li>
</ul>
<ul class="container">
<li class="draggable">1</li>
<li class="draggable">2</li>
<li class="draggable">3</li>
</ul>
<ul class="container">
<li class="draggable">1</li>
<li class="draggable">2</li>
<li class="draggable">3</li>
</ul>

JavaScript content

var containers = document.querySelectorAll('.container');
var draggable = new window.Draggable.Sortable(containers, {
  draggable: '.draggable'
});

How it looks like

See the fiddle for yourself!

Friday, August 3, 2018

Developing Gramps on Ubuntu 16.04

Gramps is an open-source genealogy research tool written in Python3.

If you want to develop it on Windows, here are the instructions to do that.

To get started you'll need to read through a lot of documentation.
As for Python3 these can help:

Dependencies needed for Gramps

...are listed in the README.md:

EDIT: I just noticed this in the Getting Started and it might work instead of all those individual installations below, but you have to enable source code sources before you can do it: apt-get build-dep gramps

Instructions for Ubuntu 16.04:
  • Python 3.2 or greater: already installed
    • install python3-pip for further usage: sudo apt-get install python3-pip
  • GTK 3.10 or greater: already installed
  • pygobject 3.12 or greater: install it by running the following command from terminal:
    sudo apt install python-gi python-gi-cairo python3-gi python3-gi-cairo gir1.2-gtk-3.0
  • GObject Introspection bindings:
    • cairo 1.13.1 or greater: already installed (libcairo2)
    • Pycairo 1.13.3 or greater: already installed (python-cairo)
    • pango: already installed (libpango-1.0-0, libpango1.0-0)
    • pangocairo: already installed (libpangocairo-1.0-0)
    • librsvg2: already installed (librsvg2-2)
    • xdg-utils: already installed (xdg-utils)
    • bsddb3:
      • install BerkeleyDB dev package: sudo apt-get install libdb5.3-dev
      • install bsddb3: pip3 install bsddb3 --user
    • sqlite3: should be already installed with python.
  • language-pack-gnome-xx: i.e.: sudo apt-get install language-pack-gnome-en
  • osmgpsmap: 
    • install osmgpsmap: sudo apt-get install libosmgpsmap-1.0-1
    • and the python bindings: sudo apt-get install gir1.2-osmgpsmap-1.0
  • Graphviz: sudo apt-get install graphviz
  • PyICU: 
    • install ICU dev package: sudo apt-get install libicu-dev
    • and PyICU: pip3 install pyicu --user
  • Ghostscript: already installed
  • GExiv2: to get rid of the error popup when running Gramps
    • sudo apt-get install libgexiv2-2
    • sudo apt-get install gir1.2-gexiv2-0.10

Try what you cooked

  • download: git clone https://github.com/gramps-project/gramps.git Gramps
  • build: python3 setup.py build
  • DON'T INSTALL IT! (that would be python3 setup.py install)
  • run: python3 Gramps.py

Tuesday, July 31, 2018

How to subtract number of years, months and day from dates before 1900 in Google Spreadsheets?

Apparently Google Spreadsheet in incapable of handling dates before 1900 in the DATE, YEAR, MONTH, DAY functions.
So while in LibreOffice you can do this:
=DATE(YEAR(A1)-B1, MONTH(A1)-C1, DAY(A1)-D1)
where A1 is a date before 1900 and B1, C1, D1 are integers for the years, months, days to subtract
in Google Spreadsheet this results in a #NUM! error.

A workaround would be:
YEAR: =DATEDIF(-693990,A1,"Y")
MONTH: =DATEDIF(-693990,A1,"YM")
but this does not work properly with days.
A different way to put it is:
YEAR: =YEAR(A1+693961)-1900
MONTH: =MONTH(A1+693961)
DAY: =DAY(A1+693961)

However this does not help with subtracting and reconstructing the date.
So my workaround was to add a new spreadsheet function, because that can be written in javascript and these limitations do not apply.

From Tools > Script editor create a new script. Paste the following function and from Run > Test as add-on... add it to the sheet you need it in.

function dateSubtract(originalDate, yearsToSubtract, monthsToSubtract, daysToSubtract) {
  var date = new Date(originalDate);  
  date.setDate(date.getDate() - daysToSubtract);
  date.setMonth(date.getMonth() - monthsToSubtract);
  date.setFullYear(date.getFullYear() - yearsToSubtract);
  return date;
}
Than in the spreadsheet you can use this function like this:
=DATESUBTRACT(A1, B1, C1, D1)

What did I need this for?
In genealogy research the death records might indicate the age of the person in a years, months, days format. I collected some of these records in a spreadsheet and wanted to calculate the supposed birth date of the deceased.