<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Sararellano on Medium]]></title>
        <description><![CDATA[Stories by Sararellano on Medium]]></description>
        <link>https://medium.com/@sararellano?source=rss-bf1d17647ac------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*ZepnlAQwoW5wjStzFTvj1w.png</url>
            <title>Stories by Sararellano on Medium</title>
            <link>https://medium.com/@sararellano?source=rss-bf1d17647ac------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 22:46:07 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@sararellano/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[AI Personal Historian]]></title>
            <link>https://sararellano.medium.com/ai-personal-historian-4776c2ddbde9?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/4776c2ddbde9</guid>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[software-developer]]></category>
            <category><![CDATA[full-stack-developer]]></category>
            <category><![CDATA[history]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Mon, 15 Jun 2026 06:31:00 GMT</pubDate>
            <atom:updated>2026-06-15T06:31:00.685Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Pz248TBvWoUhOv7Ml3pKNA.png" /><figcaption>AI Personal Historian</figcaption></figure><h3>I built a memory journal that asks you ONE question a day… then writes your biography</h3><p>Yes, you read that right. A robot that interviews you for a year and turns your messy answers into a beautiful life story.</p><p>Hi, I’m Sara 👋<br>I’m a developer who loves weird side projects. And this one? It’s probably the most personal thing I’ve ever built.</p><p>Meet Personal Historian, a private, snark-free, actually‑useful memory journal that doesn’t just store your answers. It <em>understands</em> them.</p><p>Let me explain why I built it, what it does, and the stack I used to make it happen.</p><h3>The problem with regular journals</h3><p>Most journaling apps are a blank page and a sad “how do you feel?” prompt.<br>That’s terrifying. I always feel like I have to write something deep, profound, and Instagram‑worthy.</p><p>So I thought: what if the app asks one tiny, specific question every day?<br>Not “tell me your life story”.<br>But:</p><ul><li><em>“What was your favourite toy as a kid?”</em></li><li><em>“Who was your first crush?”</em></li><li><em>“What’s a mistake you’re glad you made?”</em></li></ul><p>No pressure. Just one answer. 365 days.</p><h3>What Personal Historian actually does (the cool part)</h3><p>You sign up, and every day you get a new question. You answer it. That’s it.</p><p>But behind the scenes, my app goes full detective mode.</p><ul><li>It extracts people, emotions, lessons, and milestones from your answers (using a local AI model — more on that later).</li><li>It notices when you keep talking about the same person (e.g., <em>“your grandpa shows up a lot — tell me more about him”</em>).</li><li>After a few weeks, it can generate chapters like “My childhood” or “Lessons from my first job”.</li><li>And when you’re ready? It writes your entire biography in first person, like a little memoir.</li><li>You can export it as PDF, share “20 lessons my grandpa taught me”, or just keep it for yourself.</li></ul><p>It’s part journal, part AI ghostwriter, part time machine.</p><p>And it works offline. Yes, even on a plane.</p><h3>The stack (because I know you’re here for this)</h3><p>I wanted a modern, fast, and actually deployable stack — no magic black boxes.<br>Here’s what I used 👇</p><h3>Frontend</h3><ul><li>React 19 + TanStack Start (full‑stack framework with SSR and file‑based routing — way better than classic React Router for this kind of app)</li><li>Tailwind CSS 4 + Radix UI — because I’m lazy and I like beautiful, accessible components</li><li>Recharts for emotional timeline graphs</li><li>React Markdown + html2pdf.js — biography preview and PDF export</li></ul><h3>Backend &amp; database</h3><ul><li>Supabase (PostgreSQL + Auth + Row Level Security) — handles users, answers, analysis results, and recurring topics</li><li>All sensitive queries are protected — users can only see their own data</li></ul><h3>AI (the fun part)</h3><ul><li>Local Ollama with Qwen2.5‑Coder 7B during development</li><li>In production, the app uses Lovable AI (through a simple abstraction — I can swap providers in one line)</li><li>Prompts are short, temperature is low (0.15), and they always return clean JSON. No hallucinations, I promise.</li></ul><h3>Deployment</h3><ul><li>Vercel with Nitro preset — builds the TanStack Start app as serverless functions</li><li>GitHub for version control (obviously)</li><li>No vercel.json magic – everything is in vite.config.ts (you can check the repo)</li></ul><blockquote><em>Yes, it’s a full‑stack TypeScript app with SSR, offline support, and a local‑first AI. And it runs on a free Vercel plan. 😎</em></blockquote><h3>Why I’m proud of this (and you should be too if you build it)</h3><p>I didn’t just glue APIs together. I built:</p><ul><li>A question scheduler that never repeats the same prompt too soon</li><li>An offline answer queue with IndexedDB (syncs when you’re back online)</li><li>A streak + heatmap system that actually motivates you</li><li>Recurring topic detection — the AI notices patterns without being annoying</li><li>A first‑person biography generator that doesn’t sound like a robot</li></ul><p>And the whole thing is fast. Lighthouse scores &gt; 90, dark mode, keyboard accessible, and installable as a PWA.</p><h3>Would I use this myself?</h3><p>100%.<br>I’ve been answering questions for three weeks now, and yesterday the app asked: <em>“What smell reminds you of your childhood home?”</em><br>I wrote two paragraphs about my grandmother’s kitchen.</p><p>That’s the magic of small questions over time. You don’t realise you’re building a story until it’s already there.</p><h3>Try it, clone it, or just laugh at my over‑engineering</h3><p>You can play with the live version here:<br><a href="https://ai-personal-historian.vercel.app/">https://ai-personal-historian.vercel.app</a></p><p>And the code is on GitHub (because of course it is).</p><p>— Sara<br><em>Developer who accidentally became a digital biographer</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4776c2ddbde9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JavaScript RegEx Cheatsheet]]></title>
            <link>https://sararellano.medium.com/javascript-regex-cheatsheet-fe019d11fca0?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/fe019d11fca0</guid>
            <category><![CDATA[regex]]></category>
            <category><![CDATA[javascript-tips]]></category>
            <category><![CDATA[javascript-regex]]></category>
            <category><![CDATA[regular-expressions]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Fri, 03 Jun 2022 11:15:51 GMT</pubDate>
            <atom:updated>2022-06-03T11:15:51.366Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*yJD-Nmi9XJ91-nSwujJl0w.gif" /><figcaption>JS regex cheatsheet</figcaption></figure><p>Hello!</p><p>I’ve found information about RegEx in JavaScript and I thought it would be interesting to share it with everyone and also, for me to save it and have it always available like a cheatsheet.<br>Also, to test everything I recommended you the page <a href="https://regex101.com/">https://regex101.com/</a></p><p>So… let’s start!</p><h3>What is RegEx?</h3><p>RegEx (regular expressions) are a series of symbols that will allow us to define search patterns in text strings.</p><h3>Regex in JavaScript</h3><p>In JavaScript, a RegEx is an object that describes a sequence of characters used for defining a search pattern, for example <em>/^a…s$/ </em>this regEx select any 5 letter string starting with “a” and ending with “s”:</p><ul><li>abs -&gt; no match</li><li>alias -&gt; match</li><li>Alias -&gt; no match</li></ul><p>There are two ways to create a RegEx :</p><p>1. Using a regular expression literal: consists of a pattern enclosed between “/”:</p><pre>const regularExp = /abc/;</pre><p>2. Using the RegExp() constructor function:</p><pre>const regularExp = new RegExp(&#39;abc&#39;);</pre><h3>Metacharacters</h3><p>There’re characters that are interpreted in a special way by a RegEx engine: [].^$*+?{}()\|</p><ul><li><strong>[]</strong></li></ul><p>Specify a set of characters you want to match:</p><pre>[abc] -&gt; &#39;Hello world&#39; -&gt; No matches<br>[abc] -&gt; &#39;Say goodbye&#39; -&gt; 3 matches<br>[a-e] -&gt; is same as [abcde]<br>[1-4] -&gt; is same as [1234]<br>[^abc] -&gt; means any character except a, b or c<br>[^0-9] -&gt; means any non-digit character</pre><ul><li><strong>.</strong></li></ul><p>A period “.” matches any single character (except newline ‘\n’)</p><pre>.. -&gt; means 2 characters -&gt; &#39;Ey&#39; -&gt; 1 Match<br>.. -&gt; &#39;abcd&#39; -&gt; 2 matches</pre><ul><li><strong>^</strong></li></ul><p>To check if a string <strong>starts</strong> with a specific character:</p><pre>^a -&gt; &#39;abc&#39; -&gt; match<br>^ac -&gt; &#39;abc&#39; -&gt; No match <br>^ab -&gt; &#39;abc&#39; -&gt; match</pre><ul><li><strong>$</strong></li></ul><p>To check if a string <strong>ends</strong> with a specific character:</p><pre>a$ -&gt; &#39;Sara&#39; -&gt; match<br>ab$ -&gt; &#39;Hello&#39; -&gt; no match<br>lo$ -&gt; &#39;Hello&#39; -&gt; match</pre><ul><li><strong>+</strong></li></ul><p>Matches <em>one or more</em> occurrences of the pattern left to it:</p><pre>he+l -&gt; &#39;hello&#39; -&gt; match<br>he+o -&gt; &#39;hello&#39; -&gt; no match (&#39;he&#39; has to be before &#39;o&#39;)<br>ma+n -&gt; &#39;man&#39; -&gt; matches<br>ma+n -&gt; &#39;mmaan&#39; -&gt; matches (it recognizes duplicate letters)</pre><ul><li><strong>?</strong></li></ul><p>Matches zero or one occurrence of the pattern left to it:</p><pre>he?l -&gt; &#39;hello&#39; -&gt; match<br>he?o -&gt; &#39;hello&#39; -&gt; no match<br>ma?n -&gt; &#39;man&#39; -&gt; match<br>ma?n -&gt; &#39;mmaan&#39; -&gt; no matches (it doesn&#39;t recognize duplicate letters)</pre><ul><li><strong>*</strong></li></ul><p>Matches <em>zero or more</em> occurrences:</p><pre>ma*n -&gt; &#39;woman&#39; -&gt; match<br>ma*n -&gt; &#39;main&#39; -&gt; No match (&#39;n&#39; has to be before &#39;ma&#39;)<br>ma*n -&gt; &#39;maaan&#39; -&gt; match (it recognizes duplicate letters)</pre><p><strong>+</strong> and <strong>*</strong> are very similar, but there is a little difference: <strong>*</strong> means zero-or-more, and <strong>+</strong> means one-or-more. So the difference is that the empty string would match the second expression but not the first (because the expression is optional).</p><ul><li><strong>{}</strong></li></ul><p><em>{n, m}</em> this means at least <strong>n</strong> and at most <strong>m</strong> repetitions of the pattern left to it:</p><pre>a{2,3} -&gt; &#39;abc saara&#39; -&gt; 1 match (saara)<br>a{2,3} -&gt; &#39;aabc saara&#39; -&gt; 2 matches<br>[0-9]{2,4} -&gt; &#39;ab123cxde&#39; -&gt; 1 match (123)<br>[0-9]{2,4} -&gt; &#39;12 and 345678&#39; -&gt; 3 matches (12, 3456, 78)</pre><ul><li><strong>()</strong></li></ul><p>It’s used to group sub-patterns. For instance, <em>(a|b|c)xz</em> match any string that matches either <strong>a</strong> or <strong>b</strong> or <strong>c</strong> followed by <strong>xz</strong></p><pre>(a|b|c)xz -&gt; &#39;abxz&#39; -&gt; 1 match (bxz)<br>(a|b|c)xz -&gt; &#39;axz cabxz&#39; -&gt; 1 matches</pre><ul><li><strong>|</strong></li></ul><p>Is used for alternation (or):</p><pre>a|b -&gt; &#39;abc&#39; -&gt; 2 matches<br>a|b -&gt; &#39;hello&#39; -&gt; no matches</pre><h3>Special Sequences</h3><p>Special sequences make commonly used patterns easier to write:</p><ul><li><strong>\A</strong></li></ul><p>Matches if the specified characters are at the start of a string:</p><pre>\Athe -&gt; ‘the sun’ -&gt; match <br>\Athe -&gt; ‘in the sun’ - not match</pre><ul><li><strong>\Z</strong></li></ul><p>Matches if the specified characters are at the end of a string:</p><pre>JavaScript\Z -&gt; ‘I like JavaScript’ -&gt; match<br>JavaScript\Z -&gt; ‘JavaScript is a frontend language’ -&gt; no match</pre><ul><li><strong>\b</strong></li></ul><p>Matches if the specified characters are at the beginning or end of a word:</p><pre>\bfoo -&gt; ‘a football team’ -&gt; match<br>foo\b -&gt; ‘a football team’ -&gt; no match<br>foo\b -&gt; ‘the afootest’ -&gt; no match</pre><ul><li><strong>\B</strong></li></ul><p>Matches if the specified characters aren’t at the beginning or end of a word. It’s the opposite of \b</p><pre>\Bfoo -&gt; ‘a football team’ -&gt; no match<br>foo\B -&gt; ‘a football team’ -&gt; match<br>foo\B -&gt; ‘the afootest’ -&gt; match</pre><ul><li><strong>\d</strong></li></ul><p>Matches any decimal digit. Equivalent to [0–9]</p><pre>\d -&gt; ‘12abc3’ -&gt; 3 matches (1, 2, 3)<br>\d -&gt; ‘JavaScript’ -&gt; no match</pre><ul><li><strong>\D</strong></li></ul><p>Matches any non-decimal digit. Equivalent to [⁰-9]</p><pre>\D -&gt; 1ab34”7 -&gt; 3 matches (a, b, “)<br>\D -&gt; 1345 -&gt; no match</pre><ul><li><strong>\s</strong></li></ul><p>Matches where a string contains any whitespace character. Equivalent to [\t\n\r\f\v]</p><pre>\s -&gt;’RegEx’ -&gt; no match<br>\s -&gt; ‘Regular expression’ -&gt; 1 match</pre><ul><li><strong>\S</strong></li></ul><p>Matches where a string contains any non-whitespace character. Equivalent to [^\t\n\r\f\v]</p><pre>\S -&gt; ‘a bc’ -&gt; 3 matches (a, b, c)<br>\S -&gt; ‘ ‘ -&gt; no matches</pre><ul><li><strong>\w</strong></li></ul><p>Matches any alphanumeric character. Equivalent to [a-zA-Z0–9_]</p><pre>\w -&gt; 12&amp;”:;c -&gt; 3 matches (1, 2, c)<br>\w -&gt; $%&amp; -&gt; no matches</pre><ul><li><strong>\W</strong></li></ul><p>Matches any non-alphanumeric character. Equivalent to [^a-zA-Z0–9_]</p><pre>\W -&gt; 12&amp;”:;c -&gt; 4 matches (&amp;, “, :, ;)<br>\W -&gt; JavaScript -&gt; no matches</pre><h3>How to use RegEx</h3><p><strong>String Methods</strong></p><ul><li><strong>exec()</strong> -&gt; Executes a search for a match in a string and returns an array of information. It returns <em>null</em> on a mismatch.</li><li><strong>test()</strong> -&gt; Tests for a match in a string and returns <em>true</em> or <em>false.</em></li><li><strong>match()</strong> -&gt; Returns an array containing all the matches. It returns <em>null </em>on a mismatch.</li><li><strong>matchAll()</strong> -&gt; Returns an iterator containing all of the matches.</li><li><strong>search()</strong> -&gt; Test for a match in a string and returns the index of the match. It returns <em>-1</em> if the search fails.</li><li><strong>replace()</strong> -&gt; Searches for a match in a string and replaces the matched substring with a replacement substring.</li><li><strong>split()</strong> -&gt; Break a string into an array of substrings.</li></ul><p><strong>Regex Flag</strong></p><p><strong>g: </strong>performs a global match (find all matches).</p><p><strong>m: </strong>performs multiple match.</p><p><strong>i: </strong>performs case-insensitive matching.</p><pre>const string = &#39;Hello hello hello&#39;;</pre><pre>// performing a replacement<br>const result1 = string.replace(/hello/, &#39;world&#39;);<br>console.log(result1); // Hello world hello</pre><pre>// performing global replacement<br>const result2 = string.replace(/hello/g, &#39;world&#39;);<br>console.log(result2); // Hello world world</pre><pre>// performing case-insensitive replacement<br>const result3 = string.replace(/hello/i, &#39;world&#39;);<br>console.log(result3); // world hello hello</pre><pre>// performing global case-insensitive replacement<br>const result4 = string.replace(/hello/gi, &#39;world&#39;);<br>console.log(result4); // world world world</pre><h3>Examples</h3><pre>// Splitting strings into array elements<br>const regex = /[\s,]+/,<br>  result = &#39;hello world! &#39;.split(regex);<br>console.log(result); // [&#39;Hello&#39;, &#39;world!&#39;, &#39;&#39;]</pre><pre>// Searching the phone number pattern<br>const regex = /(\d{3})\D(\d{3})-(\d{4})/g,<br>  result = regex.exec(&#39;My phone number is: 666 123-4567.&#39;);<br>console.log(result); // [&#39;666 123-4567&#39;, &#39;666&#39;, &#39;123&#39;, &#39;4567&#39;]</pre><p><strong>Validating a phone number</strong></p><pre>function validatePhone(num) {<br>  const regex = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/g;<br>  <br>  // Check if the phone number is valid<br>  let result = num.match(regex);<br>  if (result) {<br>    console.log(The number is valid.);<br>  } else {<br>    let num = prompt(&#39;Enter number in XXX-XXX-XXXX format:&#39;);<br>    validatePhone(num);<br>  }<br>}<br></pre><pre>let number = prompt(&#39;Enter a number XXX-XXX-XXXX&#39;);<br>validatePhone(number);</pre><p><strong>Validating the email adress</strong></p><pre>function validateEmail(email) {<br>  const regex = /\S+@\S+\.\S+/g;</pre><pre>  // check if the email is valid<br>  let result = regex.test(email);<br>  if (result) {<br>    console.log(&#39;The email is valid&#39;);<br>  } else {<br>    let newEmail = prompt(&#39;Enter a valid email:&#39;);<br>    validateEmail(newEmail);<br>  }<br>}<br></pre><pre>let email = prompt(&#39;Enter an email:&#39;);<br>validateEmail(email);</pre><p>I hope you find it useful!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fe019d11fca0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Drupal Behaviors]]></title>
            <link>https://sararellano.medium.com/drupal-behaviors-7215ddba9a1e?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/7215ddba9a1e</guid>
            <category><![CDATA[drupal-development]]></category>
            <category><![CDATA[drupal-tips]]></category>
            <category><![CDATA[drupal-behaviors]]></category>
            <category><![CDATA[drupal-tricks]]></category>
            <category><![CDATA[drupal]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Thu, 14 Oct 2021 11:51:34 GMT</pubDate>
            <atom:updated>2021-10-14T11:51:34.826Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fQG3hEiutsxXGycFdLLwDA.png" /><figcaption>Drupal behavoirs</figcaption></figure><p>Hello!! <br>Maybe you know about Drupal.behaviors, but if you just know this word, be aware to this article.</p><h3>What is Drupal.behaviors?</h3><p><em>Drupal.behaviors</em> is an object inside the Javascript structure in Drupal, which allows us to attach functions to be executed at certain times during the execution time of the application.</p><p>Drupal core will call <em>Drupal.behaviors</em> when the DOM is fully loading, but these behaviors can be called again.</p><h3>Difference between Drupal.behaviors and document.ready</h3><p>The advantage of Behaviors over <em>document.ready()</em> or <em>document.addEventListener(“DOMContentLoaded”, function(){})</em> is that they are automatically re-applied to any content loaded through AJAX.</p><p><em>document.ready() </em>or<em> document.addEventListener(“DOMContentLoaded”, function(){})</em> (jQuery and JS code) only run once when the DOM is ready, but <em>Drupal.behaviors</em> can be run <strong>multiple</strong> times during page execution.</p><p>For example, in views with infinite scroll, more elements will be loaded when user clicks load “more button”, hence, DOM will change after initial load. But Drupal will call attached behaviors when the DOM is loaded, and also, when it’s changed by Ajax.</p><p>What if we want to add classes to the newly added elements? Here Drupal Behaviors come handy. Also, these behaviors allow you to override or extend the existing behavior. So for instance, if a module behavior adds a bounce effect on all links, another module could replace that behavior with a different bounce effect.</p><h3>How to use them?</h3><p><a href="https://www.drupal.org/node/756722">Drupal official documentation</a> says that all modules have to integrate javascript using Drupal.behaviors. The new object needs to have at least an <em>attach</em> method.</p><p>Inside a JS file you have to add this structure:</p><pre><em>Drupal.behaviors.behaviorName = {    <br>  attach: function (context, settings) {      <br>    // Custom code to be run on page load and on Ajax load</em><br><em>    $(&#39;.element-example&#39;, context).click(function () {        <br>      $(this).next(&#39;ul&#39;).toggle(&#39;show&#39;);      <br>    });<br></em><br>  <em>}<br></em><br><em>};</em></pre><p>Like you can see, we have to pass two arguments: context and settings:</p><ul><li><strong>Context</strong>: It is the modified DOM object, it refers to the HTML that is being affected. It allows us to act within the affected scope, for example in the submission of an Ajax form the context will only be the HTML of the form.</li><li><strong>Settings</strong>: contains all the settings injected server side (added by Drupal/PHP). This argument is added in Drupal 8.</li></ul><p>It’s important to say that the first time that <em>attach() </em>method is called, the <em>context</em> variable contains the <em>document</em> object (the whole DOME), but for the next calls, the variable <em>context</em> will hold the affected piece of HTML.</p><p>Drupal behaviors started in Drupal 6, but they have changed:</p><pre><strong>// Drupal behavior D8 &amp; D9</strong><br><br>Drupal.behaviors.behaviorName = {  <br>  attach: function (context, settings) {    <br>    // Your custom JavaScript goes inside this function...  <br>  }<br><br>};</pre><pre><strong>// Drupal behavior for D7</strong><br><br>Drupal.behaviors.behaviorName = {  <br>  attach: function(context) {    <br>    // Your custom JavaScript goes inside this function.  <br>  }<br><br>};</pre><pre><strong>// Drupal behavior for D6<br></strong><br>Drupal.behaviors.behaviorName = function(context) {  <br>  // Your custom JavaScript goes inside this function.<br><br>};</pre><h3>AttachBehaviors()</h3><p>We can see this function in <em>misc/drupal.js:</em></p><pre><em>// Attach all behaviors</em></pre><pre><em>$(function () {  <br>  <br>  Drupal.attachBehaviors(document, Drupal.settings);</em></pre><pre><em>});</em></pre><p>Remember that in jQuery <em>$(function() {} ) </em>is a shorthand for <em>$(document).ready()</em></p><p>Here we see a new method:<em> Drupal.attachBehaviors() </em>. This method can be called more times after the DOM is loaded. For instance, Drupal <strong>core</strong> will call <em>Drupal.attachBehaviors() </em>when:</p><ul><li>When DOM is ready</li><li>After an administration overlay has been loaded into the page</li><li>After submitting an Ajax Form API</li><li>When an Ajax request returns a command that modifies the HTML code, such as ajax_command_replace()</li></ul><p>Also, <strong>contrib</strong> and <strong>custom</strong> <strong>modules</strong> can execute <em>Drupal.attachBehaviors()</em>. For example:</p><ul><li>Ctools calls it after loading a modal</li><li>Views calls it after loading a new page using Ajax</li><li>Views calls it when you have a pagination and you change the page</li><li>Any custom module can be called by executing the method in JS: <em>Drupal.attachBehaviors()</em></li></ul><h3>When we don’t have to use Drupal.behaviors?</h3><p>In general, Drupal invites us to always use Drupal.behaviors, however there are cases where it is not convenient to use it: when we need the JS code to be executed in a single moment, like a script that defines the behavior of a hamburger menu. We will only need it to be executed when the DOM is ready and no more, because it won’t affect the HTML that we manipulate in the javascript.</p><h3>Detach</h3><p>The converse to the attach() method is <em>Drupal.behaviors.behaviorName.detach</em>. Any code in the detach() method will be called before page content is about to be removed from the DOM. Allowing JavaScript behaviors to be detached from the element before it’s removed. This can be especially useful for expensive tasks like polling, which could continue to run in the background even if the DOM element they are working on has been removed.</p><pre>Drupal.behaviors.behaviorName.detach = function(context, setting, trigger) {  <br>  // Your code here</pre><pre>}</pre><p>You can see more information about detach behaviors in <a href="http://read.theodoreb.net/drupal-jsapi/Drupal.html#.detachBehaviors">this doc</a></p><h3>jQuery Once</h3><p>Drupal.behaviors can be called multiple times, but if we want to run our code only one time we have to use <em>once().</em></p><p>jQuery Once ensures that something is processed only once by adding a class in a DOM element after the code has been executed.</p><pre>Drupal.behaviors.behaviorName = {    <br>  attach: function(context, settings) {      <br>    $(&#39;.modal&#39;, context).once(&#39;remove-modals&#39;).each(function () {        <br>      // Do stuff.        <br>      $(document).keyup(function (e) {          <br>        if (e.keyCode == 27) {            <br>          $(&#39;.modal&#39;, context).removeClass(&#39;modal-active&#39;);          <br>        }              <br>      })      <br>    })    <br>  },    <br>  detach: function(context, settings, trigger) {      <br>    $(&#39;.modal&#39;, context).removeOnce(&#39;remove-modals&#39;).each(function() {        <br>      // Undo stuff.      <br>    });    <br>  }  <br>};</pre><p>In this example, the code will add <em>remove-modals</em> class the first time the function is executed. But the next time that <em>Drupal.attachBehaviors</em> is called, <em>.once()</em> will find the class and will skip it.</p><h3>To sum up</h3><p>Behaviors will be called first when the DOM is loaded, and they can be called <strong>more times</strong> with a <em>context</em> that represents new additions or changes to the DOM.</p><p>More info:</p><ul><li><a href="https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview">https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview</a></li><li><a href="https://www.lullabot.com/articles/understanding-javascript-behaviors-in-drupal">https://www.lullabot.com/articles/understanding-javascript-behaviors-in-drupal</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7215ddba9a1e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Stacking Context]]></title>
            <link>https://sararellano.medium.com/stacking-context-a54c00e0aad3?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/a54c00e0aad3</guid>
            <category><![CDATA[frontend-development]]></category>
            <category><![CDATA[css-tricks]]></category>
            <category><![CDATA[stacking-context]]></category>
            <category><![CDATA[css-tips]]></category>
            <category><![CDATA[css]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Wed, 13 Oct 2021 07:43:34 GMT</pubDate>
            <atom:updated>2021-10-14T08:13:58.714Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/481/1*6JT7aPIKDDbc6o30Y1Gyrg.gif" /><figcaption>Stacking Context</figcaption></figure><p>The <strong>stacking context </strong>is a CSS functionality that is often difficult to understand and one of the most misunderstood tool in CSS.</p><p>These terms that I’m going to explain may not be entirely clear. Things are always better understood by seeing them in action, that’s why I have created a <a href="https://stacking-context.github.io/stacking-context/"><strong>website</strong></a> where you can play with the different position values and add z-index to them to see what happens.</p><h3>What is stacking context?</h3><p>Is a tool to control the stacking order of HTML elements. Like in image editors (like PhotoShop), you have different layers and you can put one layer after or before another. In CSS the same happens: an element can contain a set of layers.</p><p>This can be a <strong>root stacking context</strong>, as created by the html element. Or it can be a <strong>local stacking context</strong>, as created by specific properties and values.</p><p>To order the different elements we have some properties (<strong>opacity</strong> when the value is less than 1, <strong>filter</strong> when the value is not <em>none</em>, <strong>mix-blend-mode</strong> when the value is not <em>normal</em> or <strong>transform</strong> when the value is not <em>none</em>), but in this article I’m going to explain in more detail the best known: <strong>position</strong> and <strong>z-index</strong>.</p><p>We can create a stacking context in any part of the document and it can be created by any element. To know exactly what properties have to have the elements to create a new stacking context to see them in detail in <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context">MDN</a>. But it’s important to pointing that:</p><p>➔ Only child elements are affected. Stacking context doesn’t affect siblings.</p><p>➔ We can have a stacking context inside another stacking context.</p><p>When you create a stacking context, the children are painted from bottom to top in this order:</p><ol><li>Children with a negative stack level (usually with `<em>z-index: -1</em>`)</li><li>Children with <em>position: static</em></li><li>Children with stack level equal to 0 (usually with `<em>z-index: auto</em>`)</li><li>Children with positive stack level (`<em>z-index &gt;= 1</em>`)</li></ol><p>Also, children with the same stack level are ordered by their origin order (the second child is painted in front of the first child).</p><h3>Z-index</h3><p>When we positioned elements ww have 3 axes: X (width), Y (height) and <strong>Z</strong>: the third dimension. That dimension is useful to put an element in front of other elements, or behind them.</p><p><em>Z-index</em> creates a layer order following the Z axis.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/341/0*7Z3fkJ1p0UMZFe6W" /><figcaption>Z axis</figcaption></figure><p>The values for this property are positive or negative numbers. An element on the web page appears in front of other elements as its z-index value is higher.</p><p>To add <em>z-index</em> to an element, this element has to be positioned: it has to have a position value not equal to <em>static</em> or be in a grid or flex context.</p><p>The default value of <em>z-index</em> is <em>auto</em>, except the HTML that has <em>z-index: 0</em>.</p><h3>Positions</h3><p>The default value of <strong>position</strong> property is <em>static</em>. But <em>position</em> has other values: <em>relative, absolute, fixed </em>and <em>inherit</em>.</p><p><strong>Static</strong></p><p>Is the default value. It determines that the element is not positioned, so if there’s a <em>top/right/bottom/left/z-index</em> property, there will be no effect on that element. We use this value, usually, to delete a real position value.</p><p><strong>Inherit</strong></p><p>This value means the position of an element is the position of its parent. It inherits the value of the parent. If the parent is <em>position: absolute</em>, the child will be <em>position:absolute;</em></p><p><strong>Relative</strong></p><p>This is the most common value (I think…) but also, a bit complicated to understand. If you add <em>relative </em>value without other properties like <em>top/right/bottom/left</em> then there will be no effect. BUT (always there’s a <em>BUT</em>) if the others elements are not positioned (they are <em>static</em>), this element will appear in front of the others, even if you don’t add <em>z-index</em> property. Also, you can’t put a <em>relative</em> element behind a <em>static</em> element adding <em>z-index</em> to the <em>static</em> element.</p><p>In a <em>relative</em> element you can add the properties <em>top/right/bottom/left </em>and move the element. If you add <em>left: 20px</em> the element will be moved 20px to the right.</p><p>An important thing it’s that children from a <em>relative</em> element can be positioned <em>absolute</em> inside that element, creating a new stacking context.</p><p><strong>Absolute</strong></p><p>This value uses the properties <em>top/right/bottom/left </em>to move an element where you want. The position of this element depends on the relative parent (with position <em>relative</em> or <em>absolute</em>). And if there’s no a positioned parent, the element will depend on the whole HTML.</p><p>Also, we have to be careful because these elements are removed from the flow of elements on the page. This means that this element is not affected by other elements and it does not affect other elements. That can limit the flexibility of your site.</p><p><strong>Fixed</strong></p><p>Elements with <em>fixed</em> value are positioned relative to the <strong>viewport</strong>. This means that they are going to stay in the same position even if you scroll the window. This happens because the viewport doesn’t change the position when you scroll a page.</p><p>This position type is very useful for menus for example, or cookie banners.</p><p>Also, you have to be careful because these fixed elements are always going to appear in front of other elements and sometimes they can overlap others. For example, you have a fixed menu with links to internal links. So when you click on an internal link you have to subtract the height of the menu, because if you don’t do it, the menu is going to overlap the content of your link (a way to solve this is adding <em>scroll-margin-top: “menu height”</em> ).</p><p><strong>Sticky</strong></p><p><em>Sticky</em> is a very powerful value. It’s a mix between <em>relative</em> and <em>fixed</em>. A <em>sticky</em> element depends on its positioned parent and with <em>top/right/bottom/left</em> you can move the element relative to its parent. The interesting part of this value is when we scroll, because the <em>sticky</em> element is going to become <em>fixed</em> and it changes its parent by the <em>body</em> of the HTML. Then, when you return the scroll to the original parent, it’s going to return <em>relative</em>.</p><p>This is very useful when you have a menu in the bottom of your principal and first element. But when you scroll down you want to have the menu on top of the page.</p><p>— — — — — —</p><p>I hope you like it!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a54c00e0aad3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Custom Twig Filters and Functions]]></title>
            <link>https://sararellano.medium.com/custom-twig-filters-and-functions-7a25ef6cfd86?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/7a25ef6cfd86</guid>
            <category><![CDATA[frontend]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[symfony]]></category>
            <category><![CDATA[twig]]></category>
            <category><![CDATA[developer-tools]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Tue, 14 Sep 2021 10:10:33 GMT</pubDate>
            <atom:updated>2021-09-14T10:10:33.061Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/225/1*iF9LZU8wUfw6uYZaReONsw.png" /><figcaption>Twig Filters and Functions</figcaption></figure><p><strong>Twig</strong> is the template manager used by Symfony to add some logic to our variables in our templates. The functions and filters problem is that we have a limited number of them. So we are going to learn how to add new filters and functions.</p><p>But first… what are filters and functions?</p><h3>What are filters and functions?</h3><p>Filters and functions are the logic available in your twig templates. You can see in <a href="https://twig.symfony.com/doc/2.x/">Twig Documentation</a> the different functions and filters existing. For instance, we have the filter <em>|upper </em>and <em>|lower</em> to put some text uppercase or lowercase. This is the syntax of the filters:</p><p><strong>Filter upper</strong></p><pre>{{ ‘Hello world’|upper }} -&gt; Output <em>HELLO WORLD</em></pre><p>And, in the case of functions, you have other examples, like <em>active_theme()</em> to know the theme you are using in Drupal:</p><p><strong>Function active_theme()</strong></p><pre>{{ active_theme() }} -&gt; Output <em>your_theme</em></pre><p><strong>But what is the difference between Filters and Functions?</strong></p><p><strong>Filters</strong> transform the data, but <strong>Functions</strong> are used when you need to do heavier actions than only show simple datas. The functions are used when you need to calculate things to represent the result (not only show it).</p><h3>How to add new filters and functions in Twig</h3><p>In this post we are going to create a filter to convert a number into money € format (<em>moneyFormat</em>), another filter to cut a text and add ‘…’ (<em>cut_text</em>), and also, a function that returns a text in a custom color (<em>color_text</em>).</p><p>To do all, we have to have a custom module. In my post, the name of this module will be “<em>MyModule</em>”.</p><p><strong>1.</strong> Create the service file with this structure: <em>MyModule.services.yml</em></p><pre>services:  <br>  MyModule.twig_extension:    <br>    class: Drupal\MyModule\MyModuleTwigExtension    <br>    tags:      <br>      - { name: twig.extension }</pre><p><strong>2.</strong> Now we have to create the file <em>MyModuleTwigExtension.php</em> in the source: <em>MyModule/src/MyModuleTwigExtension.php</em></p><p>Here we are going to declare the <strong>class MyModuleTwigExtension</strong> and this class will extends from the class <strong>Twig_Extension</strong></p><pre>&lt;?php<br> <br>namespace Drupal\MyModule;<br> <br> <br>/**<br>* Class MyModuleTwigExtension<br>*/<br>class MyModuleTwigExtension extends \Twig_Extension {<br> <br> //  A list with all the defined functions. The first parameter is the name by which we will call the function. The second parameter is the name of the function that will implement the function.<br> public function getFunctions() {<br>   return [<br>     new \Twig_SimpleFunction(&#39;color_text&#39;, [$this, &#39;colorText&#39;]),<br>   ];<br> }<br> <br> //  A list with all the defined filters. The first parameter is the name by which we will call the filter. The second parameter is the name of the function that will implement the filter.<br> public function getFilters() {<br>   return [<br>     new \Twig_SimpleFilter(&#39;money_format&#39;, [$this, &#39;moneyFormat&#39;]),<br>     <br>     new \Twig_SimpleFilter(&#39;cut_text&#39;, [$this, &#39;cutText&#39;]),<br>   ];<br> }<br> <br> // Returns the extension name<br> public function getName() {<br>   return &#39;MyModule.MyModuleTwigExtension&#39;;<br> }<br> <br> <br> // Function that returns an example text with a color passed as a parameter. <br> public function colorText($color = &quot;black&quot;, $text = &#39;Lorem ipsum dolor sit amet,<br> consectetur adipiscing elit.  Quos quidem tibi studiose et diligenter<br> tractandos magnopere censeo.&#39;) {<br>   return &#39;&lt;span style=&quot;color: &#39; . $color . &#39;&quot;&gt; &#39; . $text . &#39; &lt;/span&gt;&#39;;<br> }<br> <br> // Filter to convert a number into €<br> public function moneyFormat($string) {<br>   setlocale(LC_MONETARY, &#39;es_ES.UTF-8&#39;);<br>   return money_format(&#39;%i&#39;, $string);<br> }<br> <br> <br> // Filter that cuts a text according to the maximum number of characters. You can also choose which characters will be put at the end of the text. By default is ‘...’<br> public function cutText($text, $maxchar, $end = &#39;...&#39;) {<br>   if (strlen($text) &gt; $maxchar || $text == &#39;&#39;) {<br>     $words = preg_split(&#39;/\s/&#39;, $text);<br>     $output = &#39;&#39;;<br>     $i = 0;<br>     while (1) {<br>         $length = strlen($output)+strlen($words[$i]);<br>         if ($length &gt; $maxchar) {<br>             break;<br>         }<br>         else {<br>             $output .= &quot; &quot; . $words[$i];<br>             ++$i;<br>         }<br>     }<br>     $output .= $end;<br> }<br> else {<br>     $output = $text;<br> }<br> return $output;<br>}<br> <br>}</pre><p>Now, you have to clean the cache and… that’s all! You can use your new filter and your new function in your templates.</p><p>The syntax will be:</p><pre>{# Function #}<br>{{ color_text(&#39;orange&#39;)|raw }}<br>{{ color_test(&#39;green&#39;, &#39;I am testing the new function&#39;)|raw }}<br> <br>{# Filters #}<br>{{ &#39;150&#39;|money_format }} // Output: 150,00 EUR</pre><pre>{{ &#39;Hello! We are learning how to create new twig extensions&#39;|cut_text(15) }}<br> // Output: Hello! We are...</pre><pre>{{ &#39;Hello! We are learning how to create new twig extensions&#39;|cut_text(15, &#39;-&#39;) }}<br> // Output: Hello! We are-</pre><p>Another interesting thing is that Twig variables can be modified by <strong>filters</strong>. Also, you can add more than 1 filter in a variable, so the output of the first filter will be affected by the second filter:</p><pre>{{ ‘I am going to cut this text’|cut_text(10)|upper }}</pre><p>For more information, you can see the <a href="https://symfony.com/doc/current/templating/twig_extension.html">documentation from Symfony</a> about how to do that.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a25ef6cfd86" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Window.location]]></title>
            <link>https://sararellano.medium.com/window-location-34a84e0109b4?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/34a84e0109b4</guid>
            <category><![CDATA[window-object]]></category>
            <category><![CDATA[developer-tools]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[developer]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Wed, 11 Aug 2021 11:05:28 GMT</pubDate>
            <atom:updated>2021-08-11T11:05:28.341Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*8b2jB6bwoHvlDx1H.jpg" /><figcaption>window location object</figcaption></figure><p><em>Window.location</em> is an object to have information about the actual page. Also you can redirect or upload it.</p><p>First of all we need to know window.location <strong>properties:</strong></p><p>For example, we have this URL: <a href="https://sararellano.medium.com/js-shorthands-3f675d4c3b13?filter=fronted#top">https://sararellano.medium.com/js-shorthands-3f675d4c3b13?filter=fronted#top</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IJj-ISLYv2bCvTlvmVLZ2g.png" /></figure><p>* This is a read-only property</p><p><strong>PORT</strong></p><p>In my example you see the result of the port is ‘’. This is because if the port number is default (80 for http and 443 for https), most browsers will display 0 or nothing.</p><p>We are going to see another example to understand <em>port </em>and the difference between <em>host </em>and <em>hostname</em>.</p><p>URL: <a href="http://localhost:8080/">http://localhost:8080</a></p><p>.port =&gt; 8080</p><p>.host (domain + port) =&gt; localhost:8080</p><p>.hostname =&gt; localhost</p><p>.origin (protocol + hostname + port) =&gt; <a href="http://localhost:8080/">http://localhost:8080</a></p><p><strong>WINDOW.LOCATION METHODS</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RQ_2P_3Wxk8Tx2L5GhplEg.png" /><figcaption>window.location methods</figcaption></figure><p><strong>DIFFERENCES BETWEEN .ASSIGN() AND REPLACE()</strong></p><p>These methods work very similar: they will redirect you or take you to another url. BUT <em>.assign() </em>will save in history your actual page before the redirection. Therefore, if you use <em>.assign()</em> and click on the back button you can go back to the previous page. And with <em>.replace()</em> you can’t go back.</p><p><strong><em>What have you said?</em></strong></p><p>Maybe I didn’t explain well, so I’m going to add an example:</p><p><strong>.assign()</strong></p><ul><li>Open your browser and go to ‘google.com’</li><li>Add window.location.assign(‘<a href="https://stackoverflow.com/">https://stackoverflow.com</a>)</li><li>Click “go to back” and you will see ‘google.com’</li></ul><p><strong>.replace()</strong></p><ul><li>Open your browser and go to ‘google.com’</li><li>Add window.location.replace(‘<a href="https://stackoverflow.com/">https://stackoverflow.com</a>)</li><li>Click “go to back” and you will see a white page</li></ul><p><strong>HOW TO REDIRECT A PAGE?</strong></p><p>You can do a redirect in 3 ways:</p><ul><li>window.location.href = ‘new web’</li><li>window.location.assign(‘new-web’)</li><li>window.location.replace(‘new-web’)</li></ul><p>Only with <em>.replace() </em>you are not going to return to the previous page (<em>.assign()</em> and .<em>href</em> save the previous page in the history).</p><p><strong>BONUS</strong></p><p>About how to redirect a page, I want to add another method, but not for <em>window.location</em> object. This method is only for <em>window</em> object: <em>.open()</em></p><p>window.open() allows you to open a new tab (a white page) without losing your current page.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=34a84e0109b4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Git Bisect]]></title>
            <link>https://sararellano.medium.com/git-bisect-1a8307f96359?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/1a8307f96359</guid>
            <category><![CDATA[debugging]]></category>
            <category><![CDATA[debugging-tools]]></category>
            <category><![CDATA[debug]]></category>
            <category><![CDATA[git]]></category>
            <category><![CDATA[development]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Wed, 07 Jul 2021 07:59:34 GMT</pubDate>
            <atom:updated>2021-07-07T07:59:34.183Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/531/1*x9Pb0ksVjKu-BNll5jvXKQ.jpeg" /><figcaption>Debugging with Git Bisect</figcaption></figure><p>Today I’m going to write about <strong>Git Bisect</strong>. This is a very useful tool to find any specific error in our code.</p><h3>What is Git Bisect?</h3><p><strong>Bisect</strong> means <em>binary search algorithm </em>and is an efficient way to search large groups of ordered data. It divides the data in half several times and applies a validation criterion. Thus, we can scan a large amount of information with few iterations.</p><p><strong>When is a good moment to use bisect?</strong> When you want to search for a change and you don’t know when this change happened. For example, you have a version 2 and you have an error or you have accidentally deleted some code, but you know that on version 1 everything is working. But between version 1 and version 2 you have 15 commits and you don’t know which commit caused the error.</p><h3>How to work with bisect</h3><p>To start you have to know the last commit where everything was working well and a commit where everything broke to specify search limits.</p><p>To start we put:</p><pre>git bisect start</pre><p>Then you have to check the last commit where the bug doesn’t exist. You can add the commit SHA, tag or branch and put it “good”:</p><pre>git bisect good 123456789</pre><p>And now, you have to add the commit where you know that the bug exist:</p><pre>git bisect bad 987654321</pre><p>Now, git starts a binary search: it splits commits in half and shows you the commit in the middle and you have to tell if this commit is good or bad. For instance, we have 15 commits between our v1 and v2, so you will see a message like that:</p><pre><em>Bisecting: 15 revisions left to test after this (roughly 4 steps)</em></pre><p>And bisect puts you on the seventh commit. Now you have to run code and check if in this commit everything is working or not and tell bisect your answer:</p><pre>git bisect good||bad</pre><p>Then, bisect jumps into other commit to test other and you have to repeat the test and put the answer:</p><pre>git bisect good||bad</pre><p>And so on until finding the commit where your code does not work.</p><p>If you can’t test a determined commit, you can run git bisect skip and jump into the next commit.</p><p>When bisect finds the first bad commit it gives you this answer:</p><pre><em>135792468 is the first bad commit</em></pre><p>And here you have your problematic commit! If you make: git show 135792468 you will see the changes done in this first bad commit and fix it.</p><p>To end with bisect you only have to run:</p><pre>git bisect reset</pre><p>And <em>et voilà!</em> thanks to this, we have been able to test 15 commits in just 4 steps. It saves you from testing all commits one by one. It’s so quick and very useful.</p><p>But that is not all! You can automate some tests with scripts. You only have to run:</p><pre>git bisect run [script] [arguments]</pre><p>For instance, you have an error while compiling your code. You can automate bisect to find the first bad commit like this (think that my script to compile my code is <em>npm run build-prod</em>) and find where the compilation stopped working:</p><pre>git bisect start</pre><pre>git bisect good 123456789</pre><pre>git bisect bad 987654321</pre><pre>git bisect run npm run build-prod</pre><p>If you have an error <em>0</em> is that this commit is good. If you have a <em>125</em> error means that bisect can’t do the test and jump into the next commit (like git bisect skip). Any other error means that the commit is bad.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1a8307f96359" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Defer and Async]]></title>
            <link>https://sararellano.medium.com/defer-and-async-3af42230852a?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/3af42230852a</guid>
            <category><![CDATA[async]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[defer]]></category>
            <category><![CDATA[javascript-tips]]></category>
            <category><![CDATA[asynchronous]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Wed, 12 May 2021 07:54:13 GMT</pubDate>
            <atom:updated>2021-05-12T07:54:13.956Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JTN-BbaI26viy2qgWmf-7A.png" /><figcaption>Defer vs Async</figcaption></figure><p>When your scripts are heavy and/or you have a slow server, they can affect the performance of your page. To help with this, we have 2 attributes that we can add to our scripts so that they don’t block or delay the execution of our website.</p><p>But first we have to understand how the execution of a web works.</p><h3>How the execution of a web works</h3><p>When the browser loads HTML and finds a `script` tag, it cannot continue to build the DOM. It has to wait for the script to download and then, execute the downloaded script. Then it can process the rest of the page.</p><p>For example:</p><pre>&lt;p&gt; First paragraph &lt;/p&gt;</pre><pre>&lt;script src=”XXX”&gt;</pre><pre>&lt;p&gt; Second paragraph &lt;/p&gt;</pre><p>In this example, the browser is going to paint the “first paragraph”, then download and execute the script, and then paint the “second paragraph”.</p><p>To solve this problem (not block content display) you can put the script tag at the end of the body. But if your HTML is too large, it’s going to take a long time and delay the loading of the page.</p><p>To see it more clearly:</p><p><em>Scripts in head:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*PSaVkkbq8btak-hZ" /><figcaption>Scripts in head</figcaption></figure><p><em>Scripts at the end of the body:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*T57EA5T_jPJbLuuS" /><figcaption>Scripts ay the end of the body</figcaption></figure><p>And at this point, <strong>defer</strong> and <strong>async</strong> start.</p><h3>Defer</h3><p>`defer` downloads the script during HTML parsing and then, when the parser is completed, the browser executes the script. So scripts with `defer` don’t block the render of a page.</p><p>An important thing is that `defer` scripts are executed when the DOM is ready, but <strong>before</strong> the <strong>DOMContentLoaded </strong>event. The DOMContentLoaded event fires when the script is downloaded and executed. A positive effect of this attribute is that the DOM will be available for your script.</p><p>Another characteristic of `defer` is that these scripts guarantee the execution in the <strong>order</strong> that they appear in the document. So you have to use `defer` if you need to keep the order. This makes defer the attribute of choice when a script depends on another script.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/903/1*cjhYkci6gzordR_6x84gjw.png" /><figcaption>With defer</figcaption></figure><h3>Async</h3><p>With `async`, the file gets downloaded asynchronously and then executed as soon as it’s downloaded, without respecting any order, so it should be used for totally independent scripts.</p><p>The `async` attribute doesn’t wait for the DOMContentLoaded event either.</p><p>In other words, `async` scripts load in the background and run when ready. And also, like the `defer` attribute, the `async` attribute doesn’t block any content.</p><p>A good example to use this attribute is with Google Analytics scripts.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/901/1*p4rbsjX8jD7ZH2X6yvUckQ.png" /><figcaption>With async</figcaption></figure><h3>To sum up</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/637/1*roprQ_DAss0Pe2LO9jc-PA.png" /><figcaption>Differences between defer and async</figcaption></figure><p>📣 <strong>Important</strong>: both attributes don’t have any effect on inline scripts.</p><h3>Support</h3><p>When you want to use `defer` and `async` you must keep in mind that not all browsers accept them. You can check better in:</p><ul><li><em>Async</em>: <a href="https://caniuse.com/script-async">https://caniuse.com/script-async</a></li><li><em>Defer</em>: <a href="https://caniuse.com/script-defer">https://caniuse.com/script-defer</a></li></ul><p>It’s important to highlight that IE9 and below have problems with `defer` and this browser doesn’t guarantee the execution order.</p><p>You can add `defer` and `async` <strong>together</strong>. If you add both, `async` overrides `defer` if the browser supports it. But you keep `defer` for old browsers that only accept `defer`.</p><h3>Extra: Dynamic Scripts</h3><p>Another and very used option to load a script asynchronously is to inject the `&lt;script&gt;` tag dynamically with JS:</p><pre>const script = document.createElement(“script”);</pre><pre>script.src = “/path-to/script.js”;</pre><pre>document.getElementsByTagName(“head”)[0].appendChild(script);</pre><p>The scripts that are dynamically added to the document are asynchronous by default and they don’t block the render of the page either. Also, they are executed as soon as they have been downloaded. In other words: the same behavior as with the `async` attribute.</p><p>Also, the DOMContentLoaded event doesn’t wait for the script to run.</p><p>In some cases we can see that attribute `async` is added in these dynamic scripts, like this:</p><pre>script.async = true;</pre><p>And it is for Firefox 3.6 and Opera browsers, which don’t have the asynchronous behavior by default for injected scripts, but they support the `async` attribute.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3af42230852a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What is BEM?]]></title>
            <link>https://sararellano.medium.com/what-is-bem-ee39cb573eba?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/ee39cb573eba</guid>
            <category><![CDATA[css]]></category>
            <category><![CDATA[bem-css]]></category>
            <category><![CDATA[frontend]]></category>
            <category><![CDATA[css-tricks]]></category>
            <category><![CDATA[bem]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Wed, 07 Apr 2021 12:32:33 GMT</pubDate>
            <atom:updated>2021-04-07T12:32:33.289Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/443/1*AQyVsQg-ItIjpUHO85fRBQ.jpeg" /></figure><p>BEM it’s a very useful development methodology based on components. The base of this methodology is to divide the user interface into separate blocks to create <strong>scalable, flexible </strong>and <strong>reusable</strong> components. Also, it proposes a style to name each of the classes, thus allowing to create a consistent and clear code (also helps you with the difficult task of finding the best names for each element).</p><p><strong>BEM = Block + Element + Modifier</strong></p><h3><strong>BLOCKS</strong></h3><p>A block is a container where other elements will be. A block is the <strong>root</strong> of the CSS class and will always go first, and from it, we will create the other classes. A block is independent and can work alone.</p><p>Example: .<em>card</em></p><pre>&lt;div class=&quot;card&quot;&gt; test &lt;/div&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/950/0*vxWhLeS33jAf9FUU" /><figcaption>BEM Block</figcaption></figure><p><em>Card</em> has all the properties to work alone and if you only add a “<em>card</em>” class you can see a simple card.</p><h3><strong>ELEMENT</strong></h3><p>An element is one of the pieces that the block will have. For example, following the last example, we can create a new element inside the card: the title. These elements can’t work alone (like modifiers), because they are attached to their block (their father).</p><p>The naming convention is to put 2 underscores before the element: <em>.card__title</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/940/0*I2_n1zhOiMfqpLP2" /><figcaption>BEM Element</figcaption></figure><h3><strong>MODIFIER</strong></h3><p>Like the name said, it’s a modifier. You can use whatever you want and modify the elements or the block directly. For example, you can have 2 different titles: red and blue. But also, you can have 2 different cards: card with red background and other with blue background.</p><p>Here, the naming convention is to add 2 hyphens before the modifier.</p><p>Modify a block:</p><ul><li><em>card — red</em></li><li><em>card — blue</em></li></ul><p>Modify an element inside a block:</p><ul><li><em>card__title — red</em></li><li><em>card__title — blue</em></li><li><em>card__title — bold</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/958/0*FDNbplMXy4GRpCl8" /><figcaption>BEM Modifier</figcaption></figure><h3><strong>ADDING A BLOCK INSIDE ANOTHER BLOCK</strong></h3><p>Is this possible? Of course! Remember that a block is an independent component, but you can create other components and add them inside others blocks.</p><p>We are going to see an example:</p><p>In the last example with the card, now we want to add a checklist inside the card. What we have to do is create our new component (<em>.checklist </em>) independently. The result will be:</p><pre>&lt;ul class=&quot;checklist&quot;&gt;</pre><pre>  &lt;li class=&quot;checklist__item&quot;&gt; Text &lt;/li&gt;</pre><pre>  &lt;li class=&quot;checklist__item--green&quot;&gt; Text &lt;/li&gt;</pre><pre>  &lt;li class=&quot;checklist__item&quot;&gt; Text &lt;/li&gt;</pre><pre>  &lt;li class=&quot;checklist__item&quot;&gt; Text &lt;/li&gt;</pre><pre>&lt;/ul&gt;</pre><p>Check that we have a <strong>block</strong>, an <strong>element</strong> (<em>item</em>) and a <strong>modifier</strong> (<em>green</em>).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/892/0*5UPUPQNQ5ByjUqXp" /></figure><p>And now, we can add it into the card, so the final result will be:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/956/0*jeLoXGzcyKgENksi" /></figure><pre>&lt;div class=&quot;card&quot;&gt;<br>  <br>  &lt;h3 class=&quot;card__title card__title--blue card__title--bold&quot;&gt; <br>    Title     <br>  &lt;/h3&gt;</pre><pre>  &lt;ul class=&quot;checklist&quot;&gt;</pre><pre>    &lt;li class=&quot;checklist__item&quot;&gt; Text &lt;/li&gt;</pre><pre>    &lt;li class=&quot;checklist__item checklist__item--green&quot;&gt; Text &lt;/li&gt;</pre><pre>    &lt;li class=&quot;checklist__item&quot;&gt; Text &lt;/li&gt;</pre><pre>    &lt;li class=&quot;checklist__item&quot;&gt; Text &lt;/li&gt;</pre><pre>  &lt;/ul&gt;</pre><pre>&lt;/div&gt;</pre><h3><strong>Advantages and disadvantages</strong></h3><p><strong>Advantages</strong></p><ul><li>Independent and portable code, so you can move your code to a different HTML structure.</li><li>Better CSS performance because you don’t need to use nested selectors. So the less browsers have to evaluate, the faster they can render.</li><li>Easy and clear naming.</li><li>Ease of code maintenance: having independent modules of code and hence easier to maintain and update without affecting other modules.</li><li>Improves multiple inheritance: You can change any of the three elements (block, module or modifier) without affecting the others.</li></ul><p><strong>Disadvantages</strong></p><ul><li>You have to learn the methodology.</li><li>Names can be very large and file sizes may grow. (Although you can minify production code).</li><li>Ugly code: code can look nasty with these classes names.</li></ul><p>More info: <a href="http://getbem.com/">http://getbem.com/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ee39cb573eba" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CSS more efficient]]></title>
            <link>https://sararellano.medium.com/css-more-efficient-75c8d49d10a?source=rss-bf1d17647ac------2</link>
            <guid isPermaLink="false">https://medium.com/p/75c8d49d10a</guid>
            <category><![CDATA[css-tricks]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[css-efficient]]></category>
            <dc:creator><![CDATA[Sararellano]]></dc:creator>
            <pubDate>Tue, 23 Mar 2021 09:37:00 GMT</pubDate>
            <atom:updated>2021-03-23T09:37:00.244Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*90ZXLu7WAKOJ-Pu3zkN78g.png" /><figcaption>CSS Efficient</figcaption></figure><p>I have to be honest: I didn’t think about how efficient my CSS is. I focus more on trying to make my JS code more efficient so that the browser renders it as soon as possible, but I had never looked at my CSS. So I started to find information about how to make more efficient CSS code and I would like to share with you my investigation:</p><h3>Selector types</h3><p>There are 4 selector types: <strong>ID</strong>, <strong>classes</strong>, <strong>tags</strong> and <strong>globals</strong>. They are ordered according to how efficient they are.</p><pre>#btn — submit {} /* ID (fastest) */</pre><pre>body .main #faq {} /* ID */</pre><pre>.main {} /* Class */</pre><pre>ul li a.btn — primary {} /* Class */</pre><pre>div {} /* Tag */</pre><pre>div ul li {} /* Tag */</pre><pre>*{} /* Global (slowest) */</pre><p>This is because browsers read CSS from <strong>right to left</strong>, so, for example in `<em>ul li a.btn — primary</em>` they search first all <em>a.btn</em> <em>— primary</em> and then if they are inside a <em>li</em> and then, if they are inside an <em>ul</em>. This is why div <em>#btn — share</em> is fastest than <em>#btn — share div</em></p><p>About that, it’s important to say that if a selector doesn’t match with anything, it is not going to waste energy because as soon as a match fails, the browser stops trying.</p><h3>Descendant selector</h3><p>A descendant selector is very expensive, and even more so if it contains a tag or a global selector. So don’t use them.</p><p><em>html body div a {}</em></p><h3>Don’t tag an ID</h3><p>IDs are unique, you can’t have 2 IDs with the same name, so they don’t need a tag with them. If you make it, you will make the ID less efficient:</p><p><em>button#btn — share {}</em> ❌</p><p><em>#btn — share</em> ✔</p><p>If you can avoid doing it with classes, don’t do it too. Classes are not unique, so maybe you need to add a tag, but if you can, avoid it.</p><h3>Properties</h3><p>Some CSS properties are heavier and expensive than others.</p><pre>border-radius</pre><pre>box-shadow</pre><pre>filter</pre><pre>position: fixed</pre><pre>transform</pre><p>I don’t say that you can’t use them, but use them with moderation and if you can, choose an alternative option.</p><p>To end, these hacks are important, but be careful, because it’s more important to take care of semantic, maintainability and legibility than a little microsecond of efficiency.</p><h3>Resources</h3><p>I found some interesting pages while writing this article.</p><ul><li><a href="https://csstriggers.com/">https://csstriggers.com/</a> : this page collects all properties in alphabetical order, and lets you know whether changing their values will trigger layout, print or composite work. You can click on a property and see more detailed information about what the costs might be and what will happen.</li><li><a href="https://github.com/uncss/uncss">https://github.com/uncss/uncss</a> : a tool that remove all useless CSS</li><li><a href="https://flukeout.github.io/">https://flukeout.github.io/</a> : a game to learn CSS selectors</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=75c8d49d10a" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>