Turn an Ext JS 6 Segmented Button into an Activity Timeline with CSS

My Ext JS 6/Java project for the National Institutes of Standards (NIST) requires an “activity path” indicator. No such widget exists directly in Ext, so I created a CSS override to the ExtJS segmented button in order to give me what I needed. Ultimately I’ll make this more robust by converting it over to Sass and using Ext JS Sass variables, but the raw overrides are presented here for your consideration.

Ext JS button definition:

 {
   xtype: 'segmentedbutton',
   cls: 'timeline',
   height: 40,
   items: [
     {
       text: 'Step 1'
     },
     {
       text: 'Step 2'
     },
     {
       text: 'Step 3'
     }
   ]
}

CSS overrides:

<style>

    /* white right-facing triangle */
    .timeline .x-segmented-button-item-horizontal:before {
	    content: " ";
	    height: 0;
	    width: 0;
	    position: absolute;
	    left: 2px;
	    top: 0px;
	    border-style: solid;
	    border-width: 19px 0 19px 19px;
	    border-color: transparent transparent transparent #fff;
	    z-index: 0;
	}

	.timeline .x-btn-default-small {
		border: 0px !important;
	}

	/* overlay right-facing triangle of standard button color, leaving
	edges of white right-facing triangle */
    .timeline .x-segmented-button-item-horizontal:after {
	    content: " ";
	    height: 0;
	    width: 0;
	    position: absolute;
	    left: 0px;
	    top: 0px;
	    border-style: solid;
	    border-width: 19px 0 19px 19px;
	    border-color: transparent transparent transparent #5fa2dd;
	    z-index: 10;
	}

	/* white arrow overlay to left of first button */
	.timeline .x-segmented-button-item-horizontal:first-child:after {
		 border-color: transparent transparent transparent white;
	}

	.timeline .x-segmented-button-item-horizontal:first-child:after, .timeline .x-segmented-button-item-horizontal.x-btn-pressed:first-child:after {
		 border-color: transparent transparent transparent white !important;
	}

	.timelinebutton.x-btn-pressed:after {
	    border-left-color: #477aa6;
	}

 	.timeline .x-segmented-button-item-horizontal.x-btn-pressed + .x-segmented-button-item-horizontal:after {
 		border-color: transparent transparent transparent #477aa6;
 	}

 	.timeline .x-segmented-button-item-horizontal.x-btn-pressed:after {
 		border-color: transparent transparent transparent #5fa2dd;
 	}

 	/* eliminate right edge border that Ext JS puts into place. */
 	.timeline .x-btn-focus.x-btn-pressed {
 		box-shadow: none !important;
 	}

 	/* set hover of triangle to standard hover color of button */
 	.timeline .x-btn-over + .x-segmented-button-item-horizontal:after {
 		border-color: transparent transparent transparent #5795cb;
 	}
</style>

My Review of Alien:Covenant

(mild spoilers)

I desperately wanted to like Alien Covenant, if not simply for the fact that they killed off James Franco within the first 5 minutes. Unfortunately, I found it to be a grossly derivative rehashing of “best of” moments from other Alien and rogue AI movies. By the time the credits roll, it’s clear that the “Engineers” from Prometheus not only developed the xenomorphs, but also created a virus that activated in 1987 and wiped out all creativity in Hollywood.

The plot is basically this:

In about 100 years, humanity has advanced to the point where we can create huge interstellar spaceships crewed with absolute morons, Danny McBride, and the daughter of actor Sam Waterston. A solar flare interrupts their trip so that they can receive a recorded message from the sole survivor of Prometheus mission singing “Country Roads” and change course to investigate.

No, I am not making this up.

Once they arrive it becomes quite evident that not a single member of the crew or the ship’s other 2000 inhabitants who are tasked with colonizing another planet, were ever trained in exobiology. Also, none of them have apparently ever seen a James Cameron or Ridley Scott movie before. They all received automatic weapons training, however. So I’m thinking that in the year 2100, everyone is a Republican.

On the bright side, the crew member who lights up a Marlboro on the strange, new planet is the first one to die.  Apparently he never got the Surgeon General’s memo that smoking and alien spores are bad for your health.

This, of course, is followed in short order by the blatant ignoring of quarantine procedures and series movie continuity.  Also, we see the use of firearms within a spaceship because in the future, there’s nothing that could possibly go “boom” on a spaceship. Oh, wait… no.

Anyway, the surviving crew members meet up with the android “David” from Prometheus who’s been living on this alien world for 10 years. Apparently, “David” has developed a deep hatred of humanity because his creator foolishly gave him access to Facebook and Instagram. This triggers his built-in HAL-9000 subroutines to further drive the plot towards an ending that should surprise absolutely no one at all.

In summary, a more appropriate title for this movie would have been “Alien: Been there, done that.”

Developing Skills for Amazon Alexa with Adobe ColdFusion.

Topics include:

  • Creating Skills for Amazon Alexa
  • Using the Amazon Skills Kit (ASK)
  • Supporting Skill Cards
  • Developing Custom Skills
  • Developing Custom Intents
  • Defining Slots
  • Defining Utterances
  • Using Built-In Intents
  • Choosing the Invocation Name for a Custom Skill
  • Creating the ColdFusion Web Service to Handle Alexa Requests
  • Registering your Skill in the Developer Portal
  • Configuring your Endpoint
  • Testing the Skill

ss1

See the recorded presentation here:
http://experts.adobeconnect.com/p8zcgm583fx/

Download the source code here:
https://github.com/sdruckerfig/CF-Alexa

If you’d like to have an Alexa skill designed and developed by Fig Leaf Software, please mail us at info@figleaf.com.

Integrating Ext JS 6, Sencha Architect 4, and TinyMCE

Note: This is a follow-up to my post from 2014
(https://druckit.wordpress.com/2014/03/30/integrating-ext-js-4-and-the-tinymce-4-rich-text-wysiwyg-editor/)

I’ve re-packaged and enhanced the plugin as a Sencha Architect Extension (.aux) file.

New features include:

  • Ext JS 5.x/6.x compatibility
  • Sencha Architect 4.x compatibility
  • The TinyMCE editor now appears directly within the design canvas of Sencha Architect
  • Added support for new TinyMCE4 features (including the Premium Spell Checker plugin)
  • Added support to use smaller buttons in the TinyMCE editor.

screenshot

By default, the editor will pull from the TinyMCE Cloud. See the usage notes in the README.md file for install instructions.

You can download the extension from my repo here:
https://github.com/sdruckerfig/SenchaArchitectExt6TinyMCE

Enjoy!

ColdFusion and Node.JS – two great tastes that taste great together!

Fig Leaf Software recently delivered a hybrid ColdFusion – Node.js solution to one of our customers.

We decided to use a hybrid architecture for the following reasons:

  1. The customer expressed a preference for using ColdFusion to drive their CMS-based website.
  2. The website has several embedded, small AJAX applications that leverage data from an XML-based API that sits behind the customer’s firewall.
  3. Java-based app servers (ColdFusion) are particularly well-suited for dynamically assembling and serving web pages.
  4. Node.js servers are particularly good at implementing REST APIs and handling large volume, asynchronous data requests for non-cacheable dynamic data.
  5. The website/web apps do not require user authentication, therefore session sharing between different app server technologies was not an issue.
  6. Sharing the workload between CF and Node gives us more flexibility for scaling up the infrastructure in a more cost-effective manner with options for  potentially off-loading the Node service to cloud platforms such as Heroku.

wmata

 

Implementing a “Deck of Cards” Layout in Salesforce Lightning Components

A “Deck of Cards” layout is where multiple “cards” of information are stacked on top of each other. Only one card is visible at any given time. Essentially, this is similar to a tab panel, but it gives you the flexibility to design your own ux for swapping the cards in and out.

I’ve implemented this as a single component that can be easily invoked from an app, or other cmp file:

<aura:application >
    <c:cardLayout aura:Id="myCardLayout">
        <div class="card">
            This is card 1
        </div>
        <div class="card">
            This is card 2
        </div>
        <div class="card">
            This is card 3
        </div>
    </c:cardLayout>
    
    <div style="position:fixed; bottom:10px; border: 1px solid black">
    <ui:button 
        label="Show Card 1"
        press="{!c.showCard1}" />
    <ui:button 
        label="Show Card 2"
        press="{!c.showCard2}" />
    <ui:button 
        label="Show Card 3"
        press="{!c.showCard3}" />
   </div>
</aura:application>

The corresponding controller simply calls a public method on the cardLayout component:

({
  showCard1 : function(component, event, helper) {
    component.find('myCardLayout').setActiveCard(0);
  },
  showCard2 : function(component, event, helper) {
    component.find('myCardLayout').setActiveCard(1);
  },
  showCard3 : function(component, event, helper) {
    component.find('myCardLayout').setActiveCard(2);
  }
})

Pretty simple, right?

Now, let’s take a look at the cardLayout component. It’s relatively straightforward:

<aura:component>
   
   <aura:method 
                name="setActiveCard" 
                action="{!c.doSetActiveCard}" 
                access="global" />
   
   <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
 
 
   <aura:attribute 
                   name="activeCard" 
                   type="String" 
                   default="0" access="global" />
	
   <div class="cardContainer">
     {!v.body}
   </div>
</aura:component>

The controller logic simply applies or removes a custom css class:

({
    doSetActiveCard : function(component, event, helper) {
        var currentActiveCard = component.get('v.activeCard');
        
        var params = event.getParam('arguments');
        var newCardId = params[0];
        
        var oldCard = component.get('v.body')[currentActiveCard];
        $A.util.removeClass(oldCard,"card--on");
        
        var newCard = component.get('v.body')[newCardId];
        
        $A.util.addClass(newCard,"card--on");
        component.set('v.activeCard',newCardId);
        
    },
    
    doInit: function(component, event, helper) {
        component.setActiveCard(component.get('v.activeCard'));
    }
})

And the CSS…well, it just defines a couple of classes for defining card visibility along with a “fade” animation

.THIS {
    height: 100%;
}

.THIS.cardContainer {
  position: relative;
  display: flex;
  flex: 1 0 auto;
  height: 100%;
}

.THIS .card {
  transition: 0.2s opacity linear; 
  visibility: visible;
  overflow: auto;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  position: absolute !important;
  opacity: 0;          
  visibility: hidden;
}

.THIS .card--on {
  opacity: 1;
  visibility: visible;
}

I’ll be discussing this technique, as well as other solutions at my presentation on “Lightning Component Best Practices” at the Dreamforce conference in Thursday, Oct 6. See you there!