Turning complexity into clarity.

Senior Front-end Developer - MetaOptima Technology - Vancouver, BC

NodeJS jobs - Wed, 12/05/2018 - 10:56
Python/Django, NodeJS, JSON, RESTful APIs, Git, Linux, Gulp, PostgreSQL/MySQL, SocketIO. We are one of Vancouver’s fastest growing startups looking for a highly...
From MetaOptima Technology - Wed, 05 Dec 2018 10:56:37 GMT - View all Vancouver, BC jobs
Categories: NodeJS

Dries Buytaert: Drupal's commitment to accessibility

News from Planet Drupal - Wed, 12/05/2018 - 10:56

Last week, WordPress Tavern picked up my blog post about Drupal 8's upcoming Layout Builder.

While I'm grateful that WordPress Tavern covered Drupal's Layout Builder, it is not surprising that the majority of WordPress Tavern's blog post alludes to the potential challenges with accessibility. After all, Gutenberg's lack of accessibility has been a big topic of debate, and a point of frustration in the WordPress community.

I understand why organizations might be tempted to de-prioritize accessibility. Making a complex web application accessible can be a lot of work, and the pressure to ship early can be high.

In the past, I've been tempted to skip accessibility features myself. I believed that because accessibility features benefited a small group of people only, they could come in a follow-up release.

Today, I've come to believe that accessibility is not something you do for a small group of people. Accessibility is about promoting inclusion. When the product you use daily is accessible, it means that we all get to work with a greater number and a greater variety of colleagues. Accessibility benefits everyone.

As you can see in Drupal's Values and Principles, we are committed to building software that everyone can use. Accessibility should always be a priority. Making capabilities like the Layout Builder accessible is core to Drupal's DNA.

Drupal's Values and Principles translate into our development process, as what we call an accessibility gate, where we set a clearly defined "must-have bar". Prioritizing accessibility also means that we commit to trying to iteratively improve accessibility beyond that minimum over time.

Together with the accessibility maintainers, we jointly agreed that:

  1. Our first priority is WCAG 2.0 AA conformance. This means that in order to be released as a stable system, the Layout Builder must reach Level AA conformance with WCAG. Without WCAG 2.0 AA conformance, we won't release a stable version of Layout Builder.
  2. Our next priority is WCAG 2.1 AA conformance. We're thrilled at the greater inclusion provided by these new guidelines, and will strive to achieve as much of it as we can before release. Because these guidelines are still new (formally approved in June 2018), we won't hold up releasing the stable version of Layout Builder on them, but are committed to implementing them as quickly as we're able to, even if some of the items are after initial release.
  3. While WCAG AAA conformance is not something currently being pursued, there are aspects of AAA that we are discussing adopting in the future. For example, the new 2.1 AAA "Animations from Interactions", which can be framed as an achievable design constraint: anywhere an animation is used, we must ensure designs are understandable/operable for those who cannot or choose not to use animations.

Drupal's commitment to accessibility is one of the things that makes Drupal's upcoming Layout Builder special: it will not only bring tremendous and new capabilities to Drupal, it will also do so without excluding a large portion of current and potential users. We all benefit from that!

Categories: Drupal

Senior Software Developer - Adacado.com - Vancouver, BC

NodeJS jobs - Wed, 12/05/2018 - 09:59
Kubernetes, Golang, Maven, Git, Tomcat, Nginx, MySQL/MariaDB, Redis, ElasticSearch, ActiveMQ, Akka, ReactJS, NodeJS, Webpack, Python, Hibernate, Spring,...
From Adacado.com - Wed, 05 Dec 2018 09:59:45 GMT - View all Vancouver, BC jobs
Categories: NodeJS

Senior Software Architect - Adacado.com - Vancouver, BC

NodeJS jobs - Wed, 12/05/2018 - 09:59
Kubernetes, Golang, Maven, Java, Tomcat, Nginx, MySQL/MariaDB, Redis, ElasticSearch, ActiveMQ, Akka, NodeJS, Python, Hibernate, Spring, Aerospike, Apache Spark,...
From Adacado.com - Wed, 05 Dec 2018 09:59:45 GMT - View all Vancouver, BC jobs
Categories: NodeJS

Online Course Creation Advisory and Partial Manual Help To Set up All Technology - Upwork

WordPress Work From UpWork - Wed, 12/05/2018 - 08:10
THE CONTEXT

I am a serial tech entrepreneur who has built several websites and managed several teams.
https://www.linkedin.com/in/paolo-messina/

THE PROBLEM
I am starting an online class on "become a Machine learning manager" for managers worldwide.
Although I know how ot create a wordpress site, I have an account on teachable and I know how to set up an email marketig system etc... putting the pieces together is wasting me lot of time.

THE GOAL
In less than a week I want to create all the website, marketing content and marketing funnel to start the PRE-LAUNCH. Basically, I want to sell the course even before I have it to my linkedin connections.

THE POTENTIAL HELP NEEDED( TASK DEFINITION)

1) Consulting on how to integrate Wordpress and Teachable
2) Consulting on How to integrate the funnel software with Teachable , this is being a pain.
3) Optimize the funnel for the specific objective we have now e.g. pre-enroll students like 6 weeks before the course launches. For example, I have a dilemma whether going with a Webinar approach or a multiple emails with several videos.
4) I am undecided on how much time invest on the traditional funnel given that I want to use my linkedin network to sell the pre-sale. So some guidance on linkedin network marketing and how to decide maybe very helpful.
5) Potentially if the cost is not too high I may outsource the creation of all website/funnel/plugins and I may focus on creating the marketing content e.g. lead magnet, top of the funnel free content, potential linkedin ads.  


WHAT I ASK

1) Define very specifically how you can address all of the 4 points above, if you can not do all the 4 define how you could source the missing piece and what would be the indicative cost.
2) Make a clear offer on the estimated total cost and delivery time
3) Specifically, discuss only the elements of your experience that are relevant to my pain points. DO not overwhelm me with material about everything.  

Some Info the course is:
https://innodemia.teachable.com/

My competitors are:
https://executive.mit.edu/openenrollment/program/artificial-intelligence-implications-for-business-strategy-self-paced-online/#.XAd1hWhKiUk

https://www.getsmarter.com/courses/us/mit-artificial-intelligence-online-short-course

https://www.getsmarter.com/search?utf8=%E2%9C%93&query=Deep+Learning%3A+A+Critical+Appraisal+&category=no-results


Posted On: December 05, 2018 11:11 UTC
Category: Design & Creative > Other - Design & Creative
Skills: aWeber, ClickFunnels, Email Marketing, Internet Marketing, LinkedIn Development, Social Media Marketing, Teachable, Web Design, Website Development, WordPress
Country: United States
click to apply

Website Design - Insects and Organic Gardening - Upwork

WordPress Work From UpWork - Wed, 12/05/2018 - 02:50
I am looking for a web designer for a website I need to build about insects and organic gardening.

Here are some comments:

Pages:  
We’re envisioning around 5 different type pages.  I am attaching a content map and have only marked the pages that I think need design.  The rest can be adapted from these.

- Home
- Blog
- Content pages (they talk about different subjects like soil, plants, planting, pest control, etc)
- Insect pages (like a wiki page of each insect)
- Insect Gallery (photos of all insects with buttons to filter)

Photographs
They will use mostly their own photographs as they are very specialised and they are part of their own collection. (insect database and photos of different projects)
These photos are not great, but they have been collected on the field for many years, so we can’t do much about this.
We might need a few nice stock ones for home page and banners (maybe?).  If we use good stock photos for home page we could create a good first impression (although I realise this might not work well as it will increase the contrast with the other photos that are not great).

Brand
They are farmers and they don’t have a brand as such.  So we will need to come up with a nice logo for the website as well.   

Web Development
We already have a developer who will create the website using Wordpress / Oxygen builder.  So we are only looking for a designer at this stage.

Purpose of website / Design
A bit more insight of what we’re after.  We're after a design that is earthy, organic, tidy, relaxing, pleasant to the eye and easy to read.  Something that connect people to earth, to nature.

The purpose of this website is more idealistic rather than a business.  They want to help people that want to grow their food organically.


-----
Please send me a quote and ONLY RELEVANT samples of your designs
(this means, designs related to nature, farming, etc).  

Please do not send designs of other types of websites as your proposal will be deleted.


Posted On: December 05, 2018 11:11 UTC
Category: Web, Mobile & Software Dev > Web & Mobile Design
Skills: Graphic Design, UX Design, Web Design
Country: Australia
click to apply

Lead Data Scientist - Invoice Simple - Vancouver, BC

NodeJS jobs - Wed, 12/05/2018 - 00:44
Written Typecript and/or Javascript on the backend with NodeJS. Invoice Simple's mission is to build the world's simplest way to run and grow a small business....
From GlassDoor.com - Wed, 05 Dec 2018 00:44:30 GMT - View all Vancouver, BC jobs
Categories: NodeJS

Senior Front-end Engineer - MetaOptima - Vancouver, BC

NodeJS jobs - Wed, 12/05/2018 - 00:30
Python/Django, NodeJS, JSON, RESTful APIs, Git, Linux, Gulp, PostgreSQL/MySQL, SocketIO. We are one of Vancouver’s fastest growing startups looking for a highly...
From GlassDoor.com - Wed, 05 Dec 2018 00:30:51 GMT - View all Vancouver, BC jobs
Categories: NodeJS

Full Stack Senior Web Developer - Real Estate WEbmasters - Nanaimo, BC

NodeJS jobs - Tue, 12/04/2018 - 23:30
JavaScript (ES5, ES6+), NodeJS, Vue.js, webpack. Real Estate Webmasters is a state-of-the-art website vendor, specializing in luxury sites for the world’s top...
From GlassDoor.com - Tue, 04 Dec 2018 23:30:36 GMT - View all Nanaimo, BC jobs
Categories: NodeJS

iOS Software Engineer - Invoice Simple - Vancouver, BC

NodeJS jobs - Tue, 12/04/2018 - 23:22
NodeJS backend in Typescript. Want to join one of Canada's fastest growing startups?...
From GlassDoor.com - Tue, 04 Dec 2018 23:22:39 GMT - View all Vancouver, BC jobs
Categories: NodeJS

Web Developer needed for developing our website to be high end luxurious looking website. - Upwork

WordPress Work From UpWork - Tue, 12/04/2018 - 23:15
Looking for someone who can rise our website to higher level and make it high end luxurious looking website with good pictures, videos, and creative contents.
- Must has knowledge of Wordpress and Woo Commerce.
- Able to meet time sensitive deadlines.
- Design graphics as required.
- Digital content development, assist in editing and creating content in various digital formats.
I will provide a test webpage to work on at the beginning after that you can start working on the official website.


Posted On: December 05, 2018 11:11 UTC
Category: Web, Mobile & Software Dev > Web Development
Skills: Adobe Photoshop, Content Writing, Graphic Design, HTML, Web Design, Website Development, WordPress
Country: Canada
click to apply

UI Engineer - FORESEE - Vancouver, BC

NodeJS jobs - Tue, 12/04/2018 - 22:37
Experience with some of ES6, NodeJS, Express JS, AWS or similar cloud solution. Founded in 2001, ForeSee is the pioneering leader in Voice of Customer (VOC)...
From GlassDoor.com - Tue, 04 Dec 2018 22:37:34 GMT - View all Vancouver, BC jobs
Categories: NodeJS

Kanopi Studios: Kanopi 2019 DrupalCon Seattle Sessions

News from Planet Drupal - Tue, 12/04/2018 - 20:29

We are thrilled to have had three of our sessions chosen for DrupalCon Seattle in April 2019. You’ll find us at the booth, in the hallway, and out and about in Seattle, but make sure to visit us in our three Builder Track sessions:

Keep Living the Dream! How to work remotely AND foster a happy, balanced life

Virtual. Remote. Distributed. Pick your label. This style of organization is becoming wildly more in demand and popular among many Drupal shops. While many folks have gone remote, some people find the experience quite isolating and disconnected.

In this session we will talk about how to be the best remote employee, as well as provide ideas if you are a leader of a remote team. We will talk about key tactics to keep you (and all other staff) inspired, creative, productive and most importantly, happy!

Presenter: Anne Stefanyk

Beyond the Screen Reader: Humanizing Accessibility

We talk a lot about the basics of accessibility. But what does it really mean to be accessible? How do we ensure we are including everyone and empowering every user in every scenario to use our sites, products, and devices? We think about deaf and blind users, we check contrast for colorblind users. We consider the elderly and sometimes those with dyslexia. Are we including trans folks? Parents? The chronically ill? People with limited literacy? The injured? People in a major emergency? Who are we designing for? What should we be considering?

If you’re wondering how these folks might be affected by accessibility and you want your website to be inclusive for everyone, this is the session for you.

Presenter: Alanna Burke

Deep Cleaning: Creating franchise model efficiencies with Drupal 8

COIT offers cleaning and 24/7 emergency restoration services. Their 100+ locations serve more than 12 million homes & businesses across the United States and Canada.

It had been years since the COIT site had been updated, and it posed a host of technical challenges. Franchise content optimizations resulted in redundant updates for the SEO team. The mobile experience wasn’t optimized for conversions. There was a mountain of custom technical debt. And despite the current content administrative challenges, the localized experience lacked the level of context-awareness that consumers have come to expect. It was time for COIT to clean up its own mess.

In this case study we will cover the more technical parts of this Drupal 8 implementation: how we kept a multinational but distinctly separate brand presence with geolocative features, maintained custom promotions tailored to each franchise location, and kept the existing hard-won SEO and SEM business drivers intact.

Presenters: Anne Stefanyk and Katherine White

The post Kanopi 2019 DrupalCon Seattle Sessions appeared first on Kanopi Studios.

Categories: Drupal

Google's, "Mobile-First indexing"–Are You Familiar With How it Works? (Need Help Implementing) - Upwork

WordPress Work From UpWork - Tue, 12/04/2018 - 14:56
I am looking to hire a developer to help make GoldenFS.org in line with best practices for mobile-first indexing.  Currently, our site has AMP and non-AMP pages, but Google stated that Google "prefers to index the mobile version of the non-AMP page." (here's Google's official statement on this matter:
https://webmasters.googleblog.com/2018/03/rolling-out-mobile-first-indexing.html)

If you look at goldenfs.org and its individual pages:

Here are a few examples:

https://goldenfs.org/arizona-debt-relief/
https://goldenfs.org/debt-relief-blog/
https://goldenfs.org/best-financial-advice/

(multiple templates)

You will see on these pages that Google's page speed score is low. We need to get this up to 95+!!

Right now, it's under 65.

To recap, Google's crawling, indexing, and ranking systems have typically used the desktop version of a page's content, which may cause issues for mobile searchers when that version is vastly different from the mobile version. Mobile-first indexing means that Google will use the mobile version of the page for indexing and ranking, to better help our – primarily mobile – users find what they're looking for.

Statement from Google: "Google is notifying sites that are migrating to mobile-first indexing via Search Console. Site owners will see significantly increased crawl rate from the Smartphone Googlebot. Additionally, Google will show the mobile version of pages in Search results and Google cached pages."

Here are the instructions on how to do this, from Google:
https://developers.google.com/search/mobile-sites/mobile-first-indexing
(It covers how sites using responsive web design or dynamic serving are generally set for mobile-first indexing. For sites that have AMP and non-AMP pages, Google will prefer to index the mobile version of the non-AMP page.)

***I am interested in doing this for a flat fee, so please include what your flat fee would be to ensure all of the pages, including all 3 examples I Provided above, are in line with Google's best practices for mobile first indexing.***


Posted On: December 04, 2018 21:11 UTC
Category: Web, Mobile & Software Dev > Web & Mobile Design
Skills: HTML, HTML5, jQuery, Web Design, Website Development, WordPress
Country: United States
click to apply

Web design for marketing agency site (in Wordpress) - Upwork

WordPress Work From UpWork - Tue, 12/04/2018 - 14:03
I run a small marketing consulting agency and built my site. PLEASE CONFIRM IN YOUR APPLICATION THAT YOU CAN ADDRESS POINTS 1-4 BELOW.

Looking for someone to review my new site and redesign it. The site was built in wordpress. All the new pages that were created are listed below. I will need you to:
1. redesign every page as you best you see fit, while maintaining the current text and order of content blocks.
2. Create/buy a couple of images to replace the current ones (the images and videos you see now on the site where either created or bought. You may choose to keep them or replace them with stock…up to you). I don’t have aan unlimited budget so please be mindful in trying to use as many free images as you can!
3. The theme comes with default font, so this is the font we will need to use UNLESS you strongly believe a new font would make a world of difference
4. Please confirm whether you are experienced with wordpress and can update the changes yourself or you will need my dev team to do it.

I will give you the logo and colors for the logo. Current colors throughout the site where used from logo. You may use those colors throughout the site if you see fit, or choose your own colors.

I want a site that looks 100% professional, clean and state of the art.

Pages:

1. HOME PAGE NEW - https://mobileevco.com/home1/
2. ASO PAGE NEW - https://mobileevco.com/app-store-optimization-1/
3. USER ACQUISITION PAGE NEW - https://mobileevco.com/user-acquisition-2/
4. CONTACT US FORM NEW - https://mobileevco.com/contact-us-3/ - We have created 6 colored boxes to display addresses of your 6 offices worldwide.
5. THE TEAM NEW - https://mobileevco.com/team2/ - In this page we have displayed names of 6 offices and placed a Contact us button below them. We propose this section of WHERE THE MAGIC HAPPENS must be common on all pages.


Posted On: December 04, 2018 21:11 UTC
Category: Web, Mobile & Software Dev > Web & Mobile Design
Skills: Adobe Illustrator, Adobe InDesign, Adobe Photoshop, Graphic Design, Illustration, Photo Editing, Web Design, WordPress
Country: United States
click to apply

Need LANDING Website for Tech Startup - Upwork

WordPress Work From UpWork - Tue, 12/04/2018 - 11:24
For my recently founded Tech Startup, I need a small and short landing page with innovative, beautiful and at the same time futuristic and technological looking look. The example that reflects my needs as best is the following:

https://the8760.com/

I do not need more text or content. I can fit in my content and text perfectly into this one.

I am searching for a Front End Developer with the needed expertise in the required fields.


Posted On: December 04, 2018 11:41 UTC
Category: Web, Mobile & Software Dev > Web Development
Country: Germany
click to apply

ComputerMinds.co.uk: Open links in popups with Foundation

News from Planet Drupal - Tue, 12/04/2018 - 11:16

Let me take you on a journey. We'll pass by Drupal content renderer services, AJAX commands, javascript libraries and a popular front-end framework. If you've only heard of one or two of those things, come lean on the experience I took diving deep into Drupal. I'm pleased with where my adventure took me to, and maybe what I learned will be useful to you too.

Here's the end result: a contact form, launched from a button link in the site header, with the page beneath obscured by an overlay. The form allows site visitors to get in touch from any page, without leaving what they were looking at.

Drupal has its own API for making links launch dialogs (leveraging jQuery UI Dialogs). But our front-end of the site was built with Foundation, the super-popular theming framework, which provides components of its own that are much better for styling. We often base our bespoke themes on Foundation, and manipulate Drupal to fit.

We had already done some styling of Foundation's Reveal component. In those places, the markup to show in the popup is already in the page, but I didn't really want the form to be in the page until it was needed. Instead, AJAX could fetch it in. So I wondered if I could combine Drupal's AJAX APIs with Foundation's Reveal markup and styling. Come with me down the rabbit hole...

There are quite a few components in making this possible. Here's a diagram:

So it comes down to the following parts, which we'll explore together. Wherever custom code is needed, I've posted it in full later in this article.

  • A link that uses AJAX, with a dialog type set in an attribute.
  • Drupal builds the content of the page that was linked to.
  • Drupal's content view subscriber picks up that response and looks for a content renderer service that matches the dialog type.
  • The content renderer returns an AJAX command PHP class in its response, and attaches a javascript library that will contain a javascript AJAX command (a method).
  • That command returns the content to show in the popup, and that javascript method name.
  • The javascript method launches the popup containing the HTML content.

Let's start at the beginning: the link. Drupal's AJAX API for links is pretty neat. We trigger it with two things:

  1. A use-ajax class, which tells it to open that link via an AJAX call, returning just the main page content (e.g. without headers & footers), to be presented in your existing page.
  2. A data-dialog-type attribute, to instruct how that content should be presented. This can be used for the jQuery UI dialogs (written up elsewhere) or the newer off-canvas sidebar, for example.

I wanted to have a go at creating my own 'dialog type', which would be a Foundation Reveal popup. The HTML fetched by the AJAX call would be shown in it. Let's start with the basic markup I wanted to my link to have:

Enquire

This could either just be part of content, or I could get this into a template using a preprocess function that would build the link. Something like this:

<?php // $url could have come from $node->toUrl(), Url::fromRoute() or similar. // For this example, it's come from a contact form entity. $url->setOption('attributes', [ 'class' => [ 'use-ajax', ], // This attribute tells it to use our kind of dialog 'data-dialog-type' => 'reveal', ]); // The variable 'popup_launcher' is to be used in the template. $variables['popup_launcher'] = \Drupal\Core\Link::fromTextAndUrl(t('Enquire'), $url);

After much reading around and breakpoint debugging to figure it out, I discovered that dialog types are matched up to content rendering services. So I needed to define a new one of those, which I could base closely on Drupal's own DialogRenderer. Here's the definition from my module's mymodule.services.yml file:

services: main_content_renderer.foundation_reveal: class: Drupal\mymodule\Render\MainContent\FoundationReveal arguments: ['@title_resolver'] tags: - { name: render.main_content_renderer, format: drupal_reveal }

Adding the tag named 'render.main_content_renderer' means my class will be picked up by core's MainContentRenderersPass when building the container. Drupal's MainContentViewSubscriber will then consider it as a service that can render responses.

The 'format' part of the tag needs to be the value that our data-dialog-type attribute has, with (somewhat arbitrarily?) 'drupal_' prepended. The arguments will just be whatever the constructor for the class needs. I often write my class first and then go back to adjust the service definition once I know what it needs. But I'll be a good tour guide and show you things in order, rather than shuttling you backwards and forwards!

Onto that FoundationReveal service class now. I started out with a copy of core's own ModalRenderer which is a simple extension to the DialogRenderer class. Ultimately, that renderer is geared around returning an AJAX command (see the AJAX API documentation), which comes down to specifying a command to invoke in the client-side javascript with some parameters.

I would need my own command, and my FoundationReveal renderer would need to specify it to be used. That only two functional differences were needed in comparison to core's DialogRenderer:

  1. Attach a custom library, which would contain the actual javascript command to be invoked:
$main_content['#attached']['library'][] = 'mymodule/dialog.ajax';
  1. Return an AJAX command class, that will specify that javascript command (rather than the OpenDialogCommand command that DialogRenderer uses) - i.e. adding this to the returned $response:
new OpenFoundationRevealCommand('#mymodule-reveal')

We'll learn about that command class later!

So the renderer file, mymodule/src/Render/MainContent/FoundationReveal.php (in that location in order to match the namespace in the service file definition), looks like this - look out for those two tweaks:

<?php namespace Drupal\mymodule\Render\MainContent; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Render\MainContent\DialogRenderer; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\mymodule\Ajax\OpenFoundationRevealCommand; use Symfony\Component\HttpFoundation\Request; /** * Default main content renderer for foundation reveal requests. */ class FoundationReveal extends DialogRenderer { /** * {@inheritdoc} */ public function renderResponse(array $main_content, Request $request, RouteMatchInterface $route_match) { $response = new AjaxResponse(); // First render the main content, because it might provide a title. $content = drupal_render_root($main_content); // Attach the library necessary for using the OpenFoundationRevealCommand // and set the attachments for this Ajax response. $main_content['#attached']['library'][] = 'core/drupal.dialog.ajax'; $main_content['#attached']['library'][] = 'mymodule/dialog.ajax'; $response->setAttachments($main_content['#attached']); // Determine the title: use the title provided by the main content if any, // otherwise get it from the routing information. $title = isset($main_content['#title']) ? $main_content['#title'] : $this->titleResolver->getTitle($request, $route_match->getRouteObject()); // Determine the dialog options and the target for the OpenDialogCommand. $options = $request->request->get('dialogOptions', []); $response->addCommand(new OpenFoundationRevealCommand('#mymodule-reveal', $title, $content, $options)); return $response; } }

That AJAX command class, OpenFoundationRevealCommand sits in mymodule/src/Ajax/OpenFoundationRevealCommand.php. Its render() method is the key, it returns the command which will map to a javascript function, and the actual HTML under 'data'. Here's the code:

<?php namespace Drupal\mymodule\Ajax; use Drupal\Core\Ajax\OpenDialogCommand; use Drupal\Core\StringTranslation\StringTranslationTrait; /** * Defines an AJAX command to open certain content in a foundation reveal popup. * * @ingroup ajax */ class OpenFoundationRevealCommand extends OpenDialogCommand { use StringTranslationTrait; /** * Implements \Drupal\Core\Ajax\CommandInterface:render(). */ public function render() { return [ 'command' => 'openFoundationReveal', 'selector' => $this->selector, 'settings' => $this->settings, 'data' => $this->getRenderedContent(), 'dialogOptions' => $this->dialogOptions, ]; } /** * {@inheritdoc} */ protected function getRenderedContent() { if (empty($this->dialogOptions['title'])) { $title = ''; } else { $title = '' . $this->dialogOptions['title'] . ''; } $button = 't('Close') . '" type="button">×'; return '' . $title . parent::getRenderedContent() . '' . $button; } }

Now, I've mentioned that the command needs to match a javascript function. That means adding some new javascript to the page, which, in Drupal 8, we do by defining a library. My 'mymodule/dialog.ajax' library was attached in the middle of FoundationReveal above. My library file defines what actual javascript file to include - it is mymodule.libraries.yml and looks like this:

dialog.ajax: version: VERSION js: js/dialog.ajax.js: {} dependencies: - core/drupal.dialog.ajax

Then here's that actual mymodule/js/dialog.ajax.js file. It adds the 'openFoundationReveal' method to the prototype of the globally-accessible Drupal.AjaxCommands. That matches the command name returned by my OpenFoundationRevealCommand::render() method that we saw.

(function ($, Drupal) { Drupal.AjaxCommands.prototype.openFoundationReveal = function (ajax, response, status) { if (!response.selector) { return false; } // An element matching the selector will be added to the page if it does not exist yet. var $dialog = $(response.selector); if (!$dialog.length) { // Foundation expects certain things on a Reveal container. $dialog = $('').appendTo('body'); } if (!ajax.wrapper) { ajax.wrapper = $dialog.attr('id'); } // Get the markup inserted into the page. response.command = 'insert'; response.method = 'html'; ajax.commands.insert(ajax, response, status); // The content is ready, now open the dialog! var popup = new Foundation.Reveal($dialog); popup.open(); }; })(jQuery, Drupal);

There we have it - that last bit of the command opens the Foundation Reveal popup dialog!

I should also add that since I was showing a contact form in the popup, I installed the Contact ajax module. This meant that a site visitor would stay within the popup once they submit the form, which meant for a clean user experience.

Thanks for following along with me!

Categories: Drupal

WeKnow: Improving Drupal and Gatsby Integration - The Drupal Modules

News from Planet Drupal - Tue, 12/04/2018 - 11:15
Improving Drupal and Gatsby Integration - The Drupal Modules

At weKnow we are not only using Drupal, we also take contributing back very seriously and now is the time for improving the Drupal and Gatsby integration.

As mentioned in my personal blog, Moving weKnow's personal blog sites from Drupal to GatsbyJS, we have been using Gatsby with Drupal for projects as our decouple strategy lately, and after building a few sites with Drupal and Gatsby we found some challenges, which we resolved writing custom code. But now we’ve decided to share our knowledge as contributed modules.

Toast UI Editor

This module provides a markdown WYSIWYG editor integration for Toast UI Editor

jmolivas Tue, 12/04/2018 - 11:15
Categories: Drupal

Wordpress website project manager - Upwork

WordPress Work From UpWork - Tue, 12/04/2018 - 09:27
We have purchased a template wordpress website and we are looking now for a project manager to customise it with our brand, logos, manage and coordinate content creation and translations, manage and coordinate images content, set it up, and manage and coordinate its hosting and full operational mode delivery and completion.
Thanks in advance for your reply.
Kind regards


Posted On: December 04, 2018 11:41 UTC
Category: Web, Mobile & Software Dev > Web Development
Skills: Content Writing, Facebook Marketing, Project Management, Project Management Professional, Website Development, WordPress, Wordpress Theme
Country: United Kingdom
click to apply

Web Omelette: Simple Guzzle API mocking for functional testing in Drupal 8

News from Planet Drupal - Tue, 12/04/2018 - 08:05

In this article I am going to show you a technique I used recently to mock a relatively simple external service for functional tests in Drupal 8.

Imagine the following scenario: you have an API with one or a few endpoints and you write a service that handles the interaction with it. For example, one of the methods of this service takes an ID and calls the API in order to return the resource for that ID (using the Guzzle service available in Drupal 8). You then cast the Guzzle response stream to a string and return whatever from there to use in your application. How can you test your application with this kind of requirements?

The first thing you can do is unit test your service. In doing so, you can pass to it a mock client that can return whatever you set to it. Guzzle even provides a MockHandler that you can use with the client and specify what you want returned. Fair enough. But what about things like Kernel or Functional tests that need to use your client and make requests to this API? How can you handle this?

It’s not a good idea to use the live API endpoint in your tests for a number of reasons. For example, your testing pipeline would depend on an external, unpredictable service which can go down at any moment. Sure, it’s good to catch when this happens but clearly this is not the way to do it. Or you may have a limited amount of requests you can make to the endpoint. All these test runs will burn through your budget. And let’s not forget you need a network connection to run the tests.

So let’s see an interesting way of doing this using the Guzzle middleware architecture. Before diving into that, however, let’s cover a few theoretical aspects of this process.

Guzzle middlewares

A middleware is a piece of functionality that can be added to the pipeline of a process. For example, the process of turning a request into a response. Check out the StackPHP middlewares for a nice intro to this concept.

In Guzzle, middlewares are used inside the Guzzle handler stack that is responsible for turning a Guzzle request into a response. In this pipeline, middlewares are organised as part of the HandlerStack object which wraps the base handler that does the job, and are used to augment this pipeline. For example, let’s say a Guzzle client uses the base Curl handler to make the request. We can add a middleware to the handler stack to make changes to the outgoing request or to the incoming response. I highly recommend you read the Guzzle documentation on handlers and middlewares for more information.

Guzzle in Drupal 8

Guzzle is the default HTTP client used in Drupal 8 and is exposed as a service (http_client). So whenever we need to make external requests, we just inject that service and we are good to go. This service is instantiated by a ClientFactory that uses the default Guzzle handler stack (with some specific options for Drupal). The handler stack that gets injected into the client is configured by Drupal’s own HandlerStackConfigurator which also registers all the middlewares it finds.

Middlewares can be defined in Drupal as tagged services, with the tag http_client_middleware. There is currently only one available to look at as an example, used for the testing framework: TestHttpClientMiddleware.

Our OMDb (Open Movie Database) Mock

Now that we have an idea about how Guzzle processes a request, let’s see how we can use this to mock requests made to an example API: OMDb.

The client

Let’s assume a module called omdb which has this simple service that interacts with the OMDb API:

<?php namespace Drupal\omdb; use Drupal\Core\Site\Settings; use Drupal\Core\Url; use GuzzleHttp\ClientInterface; /** * Client to interact with the OMDb API. */ class OmdbClient { /** * @var \GuzzleHttp\ClientInterface */ protected $client; /** * Constructor. * * @param \GuzzleHttp\ClientInterface $client */ public function __construct(ClientInterface $client) { $this->client = $client; } /** * Get a movie by ID. * * @param \Drupal\omdb\string $id * * @return \stdClass */ public function getMovie(string $id) { $settings = $this->getSettings(); $url = Url::fromUri($settings['url'], ['query' => ['apiKey' => $settings['key'], 'i' => $id]]); $response = $this->client->get($url->toString()); return json_decode($response->getBody()->__toString()); } /** * Returns the OMDb settings. * * @return array */ protected function getSettings() { return Settings::get('omdb'); } }

We inject the http_client (Guzzle) and have a single method that retrieves a single movie from the API by its ID. Please disregard the complete lack of validation and error handling, I tried to keep things simple and to the point. To note, however, is that the API endpoint and key is stored in the settings.php file under the omdb key of $settings. That is if you want to play around with this example.

So assuming that we have defined this service inside omdb.services.yml as omdb.client and cleared the cache, we can now use this like so:

$client = \Drupal::service('omdb.client'); $movie = $client->getMovie('tt0068646');

Where $movie would become a stdClass representation of the movie The Godfather from the OMDb.

The mock

Now, let’s assume that we use this client to request movies all over the place in our application and we need to write some Kernel tests that verify that functionality, including the use of this movie data. One option we have is to switch out our OmdbClient client service completely as part of the test, with another one that has the same interface but returns whatever we want. This is ok, but it’s tightly connected to that test. Meaning that we cannot use it elsewhere, such as in Behat tests for example.

So let’s explore an alternative way by which we use middlewares to take over any requests made towards the API endpoint and return our own custom responses.

The first thing we need to do is create a test module where our middleware will live. This module will, of course, only be enabled during test runs or any time we want to play around with the mocked data. So the module can be called omdb_tests and we can place it inside the tests/module directory of the omdb module.

Next, inside the namespace of the test module we can create our middleware which looks like this:

<?php namespace Drupal\omdb_tests; use Drupal\Core\Site\Settings; use GuzzleHttp\Promise\FulfilledPromise; use GuzzleHttp\Psr7\Response; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; /** * Guzzle middleware for the OMDb API. */ class OmdbMiddleware { /** * Invoked method that returns a promise. */ public function __invoke() { return function ($handler) { return function (RequestInterface $request, array $options) use ($handler) { $uri = $request->getUri(); $settings = Settings::get('omdb'); // API requests to OMDb. if ($uri->getScheme() . '://' . $uri->getHost() . $uri->getPath() === $settings['url']) { return $this->createPromise($request); } // Otherwise, no intervention. We defer to the handler stack. return $handler($request, $options); }; }; } /** * Creates a promise for the OMDb request. * * @param RequestInterface $request * * @return \GuzzleHttp\Promise\PromiseInterface */ protected function createPromise(RequestInterface $request) { $uri = $request->getUri(); $params = \GuzzleHttp\Psr7\parse_query($uri->getQuery()); $id = $params['i']; $path = drupal_get_path('module', 'omdb_tests') . '/responses/movies'; $json = FALSE; if (file_exists("$path/$id.json")) { $json = file_get_contents("$path/$id.json"); } if ($json === FALSE) { $json = file_get_contents("$path/404.json"); } $response = new Response(200, [], $json); return new FulfilledPromise($response); } }

Before explaining what all this code does, we need to make sure we register this as a tagged service inside our test module:

services: omdb_tests.client_middleware: class: Drupal\omdb_tests\OmdbMiddleware tags: - { name: http_client_middleware }

Guzzle middleware services in Drupal have one single (magic) method called __invoke. This is because the service is treated as a callable. What the middleware needs to do is return a (callable) function which gets as a parameter the next handler from the stack that needs to be called. The returned function then has to return another function that takes the RequestInterface and some options as parameters. At this point, we can modify the request. Lastly, this function needs to make a call to that next handler by passing the RequestInterface and options, which in turn will return a PromiseInterface. Take a look at TestHttpClientMiddleware for an example in which Drupal core tampers with the request headers when Guzzle makes requests during test runs.

So what are we doing here?

We start by defining the first two (callable) functions I mentioned above. In the one which receives the current RequestInterface, we check for the URI of the request to see if it matches the one of our OMDb endpoint. If it doesn’t we simply call the next handler in the stack (which should return a PromiseInterface). If we wanted to alter the response that came back from the next handler(s) in the stack, we could call then() on the PromiseInterface returned by the stack, and pass to it a callback function which receives the ResponseInterface as a parameter. In there we could make the alterations. But alas, we don’t need to do that in our case.

A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then method, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled.

Read this for more information on what promises are and how they work.

Now for the good stuff. If the request is made to the OMDb endpoint, we create our own PromiseInterface. And very importantly, we do not call the next handler. Meaning that we break out of the handler stack and skip the other middlewares and the base handler. This way we prevent Guzzle from going to the endpoint and instead have it return our own PromiseInterface.

In this example I decided to store a couple of JSON responses for OMDb movies in files located in the responses/movies folder of the test module. In these JSON files, I store actual JSON responses made by the endpoint for given IDs, as well as a catch-all for whenever a missing ID is being requested. And the createPromise() method is responsible for determining which file to load. Depending on your application, you can choose exactly based on what you would like to build the mocked responses.

The loaded JSON is then added to a new Response object that can be directly added to the FulfilledPromise object we return. This tells Guzzle that the process is done, the promise has been fulfilled, and there is a response to return. And that is pretty much it.

Considerations

This is a very simple implementation. The API has many other ways of querying for data and you could extend this to store also lists of movies based on a title keyword search, for example. Anything that serves the needs of the application. Moreover, you can dispatch an event and allow other modules to provide their own resources in JSON format for various types of requests. There are quite a lot of possibilities.

Finally, this approach is useful for “simple” APIs such as this one. Once you need to implement things like Oauth or need the service to call back to your application, some more complex mocking will be needed such as a dedicated library and/or containerised application that mocks the production one. But for many such cases in which we read data from an endpoint, we can go far with this approach.

Categories: Drupal