diceline-chartmagnifierquestion-marktwitter-whiteTwitter_Logo_Blue

Today I Learned

Workaround for storage event not triggering in the originator window

Whenever a value is set in localStorage, a storage event will be dispatched on all other windows from the same origin. The event is not fired or catchable in the originator window when it is modified through a script.

This was a problem because I wanted to be able to have an Elm subscription as the only source of truth for my session.

In order to achieve this, I'm mimicking the storage event from within the command port as soon as the message is received through the port.

app.ports.commandPort.subscribe(session => {
  localStorage.session = JSON.stringify(session);
  app.ports.subscriptionPort.send(localStorage.session);
});
window.addEventListener(
    "storage",
    event => {
      if (event.storageArea === localStorage && event.key === "session") {
        app.ports.subscriptionPort.send(event.newValue);
      }
    },
    false
);

And in Elm:

port subscriptionPort : (Encode.Value -> msg) -> Sub msg
port commandPort : Maybe Encode.Value -> Cmd msg

How to fix render-blocking video resource download on Safari

This is related to the MOOV atom that contains all the metadata and information about the frame locations other important information the browser needs to know about the video. For some reason, all other major browsers load it with no issues but Safari prefers to wait until the whole resource has downloaded in order to decide what to do with it.

For mp4 files, downloading FFMPEG and running the following command solved my issue:

./ffmpeg -y -i source.mp4 -movflags faststart dest.mp4

What it does is that it takes the MOOV atom from the end and adds it right at the start.

Extend Ecto's query API with your own macros

Imagine for a second this is something you're using a lot when programming Elixir and Phoenix:

Repo.one(
    from u in User,
        where: fragment("lower(?)", u.email) == ^email
)

You can write your own Elixir macro to improve your flow.

defmacro lower(arg) do
    quote do: fragment("lower(?)", unquote(arg))
end

Then your query can be rewritten like this:

Repo.one(
    from u in User,
        where: lower(u.email) == ^email
)

Advance Custom Fields' textarea newline behaviour in Wordpress

Have you ever wondered why ACF's textarea field adds <br>s in your frontend html instead of a paragraph tag? An this happens in spite of the explicit newline settings on the fields

It turns out this is the default behaviour and it's a rather common pitfall for many ACF newcomers.

Here's the deal:

Hit Enter twice for a paragraph p.
Hit it just once for a regular single line break <br>.

The importance of expressive, namespaced html attributes

Here's another reminder why expressive, namespaced ids are important. This time is about a label's for attribute.

<input id="phone">
<label for="phone"></label

This would work just as expected unless, for example, we have a svg sprite at the beginning of the document that includes an svg with a "phone" id.

<symbol id="phone" viewBox="0 0 61.4 48">...</symbol>
...
<input id="phone">
<label for="phone"></label

In this case, the label's for will match the first in a top-down order that has the target id.

And you will never know why clicking the label won't trigger the input.

You can write better jQuery. A DRY approach to multiple configurations

From this
$('.multiSelectOne').multiselect({
    buttonClass: 'btn btn-default',
    buttonWidth: '100%',
    ...
});
$('.multiSelectTwo').multiselect({
    buttonClass: 'btn btn-default',
    buttonWidth: '100%',
    nonSelectedText: '---',
    ...
});
To This
<select class="js-multiselect" 
    data-include-select-all-option="true" 
    data-all-selected-text="All">
    <option></option>
</select>
$('.js-multi-select).each(function () {
    let options = {};

    Object.entries($(this).data())
        .map(property => options[property[0]] = property[1]);

  $(this).multiselect(options);

}

And never go back for adjustments in the script file ever again.

.times in JavaScript

Never modify JavaScript's standard built-in objects. That's what they say.

But you're at this hackathon stuck with JS missing Ruby's .times iterator and that's what JS's prototypes are for after all.

Here's how you do it:

String.prototype.times = function (n) {
    for (var i = 0; i < parseInt(this); i++) {
        n();
    }
}
var myFunc = function () { console.log('Hello World') }
"2".times(myFunc)

Output:

"Hello World"
"Hello World"