WordPress Contributors Propose Updating Trac Ticket Resolutions to Be More Friendly

WordPress contributors are currently discussing adopting friendlier terms for some of the trac ticket resolutions to create a more welcoming environment for participants and newcomers. Since trac resolutions are not set in stone, organizations can customize these terms for different workflows.

During a recent core developers chat, Sergey Biryukov proposed that WordPress trac rename “invalid,” “worksforme,” and “wontfix” ticket resolutions to something more friendly and less confusing. The idea was positively received and is now an official proposal.

“More than a few times I’ve seen someone closing a ticket as worksforme after testing a patch because, well, it works for them. When that happens, the ticket has to be reopened with a comment that the patch still needs to be reviewed and committed,” Biryukov said. This particular scenario clearly illustrates how the resolutions can sometimes be confusing for contributors.

Biryukov proposed the following updates:

  • invalid → not-applicable
  • worksforme → not-reproducible or cannot-reproduce
  • wontfix → not-implemented

Others suggested further refinements in the comments of the proposal. Juliette Reinders Folmer noted that ‘not-implemented’ doesn’t seem to capture the full weight of ‘wontfix’ as a decision, because it doesn’t convey anything about the intention.

“The thing which worries me about ‘not implemented’ is that it can be interpreted as an invitation to implement,” Reinders Folmer said. “It doesn’t convey that there is no intention (at this time) to accept an implementation.”

Mika Epstein said they may want to consider having multiple alternatives to ‘wontfix,’ such as not-in-scope, insufficient resources, or better-as-a-plugin.

Peter Wilson suggested the term ‘support-referral’ as an alternative to ‘invalid,’ since many of these tickets are closed due to support requests.

Goodbye, ‘Wontfix’

‘Wontfix’ is a somewhat polite way to say “forget about it” to someone voicing a concern or a suggestion that doesn’t fit with a project’s goals. It is broadly used and understood throughout the industry, and has sometimes been wielded as a gavel to shut down conversation in heated discussions.

The experience of submitting an issue that is closed with the resolution ‘wontfix’ is so visceral that it is often used in a humorous context outside of software development.

For project maintainers who are handing down ticket resolutions as edicts, terms like ‘wontfix’ and ‘worksforme’ have a certain irreplaceable, incisive charm to them. On the other hand, it’s easy to see how these terms might be particularly irksome, especially for new contributors.

Contributors are still brainstorming alternative ticket resolution terms. Anyone with suggestions can jump in on Biryukov’s proposal. As long as WordPress core is still using trac for development, terminology that is clearer and more welcoming may help make the requirement of using trac more friendly in general.

“I know we plan on moving away from Trac at some point, but we’re not there yet, and I think clarifying these resolutions would be helpful in the short term,” Biryukov said.

Some might argue that moving WordPress core development to a platform like GitHub or GitLab would do a great deal more to make it a friendlier contribution experience. Earlier this month, Matt Mullenweg was asked during a virtual Q&A if there has been any progress in moving WordPress development to GitHub.

“No progress there yet, since a lot of the active development has already moved to Github and the Gutenberg plugin, there’s been less pressure on migrating the Trac-based tickets and workflows,” Mullenweg said.

Hide Scrollbars During an Animation

CSS still can’t animate to auto dimensions.

.dropdown {
  transition: 0.2s;
  height: 0;
}
.dropdown.open {
  /* the height will change, but it won't animate. */
  height: auto;
}

There is JavaScript trickery you can try. Brandon Smith outlined several techniques here a little while back. My mind always goes to this solution just because it’s so simple:

.dropdown {
  transition: 0.2s;
  max-height: 0;
}
.dropdown.open {
  /* 🎉 */
  max-height: 400px;
}

Now we have this 400px magic number which is really not ideal. But the fact that this works and is so simple makes it extremely appealing that I use it production all the time.

But the magic number isn’t the only problem. Another problem is scrollbars.

When we set max-height: 0;, we also need overflow: hidden; to make sure the dropdown is actually hidden when it is closed. When the dropdown is open, we should probably be using overflow: auto; so that we don’t accidentally cut off content in case the natural height of the dropdown is taller than the max-height after it expands. The use of overflow: auto; solves that problem while introducing another: during the expansion, our dropdown will always have scrollbars for at least part of the expansion, even if the final expansion height doesn’t need them. That’s awkward!

CSS trickery to the rescue.

We can still use overflow: auto; on the expanded state — we’ll just override it during the animation. As we learned in the great CSS specificity battle, @keyframes have an amazing ability to override anything while they are active. Let’s use them not to animate the opening, but just for this scrollbar-hiding functionality:

.dropdown {
  max-height: 0;
  overflow: hidden;
  transition: max-height 1.2s ease-in-out;
}
.dropdown.open {
  overflow: auto;
  max-height: 400px;
  animation: hide-scroll 1.2s backwards;
  @keyframes hide-scroll {
    from, to { overflow: hidden; } 
  }
}

That does the trick!

Try adjusting the height to something less to see how you don’t see scrollbars during the animation but only at the end when they are needed. That causes a little bit of jerkiness when the scrollbar pops in, but that was acceptable in my case as it’s rare that it happens at all. If you absolutely wanted to stop the jerkiness, you’d probably apply a (custom) scrollbar at all times to the dropdown and perhaps adjust the styling of the scrollbar during the animation, if needed.


Credit here to Mr. Stephen Shaw of the fancy @keyframers for this trick. I yanked him in to help me figure it out while I was working on it for something on CodePen. We decided to turn the trick into a video for the CodePen channel showcasing Collab Mode, which we used to figure out the problem/solution:

The post Hide Scrollbars During an Animation appeared first on CSS-Tricks.

Gutenberg 8.4 Adds Image Editing, Includes Multi-Block Controls, and Enables Block Directory Search

Gutenberg 8.4 landed today with some major user-facing changes, including new image editing tools and the ability to edit options for multiple blocks. The previously experimental block directory search is now enabled for all Gutenberg installations.

Version 8.4 is next to the last major version of Gutenberg planned for integration in WordPress 5.5. The first 5.5 beta is currently on schedule for July 7.

This update includes over three dozen bug fixes, which is several more than typical of a two-week release cycle. It is well worth updating for this alone. It also includes a couple of dozen enhancements, such as support for drag-and-drop in the Social Links block and the ability to transform a Preformatted block into a Code block. Theme authors should enjoy the removal of the canvas padding, which should further improve the ability to match the editor and front end styles.

As usual, this update seems to be an improvement over the previous version. Thus far, I have not run into any regressions in testing.

Upgrade to Get Image Editing

Cropping and changing an image's aspect ratio in the block editor.
Image editing tools in the block editor.

WordPress may be well on its way to replacing one of the extra tools I always use when publishing. For years, I have manually zoomed, cropped, and rotated images in Photoshop, Gimp, or another image editor. I have performed this same action for so long that it feels like a part of the publishing process.

Gutenberg 8.4’s new image editing tools may have me rethinking the need for additional software. The feature allows users to zoom, rotate, or change the aspect ratio for an image directly in the editor.

After selecting an image block, the editor toolbar will display a new crop icon. Once clicked, a range slider will appear below the image in the editor. The slider allows users to zoom in on an image.

After clicking the crop button in the toolbar, two new buttons will also appear. The first button is a simple rotation button, which allows users to rotate the image clockwise, 90 degrees at a time. The second button is for changing the image’s aspect ratio. Once clicked, it will display a dropdown with the following options:

  • Landscape
    – 16:10
    – 16:9
    – 4:3
    – 3:2
  • Portrait
    – 10:16
    – 9:16
    – 3:4
    – 2:3
  • Square

After zooming or changing the aspect ratio, users can also move the image around to change the focal point. The image editor also provides a 3×3 grid for aligning images perfectly, which should be a nice addition for photographers (see rule of thirds).

If nothing else excites you about Gutenberg 8.4, this is the feature you will want to try. The development team put a lot of thought and care behind the user experience.

Customize Multiple Blocks at Once

Editing the block options for two paragraphs.
Assigning custom text color to two paragraphs.

Have you ever wanted to change the text color of multiple paragraphs? Perhaps you have needed to enlarge the font size for two blocks or a multitude of other customizations that you have wanted to apply to multiple blocks? Gutenberg 8.4 allows end-users to edit the block options for more than one block at a time. The only limitation is that the blocks must be of the same type, which makes sense because each block type has different options.

The process is simple. Select two or more blocks and customize all of the selected blocks via the block options panel.

In the past, I have gotten around this missing feature on occasion by adding multiple blocks to a Group block and editing its options. The limitation with that method is that the Group block only supports custom text and background colors. It is nice to see the Gutenberg development team tackling this much-needed feature. It will at least allow some of us to do away with such hacks.

Search and Find New Blocks

Installing a block from the editor via the Gutenberg block directory search.
Adding a block via the block directory search feature.

In September 2019, Gutenberg plugin users received their first glimpse of the block directory search. The experimental feature first landed in version 6.5 and promised to revolutionize the block installation process. Users would be able to seamlessly add blocks from the WordPress block directory from the editing screen. No need to save the current post and head over to the plugins screen. Just search, add a block, and continue writing.

Now, nearly 20 major releases later, the feature is no longer experimental. It is a fully-integrated part of the plugin and is expected to land in WordPress 5.5. That means it is time for Gutenberg users to begin heavily testing this feature and reporting any bugs. It also means it is time for plugin developers to step up their game and begin submitting more single-block plugins to the directory.

To use the new feature, users merely need to search for a block via the block inserter. If one is not installed, it will search for the block on WordPress.org. If one is found, Gutenberg will display an “Add Block” button. Once clicked, it will install the block plugin and insert the block into the post editor.

For the most part, it worked reasonably well in my tests. However, it was not without a few faults.

One issue I ran into was that the block plugin’s CSS did not take effect without reloading the page. Thinking this may have been a fluke, I tested again and ran into the same issue. Considering this was the Layout Grid block from Automattic, which needs specific CSS to align columns, the experience was not ideal. My content was not aligned in columns.

I also had the issue of installing a new block but WordPress not recognizing it as available to insert into the editor. When clicking the “Add Block” button a second time in this scenario, I received the “destination folder already exists” message. It was only after refreshing the page that I was able to use the block.

For this feature to land in core, it needs to be a seamless experience. Users should be able to add new blocks and use them on the fly. At least in my tests, this feature was not quite there. Maybe it is my environment. Maybe I just had some bad luck for the day, but it looks like there is still more work to be done before this is a prime-time feature.

Best Collaboration Software

Collaboration tools have changed the way people work—and for the better.

The days of knocking on office doors, leaving voicemails, or sending lengthy email chains with updates and attachments are long behind us. Modern technology makes it much easier for teams of all sizes to work together more efficiently.

With collaboration software, users can access a shared space with individual login information. The right team members will be notified with relevant updates, and everyone will have access to the information they need to get the job done.

Collaboration software is great for managing ongoing tasks and communication, as well as team projects at scale.

By using collaboration tools, you’ll also improve workflow efficiency with people working from multiple locations, which is crucial for today’s business environment. With remote workers, teams in different buildings, freelancers, contractors, and clients always in different locations, collaboration software acts as a centralized digital hub for everyone.

The Top 7 Best Collaboration Software

After researching and demoing the best collaboration tools on the market today, I narrowed down my list of recommendations to seven. I’ll cover the features, benefits, pricing, use cases, and potential drawbacks in an in-depth review for each one below.

#1 – Ryver — Best Overall Collaboration Software

• Starts at $49
• Unlimited chat
• Unlimited file sharing
• 14 day free trial
Start for free

Ryver is an all-in-one team collaboration app. Instead of using multiple tools and resources to communicate with your team, Ryver provides everything you need to collaborate at scale.

The software was initially created back in 2014 to solve the business “email problem.” which is the outdated way that most teams were collaborating. But since then, the software has quickly evolved to meet the growing demands of the modern workforce.

Ryver contains features for group messaging, task management, as well as voice and video calling.

Some of the top benefits of using Ryver’s collaboration software include:

  • Unlimited chat and topics
  • Unlimited file sharing
  • Unlimited tasks
  • Unlimited team and personal task boards
  • One-click calling
  • Single sign-on (SSO)
  • Premium support

Ryver integrates with other tools that your team is already using, like Gmail, Salesforce, Zendesk, Trello, Dropbox, MailChimp, and more.

Here’s a quick glance at the plans and price pricing for Ryver:

  • Starter — $49 per month
  • Unlimited — $79 per month
  • Enterprise — $149 per month

The Starter plan comes with up to 12 users and all of the basic collaboration features you need. As the name implies, the Unlimited plan is for an unlimited number of users. Advanced features like SSO and Premium support are only available at the Enterprise plan level.

It’s also worth noting that the voice and video calling is still in the beta stages. The software can support up to five users per call.

You can try Ryver free for 14 days; no credit card required.

#2 – Slack — Best For Real-Time Team Communication

• Starts at $6.67
• 2,000+ integrations
• Unlimited messaging
• Voice and video calling
Try for free

Slack has quickly become an industry leader in team collaboration. From startups to enterprises and everything in between, this software is used by thousands of teams across the world. It’s trusted by Airbnb, Ticketmaster, Target, Oracle, Time Magazine, Samsung, and more. We even use Slack to collaborate here at Quick Sprout.

Compared to email, Slack is just a better way to manage team communication in real-time.

The software integrates with 2,000+ third-party apps like Google Drive, Asana, GitHub, Salesforce, Trello, and more.

Set up Slack channels to collaborate by project, team, client, or any other way that your organization sees fit. The software supports group messaging and updates, as well as one-on-one conversations for individual members.

Slack supports voice and video calling as well as integrated file sharing.

Pricing for Slack Standard starts at $6.67 per user per month with an annual contract. Slack Plus starts at $12.50 and comes with advanced features like user provisioning, SSO, and corporate exports for all messages.

For those of you who have advanced security needs, such as HIPAA-compliant messaging and file collaboration, contact the Slack sales team for a custom enterprise quote.

It’s worth noting that Slack is more of a communication tool than an all-in-one solution for project management—at least out of the box. You can always customize your Slack solution with apps and integrations.

#3 – Basecamp — Best For Remote Workers

• Free for basic use
• $99 for all features
• Project management tools
• Group chat and messaging
Start for free

Basecamp is branded as an all-in-one project management and team communication tool for working remotely. Whether your organization has always had a remote workforce or was recently forced to go remote due to current events, Basecamp should be a top consideration for your needs.

The software makes it easy to organize all remote collaboration in a single location. It’s easy to get started and works well at scale.

The dashboard is clean, organized, and has everything your remote team needs to work collaboratively.

Basecamp has tools for messaging, task lists, group chat, schedules, document sharing, and project management features, as well.

You can use Basecamp to split up virtual areas based on projects, departments, or teams. Add whoever needs to be involved in each area so they can work together. Basecamp allows users to customize how they are notified about updates. So you can easily pause notifications to avoid distractions after hours or when you’re working on crucial tasks.

The software has advanced tools for owners, executives, managers, and individual users as well. Employees can track assignments, schedules, and everything else on their plates. Managers can see a total overview of the entire team’s productivity.

Basecamp’s pricing is straightforward. The $99 per month flat rate includes:

  • Unlimited users
  • Unlimited projects
  • 500 GB storage
  • Project templates
  • Priority support
  • Company HQ
  • Team projects

There’s also a free plan for basic use, but it’s limited. The free plan supports up to three projects, 20 users, and 1 GB of storage. This is a fine option for freelancers, small teams, or individual users.

#4 – Asana — Best For Workflow Management

• Free for basic use
• Starts at $10.99
• Kanban boards
• 30 day free trial
Start for free

Asana is one of the world’s most popular project management tools. Teams of all sizes trust this software to manage both simple and complex projects at scale.

More than 70,000 organizations worldwide use Asana, including GE, NASA, The New York Times, Red Bull, and Deloitte.

It’s a popular tool for marketers, sales teams, operations, product development, and more. Asana uses Kanban boards for project management. But it also has various workflows like calendar tools, timelines, forms, productivity tools, and supports agile & scrum teams.

Asana has tools for automation to help you streamline and simplify tedious workflows. The software is exceptional out of the box but has 100+ third-party integrations so your team can access everything they need in a single place.

Create templates for common processes, use custom fields to track important information, control data, set privacy permissions, and do more with Asana for team collaboration.

Here’s a look at the plans and price points of Asana:

  • Basic — Free forever
  • Premium — Starts at $10.99 per user per month
  • Business — Starts at $24.99 per user per month
  • Enterprise — Custom pricing

Unfortunately, Asana does not have a live chat or instant messaging feature. Communication would have to take place on individual boards, projects, and tasks.

Try Asana free for 30 days.

#5 – Zoho Projects — Best Collaboration Software For Project Management

• Starts at $3
• Chat rooms and boards
• Gantt charts and Kanban boards
• 10 day free trial
Start for free

Zoho Projects is another all-in-one collaboration solution for project management. It’s an affordable and user-friendly option for businesses of all shapes and sizes.

You can use Zoho Projects to fully customize your experience. The software makes it easy to create personalized layouts, fields, workflows, and statuses.

Top features and benefits of Zoho Projects include:

  • Gantt charts
  • Automations
  • Task management
  • Reporting
  • Time tracking
  • Kanban boards

The software also supports real-time collaboration with chat rooms and boards. Whether you want to initiate a discussion with one person or your entire group, Zoho Projects makes this possible.

Pricing for Zoho Projects starts at $3 per user per month, with a six-user minimum.

The price per user increases based on team size and features. But even the most expensive plan is just $6 per month. Unlimited projects start at $4 per user. That plan has a 12-user minimum and 50-user maximum.

Try Zoho Projects free for ten days. Save 17% when you sign up for annual billing.

#6 – Flowdock — Best Cheap Collaboration Software

• Free for up to 5 users
• Starts at $3 per month
• Video chat and screen sharing
• 100+ integrations
Start for free

Flowdock isn’t quite as popular or well-known as some of the other solutions on our list. But it’s still an excellent choice for collaboration software, especially for those of you on a tight budget.

The software starts at $3 per user per month, with no user minimums. So it’s a great choice for smaller teams as well. In fact, Flowdock is free for teams of five or less.

Flowdock is designed to help teams working in multiple locations and time zones stay organized. Some of the top features and benefits include:

  • Team threads
  • 1:1 communication
  • Instant video chat
  • Screen sharing
  • 100+ integrations

For advanced features like data encryption, SSO, and more administrative-level customization, Flowdock has an enterprise plan for $9 per user per month.

Overall, Flowdock isn’t as flashy or feature-rich as some of the other solutions on our list. But it’s cheap and gets the job done. I’d definitely recommend it to smaller teams as a more cost-effective alternative to other options on the market.

#7 – Podio — Best Custom Collaboration Software

• Starts at $9
• Free for non-employee users
• Advanced customizations
• Automate workflows
Start for free

Podio is another all-in-one solution for collaboration and project management. It’s trusted by organizations like Volvo, the National Football League, and 500,000+ teams worldwide.

The best part about Podio is its flexibility. Rather than having to change your current workflows and environment to match the capabilities of your collaboration software, Podio makes it easy to choose the features you need to suit your existing structure.

Podio allows you to set up individual employee profiles with information like their contact details, location, skills, and a short bio. This makes it much easier for team members to find basic info for collaborating with the right person.

Create custom templates to store vital information. Make documents accessible for everyone on your team. Use Podio to create tasks, automate workflows, and add notes to projects.

You can set up an activity feed so everyone within a certain team or department can see what’s going on. View team bulletins, comments, and discuss news or updates on the status of assignments. These are just a handful of the potential use cases for Podio.

Pricing for the software is surprisingly affordable for how powerful it is:

  • Free — $0 for up to five employees
  • Basic — $9 per employee per month
  • Plus — $14 per employee per month
  • Premium — $24 per employee per month

If you’re managing clients or freelancers, you can add those external users to your Podio plan for free.

For those of you with complex needs that want complete customization over your collaboration software, Podio will be your best option. It’s arguably the most versatile and robust solution on the market today.

How to Find the Best Collaboration Software For You

There are certain factors that must be taken into consideration when you’re shopping around for collaboration software. Generally speaking, there is no “best for everyone” tool.

This is the methodology that I used to narrow down the winners in this guide. I’ll explain these elements in greater detail below, which will make it easier to for you to determine the best software for your needs.

Type of Software

Not all collaboration software is the same.

Some tools are all-in-one software for collaboration and project management. In addition to file sharing and messaging, you’ll benefit from features like Kanban boards, Gantt charts, workflow management, automations, and more.

Other solutions just focus on communication, with features like live chat, voice calls, video calls, and screen sharing.

Not every project management solution has tools for real-time messaging or calling. So just figure out which feature matters most to you while you’re evaluating options.

Team Size

Generally speaking, teams of five and teams of 50 will have different needs.

Larger teams need features to segment users by department, project, or another category. Otherwise, things will get too messy if every single person in your organization sees status updates, files, and messages that are irrelevant to their job or project.

You might also want to consider software with management or admin features for adding team members and keeping an eye on everyone’s progress. This is more common in a project management solution.

It’s also worth noting that smaller teams might be eligible for free collaboration software from certain providers.

Integrations and Customization

It’s important for collaboration software to integrate with tools that you’re already using. Some of the software on our list integrates with hundreds or even up to 2,000+ third-party apps.

Ideally, you’ll want your tool to have as much functionality out of the box, but having the ability to customize your solution is nice to have. Just make sure everything integrates seamlessly. I’d recommend testing out the software with a free trial just to be certain that the features you want are working properly.

Ease of Use

At the end of the day, collaboration software is designed to make things more efficient.

If your team is spending extra time trying to navigate and figure out how to use different tools, it defeats the purpose. Some software has a sharper learning curve than others. But with that said, most of the solutions in this guide are fairly easy to use. Larger teams may want to consider using software with priority support, in case your staff needs help along the way.

Conclusion

What’s the best collaboration software on the market today? Ryver is our top overall recommendation.

However, there are plenty of other viable alternatives, depending on your specific needs. Slack is the best choice for real-time communication. Try Basecamp for remote teams and Asana to manage workflows. Flowdock is perfect for businesses on a tight budget.

For those of you seeking an all-in-one solution for team collaboration and project management, we recommend Zoho Projects. If you need advanced customization, try Podio.

Regardless of your team size, industry, or collaboration needs, you can use this guide to find the perfect solution for your business.

How to Make localStorage Reactive in Vue

Reactivity is one of Vue’s greatest features. It is also one of the most mysterious if you don’t know what it’s doing behind the scenes. Like, why does it work with objects and arrays and not with other things, like localStorage?

Let’s answer that that question, and while we’re at it, make Vue reactivity work with localStorage.

If we were to run the following code, we would see that the counter being displayed as a static value and not change like we might expect it to because of the interval changing the value in localStorage.

new Vue({
  el: "#counter",
  data: () => ({
    counter: localStorage.getItem("counter")
  }),
  computed: {
    even() {
      return this.counter % 2 == 0;
    }
  },
  template: `<div>
    <div>Counter: {{ counter }}</div>
    <div>Counter is {{ even ? 'even' : 'odd' }}</div>
  </div>`
});
// some-other-file.js
setInterval(() => {
  const counter = localStorage.getItem("counter");
  localStorage.setItem("counter", +counter + 1);
}, 1000);

While the counter property inside the Vue instance is reactive, it won’t change just because we changed its origin in localStorage

There are multiple solutions for this, the nicest perhaps is using Vuex and keep the store value in sync with localStorage. But what if we need something simple like what we have in this example? We have to take a dive in how Vue’s reactivity system works.

Reactivity in Vue

When Vue initializes a component instance, it observes the data option. This means it walks through all of the properties in data and converts them to getters/setters using Object.defineProperty. By having a custom setter for each property, Vue knows when a property changes, and it can notify the dependents that need to react to the change. How does it know which dependents rely on a property? By tapping into the getters, it can register when a computed property, watcher function, or  render function accesses a data prop.

// core/instance/state.js
function initData () {
  // ...
  observe(data)
}
// core/observer/index.js
export function observe (value) {
  // ...
  new Observer(value)
  // ...
}

export class Observer {
  // ...
  constructor (value) {
    // ...
    this.walk(value)
  }
  
  walk (obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i])
    }
  }
} 


export function defineReactive (obj, key, ...) {
  const dep = new Dep()
  // ...
  Object.defineProperty(obj, key, {
    // ...
    get() {
      // ...
      dep.depend()
      // ...
    },
    set(newVal) {
      // ...
      dep.notify()
    }
  })
}

So, why isn’t localStorage reactive? Because it’s not an object with properties.

But wait. We can’t define getters and setters with arrays either, yet arrays in Vue are still reactive. That’s because arrays are a special case in Vue. In order to have reactive arrays, Vue overrides array methods behind the scenes and patches them together with Vue’s reactivity system.

Could we do something similar with localStorage?

Overriding localStorage functions

As a first try, we can fix our initial example by overriding localStorage methods to keep track which component instances requested a localStorage item.

// A map between localStorage item keys and a list of Vue instances that depend on it
const storeItemSubscribers = {};


const getItem = window.localStorage.getItem;
localStorage.getItem = (key, target) => {
  console.info("Getting", key);


  // Collect dependent Vue instance
  if (!storeItemSubscribers[key]) storeItemSubscribers[key] = [];
  if (target) storeItemSubscribers[key].push(target);


  // Call the original function 
  return getItem.call(localStorage, key);
};


const setItem = window.localStorage.setItem;
localStorage.setItem = (key, value) => {
  console.info("Setting", key, value);


  // Update the value in the dependent Vue instances
  if (storeItemSubscribers[key]) {
    storeItemSubscribers[key].forEach((dep) => {
      if (dep.hasOwnProperty(key)) dep[key] = value;
    });
  }


  // Call the original function
  setItem.call(localStorage, key, value);
};
new Vue({
  el: "#counter",
  data: function() {
    return {
      counter: localStorage.getItem("counter", this) // We need to pass 'this' for now
    }
  },
  computed: {
    even() {
      return this.counter % 2 == 0;
    }
  },
  template: `<div>
    <div>Counter: {{ counter }}</div>
    <div>Counter is {{ even ? 'even' : 'odd' }}</div>
  </div>`
});
setInterval(() => {
  const counter = localStorage.getItem("counter");
  localStorage.setItem("counter", +counter + 1);
}, 1000);

In this example, we redefine getItem and setItem in order to collect and and notify the components that depend on localStorage items. In the new getItem, we note which component requests which item, and in setItems, we reach out to all the components that requested the item and rewrite their data prop.

In order to make the code above work, we have to pass on a reference to the component instance to getItem and that changes its function signature. We also can’t use the arrow function anymore because we otherwise wouldn’t have the correct this value.

If we want to do better, we have to dig deeper. For example, how could we keep track of dependents without explicitly passing them on?

How Vue collects dependencies

For inspiration, we can go back to Vue’s reactivity system. We previously saw that a data property’s getter will subscribe the caller to the further changes of the property when the data property is accessed. But how does it know who made the call? When we get a data prop, its getter function doesn’t have any input regarding who the caller was. Getter functions have no inputs. How does it know who to register as a dependent? 

Each data property maintains a list of its dependents that need to react in a Dep class. If we dig deeper in this class, we can see that the dependent itself is already defined in a static target variable whenever it is registered. This target is set by a so-far-mysterious Watcher class. In fact, when a data property changes, these watchers will be actually notified, and they will initiate the re-rendering of the component or the recalculation of a computed property.

But, again, who they are?

When Vue makes the data option observable, it also creates watchers for each computed property function, as well as all the watch functions (which shouldn’t be confused with the Watcher class), and the render function of every component instance. Watchers are like companions for these functions. They mainly do two things:

  1. They evaluate the function when they are created. This triggers the collection of dependencies.
  2. They re-run their function when they are notified that a value they rely on has changed. This will ultimately recalculate a computed property or re-render a whole component.

There is an important step that happens before watchers call the function they are responsible for: they set themselves as target in a static variable in the Dep class. This makes sure the they are registered as dependent when a reactive data property is accessed.

Keeping track of who called localStorage

We can’t exactly do that because we don’t have access to the inner mechanics of Vue. However, we can use the idea from Vue that lets a watcher set the target in a static property before it calls the function it is responsible for. Could we set a reference to the component instance before localStorage gets called?

If we assume that localStorage gets called while setting the data option, then we can hook into beforeCreate and created. These two hooks get triggered before and after initializing the data option, so we can set, then clear, a target variable with a reference to the current component instance (which we have access to in lifecycle hooks). Then, in our custom getters, we can register this target as a dependent.

The final bit we have to do is make these lifecycle hooks part of all our components. We can do that with a global mixin for the whole project.

// A map between localStorage item keys and a list of Vue instances that depend on it
const storeItemSubscribers = {};

// The Vue instance that is currently being initialised
let target = undefined;

const getItem = window.localStorage.getItem;
localStorage.getItem = (key) => {
  console.info("Getting", key);

  // Collect dependent Vue instance
  if (!storeItemSubscribers[key]) storeItemSubscribers[key] = [];
  if (target) storeItemSubscribers[key].push(target);

  // Call the original function
  return getItem.call(localStorage, key);
};

const setItem = window.localStorage.setItem;
localStorage.setItem = (key, value) => {
  console.info("Setting", key, value);

  // Update the value in the dependent Vue instances
  if (storeItemSubscribers[key]) {
    storeItemSubscribers[key].forEach((dep) => {
      if (dep.hasOwnProperty(key)) dep[key] = value;
    });
  }
  
  // Call the original function
  setItem.call(localStorage, key, value);
};

Vue.mixin({
  beforeCreate() {
    console.log("beforeCreate", this._uid);
    target = this;
  },
  created() {
    console.log("created", this._uid);
    target = undefined;
  }
});

Now, when we run our initial example, we will get a counter that increases the number every second.

new Vue({
  el: "#counter",
  data: () => ({
    counter: localStorage.getItem("counter")
  }),
  computed: {
    even() {
      return this.counter % 2 == 0;
    }
  },
  template: `<div class="component">
    <div>Counter: {{ counter }}</div>
    <div>Counter is {{ even ? 'even' : 'odd' }}</div>
  </div>`
});
setInterval(() => {
  const counter = localStorage.getItem("counter");
  localStorage.setItem("counter", +counter + 1);
}, 1000);

The end of our thought experiment

While we solved our initial problem, keep in mind that this is mostly a thought experiment. It lacks several features, like handling removed items and unmounted component instances. It also comes with restrictions, like the property name of the component instance requires the same name as the item stored in localStorage. That said, the primary goal is to get a better idea of how Vue reactivity works behind the scenes and get the most out of it, so that’s what I hope you get out of all this.

The post How to Make localStorage Reactive in Vue appeared first on CSS-Tricks.

A Glitchy Grid Layout Slideshow

I love experimenting with irregular layouts. I wanted to try to take this custom “background” grid one level further and add a stack-like navigation effect. I liked how it turned out but there was some Jazz missing. It was calling for some dramatic effect, like a glitch animation! So I added it and it was the missing bit indeed.

So, here it is: a glitchy grid layout slideshow with a magnetic link effect and a quick, stack-like animation when navigating.

Here’s the initial view:

When clicking on one of the navigation buttons, there’s a quick stacking animation:

When hovering over the “Enter” button, a glitch animation happens on all the images and texts. This is how it all comes together:

I really hope this comes in handy as a starting point for your ideas! Let me know what you think @codrops or @crnacura 🙂

The post A Glitchy Grid Layout Slideshow appeared first on Codrops.