Adapting HTML CSS JS project

ok-at-github edited this page Aug 28, 2017 · 5 revisions

The origin version of this document was written by Harbs. Thanks for contributing this awesome stuff!

CodePen live demo of the origin JavaScript project

Table of contents

Introduction
Step 1: Understanding the Structure
Step 2: Deciding what components we need
Step 3: Creating the Wrapper Component
Step 4: Adding Code
Step 5: Adding CSS
Step 6: Using the Component
Conclusion

Introduction

I needed a tabbed interface for an app and FlexJS does not yet have a built-in component which does this. I searched for some nicely formatted tabbed UIs and I found one I liked which was created by Lewi Hussey. Download it as zip or run the origin live demo via CodePen.
If you open the project, you will see there’s a specific hierarchy of HTML, CSS and JS that’s all needed for it to work correctly. I thought this would be a great opportunity to explain how to incorporate something like this into a project.

Step 1: Understanding the Structure

I stripped the content down to its core. This left me with the following HTML structure:

<section class="wrapper">
<ul class="tabs">
<li class="active">Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="tab__content">
<li class="active">
<div class="content__wrapper">
<h2>Section 1</h2>
<p>Section 1 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 2</h2>
<p>Section 2 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 3</h2>
<p>Section 3 text</p>
</div>
</li>
</ul>
</section>

The significant part of this is that we need the following pieces:

  • A “wrapper” around everything
  • A <ul> element for the tabs
  • A <ul> element for the content
  • A <li> element for each of the tabs
  • A <li> element for each of the content sections.

Step 2: Deciding what components we need

Technically we do not need any custom elements to create this setup. We can use a <js:Div> component for the wrapper, and <js:Ul> and <js:Li> components for the rest. However, it is easier if we create at least one component to contain the ActionScript version of the JavaScript code which does its thing. We can create the component either in ActionScript or MXML. The advantage of MXML is that we can declare both ActionScript code and the CSS in the same file. If we would use an ActionScript version, the JavaScript (ActionScript) can be included, but the CSS must go elsewhere.

The simplest component which can be used as a base for an MXML file is <js:Group>, so I am going to use that.

Step 3: Creating the Wrapper Component

On the simplest level, adding a new MXML <js:Group> component looks like this:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</js:Group>

All CSS styling will go within the <fx:Style> section, and all code will go within the <fx:Script> section. The actual content does not need to be declared inside the component because this component will be used inside another MXML file which will declare the sub-content there. The only thing we might want to do would be to declare some class name so we could apply consistent styling to all tab wrappers in our app. We do that like this:

<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer">

The reason I’m using <typeNames> rather than <className> is because <className> is added to the list of <typeNames> defined in the component. This allows me to set specific <classNames> to instances of the component and add class-based styling to instances while preserving the global styling.

Step 4: Adding Code

I stripped out the JavaScript code which is not component-specific and the remaining original code looks like this:

$(document).ready(function(){
// Variables
var clickedTab = $(".tabs > .active");
var tabWrapper = $(".tab__content");
var activeTab = tabWrapper.find(".active");
var activeTabHeight = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function() {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function() {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
height: activeTabHeight
}, 500, function() {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
});

To convert this to ActionScript code, we could try and rewrite this to use actual references to FlexJS components. Ultimately this would probably be more efficient and allow hooks into FlexJS functionality, but for my use case, I don’t really care that much about that. I just want to get the functionality of this code as quickly and easily as possible. I’m already using jquery elsewhere in my app, so there’s no extra code loading for doing so.

FlexJS already has type definitions for jquery, so we can actually assign types to the jquery code and get code intelligence in an IDE (I am using Visual Studio Code).

Additionally, there’s no reason to call $(document).ready() in FlexJS. I use initComplete instead and my component becomes:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer" initComplete="init()">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
private function init():void {
// Variables
var clickedTab:jQuery = $(".tabs > .active");
var tabWrapper:jQuery = $(".tab__content");
var activeTab:jQuery = tabWrapper.find(".active");
var activeTabHeight:Number = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function():void {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function():void {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex:Number = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
"height": activeTabHeight
}, 500, function():void {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
}
]]>
</fx:Script>
</js:Group>

One thing worth noting: in the animate() function, I changed the literal object notation to use property names in quotes. The reason I did this is to prevent Google Closure Compiler from minimizing the height property. That’s all we need to do to migrate the JS code for FlexJS.

Step 5: Adding CSS

To add the CSS, it should be as simple as copying and paste the CSS into the style element:

<fx:Style>
@namespace "http://www.w3.org/1999/xhtml";
.tabs {
display: table;
table-layout: fixed;
width: 100%;
transform: translateY(5px);
}
.tabs > li {
transition-duration: .25s;
display: table-cell;
list-style: none;
text-align: center;
padding: 20px 20px 25px 20px;
position: relative;
overflow: hidden;
cursor: pointer;
color: white;
}
.tabs > li:before {
z-index: -1;
position: absolute;
content: "";
width: 100%;
height: 120%;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(100%);
transition-duration: .25s;
border-radius: 5px 5px 0 0;
}
.tabs > li:hover:before {
transform: translateY(70%);
}
.tabs > li.active {
color: #50555a;
}
.tabs > li.active:before {
transition-duration: .5s;
background-color: white;
transform: translateY(0);
}
.tab__content {
background-color: white;
position: relative;
width: 100%;
border-radius: 5px;
}
.tab__content > li {
width: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
list-style: none;
}
.tab__content > li .content__wrapper {
text-align: center;
border-radius: 5px;
width: 100%;
padding: 45px 40px 40px 40px;
background-color: white;
}
.content__wrapper h2 {
width: 100%;
text-align: center;
padding-bottom: 20px;
font-weight: 300;
}
.content__wrapper img {
width: 100%;
height: auto;
border-radius: 5px;
}
</fx:Style>

To handle native HTML selectors like <li> it’s necessary to add the default namespace @namespace "http://www.w3.org/1999/xhtml";

That allows the compiler to understand unmodified CSS.

Step 6: Using the Component

Using the component is very straight-forward. We just follow the markup pattern in the original HTML using FlexJS markup syntax:

<palette:TabContainer>
<js:Ul className="tabs" id="tabList">
<js:Li className="active">
<js:TextNode text="{tabTitle1}"/>
</js:Li>
<js:Li>
<js:TextNode text="{tabTitle2}"/>
</js:Li>
</js:Ul>
<js:Ul className="tab__content" id="contentList">
<js:Li className="active">
<js:Div className="content__wrapper">
<palette:TabContent1/>
</js:Div>
</js:Li>
<js:Li>
<js:Div className="content__wrapper">
<palette:TabContent2/>
</js:Div>
</js:Li>
</js:Ul>
</palette:TabContainer>

The actual content is declared elsewhere. I added ids to the <ul> for the tabs and content to make it possible to set the correct classNames programmatically in addition to the automatic changes done by jquery.

Conclusion

That’s it. I’ve now incorporated some random HTML, JS and CSS into my project.

Of course, if I wanted to implement an actual cross-platform FlexJS component, it would be much more work (and ultimately more flexible), but I think this “hacking together” of random HTML found on the web is a pretty common need and I hope this tutorial is helpful.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Adapting HTML CSS JS project

ok-at-github edited this page Aug 28, 2017 · 5 revisions

The origin version of this document was written by Harbs. Thanks for contributing this awesome stuff!

CodePen live demo of the origin JavaScript project

Table of contents

Introduction
Step 1: Understanding the Structure
Step 2: Deciding what components we need
Step 3: Creating the Wrapper Component
Step 4: Adding Code
Step 5: Adding CSS
Step 6: Using the Component
Conclusion

Introduction

I needed a tabbed interface for an app and FlexJS does not yet have a built-in component which does this. I searched for some nicely formatted tabbed UIs and I found one I liked which was created by Lewi Hussey. Download it as zip or run the origin live demo via CodePen.
If you open the project, you will see there’s a specific hierarchy of HTML, CSS and JS that’s all needed for it to work correctly. I thought this would be a great opportunity to explain how to incorporate something like this into a project.

Step 1: Understanding the Structure

I stripped the content down to its core. This left me with the following HTML structure:

<section class="wrapper">
<ul class="tabs">
<li class="active">Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="tab__content">
<li class="active">
<div class="content__wrapper">
<h2>Section 1</h2>
<p>Section 1 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 2</h2>
<p>Section 2 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 3</h2>
<p>Section 3 text</p>
</div>
</li>
</ul>
</section>

The significant part of this is that we need the following pieces:

  • A “wrapper” around everything
  • A <ul> element for the tabs
  • A <ul> element for the content
  • A <li> element for each of the tabs
  • A <li> element for each of the content sections.

Step 2: Deciding what components we need

Technically we do not need any custom elements to create this setup. We can use a <js:Div> component for the wrapper, and <js:Ul> and <js:Li> components for the rest. However, it is easier if we create at least one component to contain the ActionScript version of the JavaScript code which does its thing. We can create the component either in ActionScript or MXML. The advantage of MXML is that we can declare both ActionScript code and the CSS in the same file. If we would use an ActionScript version, the JavaScript (ActionScript) can be included, but the CSS must go elsewhere.

The simplest component which can be used as a base for an MXML file is <js:Group>, so I am going to use that.

Step 3: Creating the Wrapper Component

On the simplest level, adding a new MXML <js:Group> component looks like this:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</js:Group>

All CSS styling will go within the <fx:Style> section, and all code will go within the <fx:Script> section. The actual content does not need to be declared inside the component because this component will be used inside another MXML file which will declare the sub-content there. The only thing we might want to do would be to declare some class name so we could apply consistent styling to all tab wrappers in our app. We do that like this:

<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer">

The reason I’m using <typeNames> rather than <className> is because <className> is added to the list of <typeNames> defined in the component. This allows me to set specific <classNames> to instances of the component and add class-based styling to instances while preserving the global styling.

Step 4: Adding Code

I stripped out the JavaScript code which is not component-specific and the remaining original code looks like this:

$(document).ready(function(){
// Variables
var clickedTab = $(".tabs > .active");
var tabWrapper = $(".tab__content");
var activeTab = tabWrapper.find(".active");
var activeTabHeight = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function() {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function() {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
height: activeTabHeight
}, 500, function() {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
});

To convert this to ActionScript code, we could try and rewrite this to use actual references to FlexJS components. Ultimately this would probably be more efficient and allow hooks into FlexJS functionality, but for my use case, I don’t really care that much about that. I just want to get the functionality of this code as quickly and easily as possible. I’m already using jquery elsewhere in my app, so there’s no extra code loading for doing so.

FlexJS already has type definitions for jquery, so we can actually assign types to the jquery code and get code intelligence in an IDE (I am using Visual Studio Code).

Additionally, there’s no reason to call $(document).ready() in FlexJS. I use initComplete instead and my component becomes:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer" initComplete="init()">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
private function init():void {
// Variables
var clickedTab:jQuery = $(".tabs > .active");
var tabWrapper:jQuery = $(".tab__content");
var activeTab:jQuery = tabWrapper.find(".active");
var activeTabHeight:Number = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function():void {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function():void {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex:Number = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
"height": activeTabHeight
}, 500, function():void {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
}
]]>
</fx:Script>
</js:Group>

One thing worth noting: in the animate() function, I changed the literal object notation to use property names in quotes. The reason I did this is to prevent Google Closure Compiler from minimizing the height property. That’s all we need to do to migrate the JS code for FlexJS.

Step 5: Adding CSS

To add the CSS, it should be as simple as copying and paste the CSS into the style element:

<fx:Style>
@namespace "http://www.w3.org/1999/xhtml";
.tabs {
display: table;
table-layout: fixed;
width: 100%;
transform: translateY(5px);
}
.tabs > li {
transition-duration: .25s;
display: table-cell;
list-style: none;
text-align: center;
padding: 20px 20px 25px 20px;
position: relative;
overflow: hidden;
cursor: pointer;
color: white;
}
.tabs > li:before {
z-index: -1;
position: absolute;
content: "";
width: 100%;
height: 120%;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(100%);
transition-duration: .25s;
border-radius: 5px 5px 0 0;
}
.tabs > li:hover:before {
transform: translateY(70%);
}
.tabs > li.active {
color: #50555a;
}
.tabs > li.active:before {
transition-duration: .5s;
background-color: white;
transform: translateY(0);
}
.tab__content {
background-color: white;
position: relative;
width: 100%;
border-radius: 5px;
}
.tab__content > li {
width: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
list-style: none;
}
.tab__content > li .content__wrapper {
text-align: center;
border-radius: 5px;
width: 100%;
padding: 45px 40px 40px 40px;
background-color: white;
}
.content__wrapper h2 {
width: 100%;
text-align: center;
padding-bottom: 20px;
font-weight: 300;
}
.content__wrapper img {
width: 100%;
height: auto;
border-radius: 5px;
}
</fx:Style>

To handle native HTML selectors like <li> it’s necessary to add the default namespace @namespace "http://www.w3.org/1999/xhtml";

That allows the compiler to understand unmodified CSS.

Step 6: Using the Component

Using the component is very straight-forward. We just follow the markup pattern in the original HTML using FlexJS markup syntax:

<palette:TabContainer>
<js:Ul className="tabs" id="tabList">
<js:Li className="active">
<js:TextNode text="{tabTitle1}"/>
</js:Li>
<js:Li>
<js:TextNode text="{tabTitle2}"/>
</js:Li>
</js:Ul>
<js:Ul className="tab__content" id="contentList">
<js:Li className="active">
<js:Div className="content__wrapper">
<palette:TabContent1/>
</js:Div>
</js:Li>
<js:Li>
<js:Div className="content__wrapper">
<palette:TabContent2/>
</js:Div>
</js:Li>
</js:Ul>
</palette:TabContainer>

The actual content is declared elsewhere. I added ids to the <ul> for the tabs and content to make it possible to set the correct classNames programmatically in addition to the automatic changes done by jquery.

Conclusion

That’s it. I’ve now incorporated some random HTML, JS and CSS into my project.

Of course, if I wanted to implement an actual cross-platform FlexJS component, it would be much more work (and ultimately more flexible), but I think this “hacking together” of random HTML found on the web is a pretty common need and I hope this tutorial is helpful.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Adapting HTML CSS JS project

ok-at-github edited this page Aug 28, 2017 · 5 revisions

The origin version of this document was written by Harbs. Thanks for contributing this awesome stuff!

CodePen live demo of the origin JavaScript project

Table of contents

Introduction
Step 1: Understanding the Structure
Step 2: Deciding what components we need
Step 3: Creating the Wrapper Component
Step 4: Adding Code
Step 5: Adding CSS
Step 6: Using the Component
Conclusion

Introduction

I needed a tabbed interface for an app and FlexJS does not yet have a built-in component which does this. I searched for some nicely formatted tabbed UIs and I found one I liked which was created by Lewi Hussey. Download it as zip or run the origin live demo via CodePen.
If you open the project, you will see there’s a specific hierarchy of HTML, CSS and JS that’s all needed for it to work correctly. I thought this would be a great opportunity to explain how to incorporate something like this into a project.

Step 1: Understanding the Structure

I stripped the content down to its core. This left me with the following HTML structure:

<section class="wrapper">
<ul class="tabs">
<li class="active">Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="tab__content">
<li class="active">
<div class="content__wrapper">
<h2>Section 1</h2>
<p>Section 1 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 2</h2>
<p>Section 2 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 3</h2>
<p>Section 3 text</p>
</div>
</li>
</ul>
</section>

The significant part of this is that we need the following pieces:

  • A “wrapper” around everything
  • A <ul> element for the tabs
  • A <ul> element for the content
  • A <li> element for each of the tabs
  • A <li> element for each of the content sections.

Step 2: Deciding what components we need

Technically we do not need any custom elements to create this setup. We can use a <js:Div> component for the wrapper, and <js:Ul> and <js:Li> components for the rest. However, it is easier if we create at least one component to contain the ActionScript version of the JavaScript code which does its thing. We can create the component either in ActionScript or MXML. The advantage of MXML is that we can declare both ActionScript code and the CSS in the same file. If we would use an ActionScript version, the JavaScript (ActionScript) can be included, but the CSS must go elsewhere.

The simplest component which can be used as a base for an MXML file is <js:Group>, so I am going to use that.

Step 3: Creating the Wrapper Component

On the simplest level, adding a new MXML <js:Group> component looks like this:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</js:Group>

All CSS styling will go within the <fx:Style> section, and all code will go within the <fx:Script> section. The actual content does not need to be declared inside the component because this component will be used inside another MXML file which will declare the sub-content there. The only thing we might want to do would be to declare some class name so we could apply consistent styling to all tab wrappers in our app. We do that like this:

<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer">

The reason I’m using <typeNames> rather than <className> is because <className> is added to the list of <typeNames> defined in the component. This allows me to set specific <classNames> to instances of the component and add class-based styling to instances while preserving the global styling.

Step 4: Adding Code

I stripped out the JavaScript code which is not component-specific and the remaining original code looks like this:

$(document).ready(function(){
// Variables
var clickedTab = $(".tabs > .active");
var tabWrapper = $(".tab__content");
var activeTab = tabWrapper.find(".active");
var activeTabHeight = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function() {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function() {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
height: activeTabHeight
}, 500, function() {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
});

To convert this to ActionScript code, we could try and rewrite this to use actual references to FlexJS components. Ultimately this would probably be more efficient and allow hooks into FlexJS functionality, but for my use case, I don’t really care that much about that. I just want to get the functionality of this code as quickly and easily as possible. I’m already using jquery elsewhere in my app, so there’s no extra code loading for doing so.

FlexJS already has type definitions for jquery, so we can actually assign types to the jquery code and get code intelligence in an IDE (I am using Visual Studio Code).

Additionally, there’s no reason to call $(document).ready() in FlexJS. I use initComplete instead and my component becomes:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer" initComplete="init()">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
private function init():void {
// Variables
var clickedTab:jQuery = $(".tabs > .active");
var tabWrapper:jQuery = $(".tab__content");
var activeTab:jQuery = tabWrapper.find(".active");
var activeTabHeight:Number = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function():void {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function():void {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex:Number = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
"height": activeTabHeight
}, 500, function():void {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
}
]]>
</fx:Script>
</js:Group>

One thing worth noting: in the animate() function, I changed the literal object notation to use property names in quotes. The reason I did this is to prevent Google Closure Compiler from minimizing the height property. That’s all we need to do to migrate the JS code for FlexJS.

Step 5: Adding CSS

To add the CSS, it should be as simple as copying and paste the CSS into the style element:

<fx:Style>
@namespace "http://www.w3.org/1999/xhtml";
.tabs {
display: table;
table-layout: fixed;
width: 100%;
transform: translateY(5px);
}
.tabs > li {
transition-duration: .25s;
display: table-cell;
list-style: none;
text-align: center;
padding: 20px 20px 25px 20px;
position: relative;
overflow: hidden;
cursor: pointer;
color: white;
}
.tabs > li:before {
z-index: -1;
position: absolute;
content: "";
width: 100%;
height: 120%;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(100%);
transition-duration: .25s;
border-radius: 5px 5px 0 0;
}
.tabs > li:hover:before {
transform: translateY(70%);
}
.tabs > li.active {
color: #50555a;
}
.tabs > li.active:before {
transition-duration: .5s;
background-color: white;
transform: translateY(0);
}
.tab__content {
background-color: white;
position: relative;
width: 100%;
border-radius: 5px;
}
.tab__content > li {
width: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
list-style: none;
}
.tab__content > li .content__wrapper {
text-align: center;
border-radius: 5px;
width: 100%;
padding: 45px 40px 40px 40px;
background-color: white;
}
.content__wrapper h2 {
width: 100%;
text-align: center;
padding-bottom: 20px;
font-weight: 300;
}
.content__wrapper img {
width: 100%;
height: auto;
border-radius: 5px;
}
</fx:Style>

To handle native HTML selectors like <li> it’s necessary to add the default namespace @namespace "http://www.w3.org/1999/xhtml";

That allows the compiler to understand unmodified CSS.

Step 6: Using the Component

Using the component is very straight-forward. We just follow the markup pattern in the original HTML using FlexJS markup syntax:

<palette:TabContainer>
<js:Ul className="tabs" id="tabList">
<js:Li className="active">
<js:TextNode text="{tabTitle1}"/>
</js:Li>
<js:Li>
<js:TextNode text="{tabTitle2}"/>
</js:Li>
</js:Ul>
<js:Ul className="tab__content" id="contentList">
<js:Li className="active">
<js:Div className="content__wrapper">
<palette:TabContent1/>
</js:Div>
</js:Li>
<js:Li>
<js:Div className="content__wrapper">
<palette:TabContent2/>
</js:Div>
</js:Li>
</js:Ul>
</palette:TabContainer>

The actual content is declared elsewhere. I added ids to the <ul> for the tabs and content to make it possible to set the correct classNames programmatically in addition to the automatic changes done by jquery.

Conclusion

That’s it. I’ve now incorporated some random HTML, JS and CSS into my project.

Of course, if I wanted to implement an actual cross-platform FlexJS component, it would be much more work (and ultimately more flexible), but I think this “hacking together” of random HTML found on the web is a pretty common need and I hope this tutorial is helpful.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Adapting HTML CSS JS project

ok-at-github edited this page Aug 28, 2017 · 5 revisions

The origin version of this document was written by Harbs. Thanks for contributing this awesome stuff!

CodePen live demo of the origin JavaScript project

Table of contents

Introduction
Step 1: Understanding the Structure
Step 2: Deciding what components we need
Step 3: Creating the Wrapper Component
Step 4: Adding Code
Step 5: Adding CSS
Step 6: Using the Component
Conclusion

Introduction

I needed a tabbed interface for an app and FlexJS does not yet have a built-in component which does this. I searched for some nicely formatted tabbed UIs and I found one I liked which was created by Lewi Hussey. Download it as zip or run the origin live demo via CodePen.
If you open the project, you will see there’s a specific hierarchy of HTML, CSS and JS that’s all needed for it to work correctly. I thought this would be a great opportunity to explain how to incorporate something like this into a project.

Step 1: Understanding the Structure

I stripped the content down to its core. This left me with the following HTML structure:

<section class="wrapper">
<ul class="tabs">
<li class="active">Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="tab__content">
<li class="active">
<div class="content__wrapper">
<h2>Section 1</h2>
<p>Section 1 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 2</h2>
<p>Section 2 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 3</h2>
<p>Section 3 text</p>
</div>
</li>
</ul>
</section>

The significant part of this is that we need the following pieces:

  • A “wrapper” around everything
  • A <ul> element for the tabs
  • A <ul> element for the content
  • A <li> element for each of the tabs
  • A <li> element for each of the content sections.

Step 2: Deciding what components we need

Technically we do not need any custom elements to create this setup. We can use a <js:Div> component for the wrapper, and <js:Ul> and <js:Li> components for the rest. However, it is easier if we create at least one component to contain the ActionScript version of the JavaScript code which does its thing. We can create the component either in ActionScript or MXML. The advantage of MXML is that we can declare both ActionScript code and the CSS in the same file. If we would use an ActionScript version, the JavaScript (ActionScript) can be included, but the CSS must go elsewhere.

The simplest component which can be used as a base for an MXML file is <js:Group>, so I am going to use that.

Step 3: Creating the Wrapper Component

On the simplest level, adding a new MXML <js:Group> component looks like this:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</js:Group>

All CSS styling will go within the <fx:Style> section, and all code will go within the <fx:Script> section. The actual content does not need to be declared inside the component because this component will be used inside another MXML file which will declare the sub-content there. The only thing we might want to do would be to declare some class name so we could apply consistent styling to all tab wrappers in our app. We do that like this:

<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer">

The reason I’m using <typeNames> rather than <className> is because <className> is added to the list of <typeNames> defined in the component. This allows me to set specific <classNames> to instances of the component and add class-based styling to instances while preserving the global styling.

Step 4: Adding Code

I stripped out the JavaScript code which is not component-specific and the remaining original code looks like this:

$(document).ready(function(){
// Variables
var clickedTab = $(".tabs > .active");
var tabWrapper = $(".tab__content");
var activeTab = tabWrapper.find(".active");
var activeTabHeight = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function() {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function() {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
height: activeTabHeight
}, 500, function() {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
});

To convert this to ActionScript code, we could try and rewrite this to use actual references to FlexJS components. Ultimately this would probably be more efficient and allow hooks into FlexJS functionality, but for my use case, I don’t really care that much about that. I just want to get the functionality of this code as quickly and easily as possible. I’m already using jquery elsewhere in my app, so there’s no extra code loading for doing so.

FlexJS already has type definitions for jquery, so we can actually assign types to the jquery code and get code intelligence in an IDE (I am using Visual Studio Code).

Additionally, there’s no reason to call $(document).ready() in FlexJS. I use initComplete instead and my component becomes:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer" initComplete="init()">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
private function init():void {
// Variables
var clickedTab:jQuery = $(".tabs > .active");
var tabWrapper:jQuery = $(".tab__content");
var activeTab:jQuery = tabWrapper.find(".active");
var activeTabHeight:Number = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function():void {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function():void {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex:Number = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
"height": activeTabHeight
}, 500, function():void {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
}
]]>
</fx:Script>
</js:Group>

One thing worth noting: in the animate() function, I changed the literal object notation to use property names in quotes. The reason I did this is to prevent Google Closure Compiler from minimizing the height property. That’s all we need to do to migrate the JS code for FlexJS.

Step 5: Adding CSS

To add the CSS, it should be as simple as copying and paste the CSS into the style element:

<fx:Style>
@namespace "http://www.w3.org/1999/xhtml";
.tabs {
display: table;
table-layout: fixed;
width: 100%;
transform: translateY(5px);
}
.tabs > li {
transition-duration: .25s;
display: table-cell;
list-style: none;
text-align: center;
padding: 20px 20px 25px 20px;
position: relative;
overflow: hidden;
cursor: pointer;
color: white;
}
.tabs > li:before {
z-index: -1;
position: absolute;
content: "";
width: 100%;
height: 120%;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(100%);
transition-duration: .25s;
border-radius: 5px 5px 0 0;
}
.tabs > li:hover:before {
transform: translateY(70%);
}
.tabs > li.active {
color: #50555a;
}
.tabs > li.active:before {
transition-duration: .5s;
background-color: white;
transform: translateY(0);
}
.tab__content {
background-color: white;
position: relative;
width: 100%;
border-radius: 5px;
}
.tab__content > li {
width: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
list-style: none;
}
.tab__content > li .content__wrapper {
text-align: center;
border-radius: 5px;
width: 100%;
padding: 45px 40px 40px 40px;
background-color: white;
}
.content__wrapper h2 {
width: 100%;
text-align: center;
padding-bottom: 20px;
font-weight: 300;
}
.content__wrapper img {
width: 100%;
height: auto;
border-radius: 5px;
}
</fx:Style>

To handle native HTML selectors like <li> it’s necessary to add the default namespace @namespace "http://www.w3.org/1999/xhtml";

That allows the compiler to understand unmodified CSS.

Step 6: Using the Component

Using the component is very straight-forward. We just follow the markup pattern in the original HTML using FlexJS markup syntax:

<palette:TabContainer>
<js:Ul className="tabs" id="tabList">
<js:Li className="active">
<js:TextNode text="{tabTitle1}"/>
</js:Li>
<js:Li>
<js:TextNode text="{tabTitle2}"/>
</js:Li>
</js:Ul>
<js:Ul className="tab__content" id="contentList">
<js:Li className="active">
<js:Div className="content__wrapper">
<palette:TabContent1/>
</js:Div>
</js:Li>
<js:Li>
<js:Div className="content__wrapper">
<palette:TabContent2/>
</js:Div>
</js:Li>
</js:Ul>
</palette:TabContainer>

The actual content is declared elsewhere. I added ids to the <ul> for the tabs and content to make it possible to set the correct classNames programmatically in addition to the automatic changes done by jquery.

Conclusion

That’s it. I’ve now incorporated some random HTML, JS and CSS into my project.

Of course, if I wanted to implement an actual cross-platform FlexJS component, it would be much more work (and ultimately more flexible), but I think this “hacking together” of random HTML found on the web is a pretty common need and I hope this tutorial is helpful.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Adapting HTML CSS JS project

ok-at-github edited this page Aug 28, 2017 · 5 revisions

The origin version of this document was written by Harbs. Thanks for contributing this awesome stuff!

CodePen live demo of the origin JavaScript project

Table of contents

Introduction
Step 1: Understanding the Structure
Step 2: Deciding what components we need
Step 3: Creating the Wrapper Component
Step 4: Adding Code
Step 5: Adding CSS
Step 6: Using the Component
Conclusion

Introduction

I needed a tabbed interface for an app and FlexJS does not yet have a built-in component which does this. I searched for some nicely formatted tabbed UIs and I found one I liked which was created by Lewi Hussey. Download it as zip or run the origin live demo via CodePen.
If you open the project, you will see there’s a specific hierarchy of HTML, CSS and JS that’s all needed for it to work correctly. I thought this would be a great opportunity to explain how to incorporate something like this into a project.

Step 1: Understanding the Structure

I stripped the content down to its core. This left me with the following HTML structure:

<section class="wrapper">
<ul class="tabs">
<li class="active">Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="tab__content">
<li class="active">
<div class="content__wrapper">
<h2>Section 1</h2>
<p>Section 1 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 2</h2>
<p>Section 2 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 3</h2>
<p>Section 3 text</p>
</div>
</li>
</ul>
</section>

The significant part of this is that we need the following pieces:

  • A “wrapper” around everything
  • A <ul> element for the tabs
  • A <ul> element for the content
  • A <li> element for each of the tabs
  • A <li> element for each of the content sections.

Step 2: Deciding what components we need

Technically we do not need any custom elements to create this setup. We can use a <js:Div> component for the wrapper, and <js:Ul> and <js:Li> components for the rest. However, it is easier if we create at least one component to contain the ActionScript version of the JavaScript code which does its thing. We can create the component either in ActionScript or MXML. The advantage of MXML is that we can declare both ActionScript code and the CSS in the same file. If we would use an ActionScript version, the JavaScript (ActionScript) can be included, but the CSS must go elsewhere.

The simplest component which can be used as a base for an MXML file is <js:Group>, so I am going to use that.

Step 3: Creating the Wrapper Component

On the simplest level, adding a new MXML <js:Group> component looks like this:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</js:Group>

All CSS styling will go within the <fx:Style> section, and all code will go within the <fx:Script> section. The actual content does not need to be declared inside the component because this component will be used inside another MXML file which will declare the sub-content there. The only thing we might want to do would be to declare some class name so we could apply consistent styling to all tab wrappers in our app. We do that like this:

<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer">

The reason I’m using <typeNames> rather than <className> is because <className> is added to the list of <typeNames> defined in the component. This allows me to set specific <classNames> to instances of the component and add class-based styling to instances while preserving the global styling.

Step 4: Adding Code

I stripped out the JavaScript code which is not component-specific and the remaining original code looks like this:

$(document).ready(function(){
// Variables
var clickedTab = $(".tabs > .active");
var tabWrapper = $(".tab__content");
var activeTab = tabWrapper.find(".active");
var activeTabHeight = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function() {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function() {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
height: activeTabHeight
}, 500, function() {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
});

To convert this to ActionScript code, we could try and rewrite this to use actual references to FlexJS components. Ultimately this would probably be more efficient and allow hooks into FlexJS functionality, but for my use case, I don’t really care that much about that. I just want to get the functionality of this code as quickly and easily as possible. I’m already using jquery elsewhere in my app, so there’s no extra code loading for doing so.

FlexJS already has type definitions for jquery, so we can actually assign types to the jquery code and get code intelligence in an IDE (I am using Visual Studio Code).

Additionally, there’s no reason to call $(document).ready() in FlexJS. I use initComplete instead and my component becomes:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer" initComplete="init()">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
private function init():void {
// Variables
var clickedTab:jQuery = $(".tabs > .active");
var tabWrapper:jQuery = $(".tab__content");
var activeTab:jQuery = tabWrapper.find(".active");
var activeTabHeight:Number = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function():void {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function():void {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex:Number = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
"height": activeTabHeight
}, 500, function():void {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
}
]]>
</fx:Script>
</js:Group>

One thing worth noting: in the animate() function, I changed the literal object notation to use property names in quotes. The reason I did this is to prevent Google Closure Compiler from minimizing the height property. That’s all we need to do to migrate the JS code for FlexJS.

Step 5: Adding CSS

To add the CSS, it should be as simple as copying and paste the CSS into the style element:

<fx:Style>
@namespace "http://www.w3.org/1999/xhtml";
.tabs {
display: table;
table-layout: fixed;
width: 100%;
transform: translateY(5px);
}
.tabs > li {
transition-duration: .25s;
display: table-cell;
list-style: none;
text-align: center;
padding: 20px 20px 25px 20px;
position: relative;
overflow: hidden;
cursor: pointer;
color: white;
}
.tabs > li:before {
z-index: -1;
position: absolute;
content: "";
width: 100%;
height: 120%;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(100%);
transition-duration: .25s;
border-radius: 5px 5px 0 0;
}
.tabs > li:hover:before {
transform: translateY(70%);
}
.tabs > li.active {
color: #50555a;
}
.tabs > li.active:before {
transition-duration: .5s;
background-color: white;
transform: translateY(0);
}
.tab__content {
background-color: white;
position: relative;
width: 100%;
border-radius: 5px;
}
.tab__content > li {
width: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
list-style: none;
}
.tab__content > li .content__wrapper {
text-align: center;
border-radius: 5px;
width: 100%;
padding: 45px 40px 40px 40px;
background-color: white;
}
.content__wrapper h2 {
width: 100%;
text-align: center;
padding-bottom: 20px;
font-weight: 300;
}
.content__wrapper img {
width: 100%;
height: auto;
border-radius: 5px;
}
</fx:Style>

To handle native HTML selectors like <li> it’s necessary to add the default namespace @namespace "http://www.w3.org/1999/xhtml";

That allows the compiler to understand unmodified CSS.

Step 6: Using the Component

Using the component is very straight-forward. We just follow the markup pattern in the original HTML using FlexJS markup syntax:

<palette:TabContainer>
<js:Ul className="tabs" id="tabList">
<js:Li className="active">
<js:TextNode text="{tabTitle1}"/>
</js:Li>
<js:Li>
<js:TextNode text="{tabTitle2}"/>
</js:Li>
</js:Ul>
<js:Ul className="tab__content" id="contentList">
<js:Li className="active">
<js:Div className="content__wrapper">
<palette:TabContent1/>
</js:Div>
</js:Li>
<js:Li>
<js:Div className="content__wrapper">
<palette:TabContent2/>
</js:Div>
</js:Li>
</js:Ul>
</palette:TabContainer>

The actual content is declared elsewhere. I added ids to the <ul> for the tabs and content to make it possible to set the correct classNames programmatically in addition to the automatic changes done by jquery.

Conclusion

That’s it. I’ve now incorporated some random HTML, JS and CSS into my project.

Of course, if I wanted to implement an actual cross-platform FlexJS component, it would be much more work (and ultimately more flexible), but I think this “hacking together” of random HTML found on the web is a pretty common need and I hope this tutorial is helpful.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Adapting HTML CSS JS project

ok-at-github edited this page Aug 28, 2017 · 5 revisions

The origin version of this document was written by Harbs. Thanks for contributing this awesome stuff!

CodePen live demo of the origin JavaScript project

Table of contents

Introduction
Step 1: Understanding the Structure
Step 2: Deciding what components we need
Step 3: Creating the Wrapper Component
Step 4: Adding Code
Step 5: Adding CSS
Step 6: Using the Component
Conclusion

Introduction

I needed a tabbed interface for an app and FlexJS does not yet have a built-in component which does this. I searched for some nicely formatted tabbed UIs and I found one I liked which was created by Lewi Hussey. Download it as zip or run the origin live demo via CodePen.
If you open the project, you will see there’s a specific hierarchy of HTML, CSS and JS that’s all needed for it to work correctly. I thought this would be a great opportunity to explain how to incorporate something like this into a project.

Step 1: Understanding the Structure

I stripped the content down to its core. This left me with the following HTML structure:

<section class="wrapper">
<ul class="tabs">
<li class="active">Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="tab__content">
<li class="active">
<div class="content__wrapper">
<h2>Section 1</h2>
<p>Section 1 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 2</h2>
<p>Section 2 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 3</h2>
<p>Section 3 text</p>
</div>
</li>
</ul>
</section>

The significant part of this is that we need the following pieces:

  • A “wrapper” around everything
  • A <ul> element for the tabs
  • A <ul> element for the content
  • A <li> element for each of the tabs
  • A <li> element for each of the content sections.

Step 2: Deciding what components we need

Technically we do not need any custom elements to create this setup. We can use a <js:Div> component for the wrapper, and <js:Ul> and <js:Li> components for the rest. However, it is easier if we create at least one component to contain the ActionScript version of the JavaScript code which does its thing. We can create the component either in ActionScript or MXML. The advantage of MXML is that we can declare both ActionScript code and the CSS in the same file. If we would use an ActionScript version, the JavaScript (ActionScript) can be included, but the CSS must go elsewhere.

The simplest component which can be used as a base for an MXML file is <js:Group>, so I am going to use that.

Step 3: Creating the Wrapper Component

On the simplest level, adding a new MXML <js:Group> component looks like this:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</js:Group>

All CSS styling will go within the <fx:Style> section, and all code will go within the <fx:Script> section. The actual content does not need to be declared inside the component because this component will be used inside another MXML file which will declare the sub-content there. The only thing we might want to do would be to declare some class name so we could apply consistent styling to all tab wrappers in our app. We do that like this:

<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer">

The reason I’m using <typeNames> rather than <className> is because <className> is added to the list of <typeNames> defined in the component. This allows me to set specific <classNames> to instances of the component and add class-based styling to instances while preserving the global styling.

Step 4: Adding Code

I stripped out the JavaScript code which is not component-specific and the remaining original code looks like this:

$(document).ready(function(){
// Variables
var clickedTab = $(".tabs > .active");
var tabWrapper = $(".tab__content");
var activeTab = tabWrapper.find(".active");
var activeTabHeight = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function() {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function() {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
height: activeTabHeight
}, 500, function() {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
});

To convert this to ActionScript code, we could try and rewrite this to use actual references to FlexJS components. Ultimately this would probably be more efficient and allow hooks into FlexJS functionality, but for my use case, I don’t really care that much about that. I just want to get the functionality of this code as quickly and easily as possible. I’m already using jquery elsewhere in my app, so there’s no extra code loading for doing so.

FlexJS already has type definitions for jquery, so we can actually assign types to the jquery code and get code intelligence in an IDE (I am using Visual Studio Code).

Additionally, there’s no reason to call $(document).ready() in FlexJS. I use initComplete instead and my component becomes:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer" initComplete="init()">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
private function init():void {
// Variables
var clickedTab:jQuery = $(".tabs > .active");
var tabWrapper:jQuery = $(".tab__content");
var activeTab:jQuery = tabWrapper.find(".active");
var activeTabHeight:Number = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function():void {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function():void {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex:Number = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
"height": activeTabHeight
}, 500, function():void {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
}
]]>
</fx:Script>
</js:Group>

One thing worth noting: in the animate() function, I changed the literal object notation to use property names in quotes. The reason I did this is to prevent Google Closure Compiler from minimizing the height property. That’s all we need to do to migrate the JS code for FlexJS.

Step 5: Adding CSS

To add the CSS, it should be as simple as copying and paste the CSS into the style element:

<fx:Style>
@namespace "http://www.w3.org/1999/xhtml";
.tabs {
display: table;
table-layout: fixed;
width: 100%;
transform: translateY(5px);
}
.tabs > li {
transition-duration: .25s;
display: table-cell;
list-style: none;
text-align: center;
padding: 20px 20px 25px 20px;
position: relative;
overflow: hidden;
cursor: pointer;
color: white;
}
.tabs > li:before {
z-index: -1;
position: absolute;
content: "";
width: 100%;
height: 120%;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(100%);
transition-duration: .25s;
border-radius: 5px 5px 0 0;
}
.tabs > li:hover:before {
transform: translateY(70%);
}
.tabs > li.active {
color: #50555a;
}
.tabs > li.active:before {
transition-duration: .5s;
background-color: white;
transform: translateY(0);
}
.tab__content {
background-color: white;
position: relative;
width: 100%;
border-radius: 5px;
}
.tab__content > li {
width: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
list-style: none;
}
.tab__content > li .content__wrapper {
text-align: center;
border-radius: 5px;
width: 100%;
padding: 45px 40px 40px 40px;
background-color: white;
}
.content__wrapper h2 {
width: 100%;
text-align: center;
padding-bottom: 20px;
font-weight: 300;
}
.content__wrapper img {
width: 100%;
height: auto;
border-radius: 5px;
}
</fx:Style>

To handle native HTML selectors like <li> it’s necessary to add the default namespace @namespace "http://www.w3.org/1999/xhtml";

That allows the compiler to understand unmodified CSS.

Step 6: Using the Component

Using the component is very straight-forward. We just follow the markup pattern in the original HTML using FlexJS markup syntax:

<palette:TabContainer>
<js:Ul className="tabs" id="tabList">
<js:Li className="active">
<js:TextNode text="{tabTitle1}"/>
</js:Li>
<js:Li>
<js:TextNode text="{tabTitle2}"/>
</js:Li>
</js:Ul>
<js:Ul className="tab__content" id="contentList">
<js:Li className="active">
<js:Div className="content__wrapper">
<palette:TabContent1/>
</js:Div>
</js:Li>
<js:Li>
<js:Div className="content__wrapper">
<palette:TabContent2/>
</js:Div>
</js:Li>
</js:Ul>
</palette:TabContainer>

The actual content is declared elsewhere. I added ids to the <ul> for the tabs and content to make it possible to set the correct classNames programmatically in addition to the automatic changes done by jquery.

Conclusion

That’s it. I’ve now incorporated some random HTML, JS and CSS into my project.

Of course, if I wanted to implement an actual cross-platform FlexJS component, it would be much more work (and ultimately more flexible), but I think this “hacking together” of random HTML found on the web is a pretty common need and I hope this tutorial is helpful.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Adapting HTML CSS JS project

ok-at-github edited this page Aug 28, 2017 · 5 revisions

The origin version of this document was written by Harbs. Thanks for contributing this awesome stuff!

CodePen live demo of the origin JavaScript project

Table of contents

Introduction
Step 1: Understanding the Structure
Step 2: Deciding what components we need
Step 3: Creating the Wrapper Component
Step 4: Adding Code
Step 5: Adding CSS
Step 6: Using the Component
Conclusion

Introduction

I needed a tabbed interface for an app and FlexJS does not yet have a built-in component which does this. I searched for some nicely formatted tabbed UIs and I found one I liked which was created by Lewi Hussey. Download it as zip or run the origin live demo via CodePen.
If you open the project, you will see there’s a specific hierarchy of HTML, CSS and JS that’s all needed for it to work correctly. I thought this would be a great opportunity to explain how to incorporate something like this into a project.

Step 1: Understanding the Structure

I stripped the content down to its core. This left me with the following HTML structure:

<section class="wrapper">
<ul class="tabs">
<li class="active">Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="tab__content">
<li class="active">
<div class="content__wrapper">
<h2>Section 1</h2>
<p>Section 1 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 2</h2>
<p>Section 2 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 3</h2>
<p>Section 3 text</p>
</div>
</li>
</ul>
</section>

The significant part of this is that we need the following pieces:

  • A “wrapper” around everything
  • A <ul> element for the tabs
  • A <ul> element for the content
  • A <li> element for each of the tabs
  • A <li> element for each of the content sections.

Step 2: Deciding what components we need

Technically we do not need any custom elements to create this setup. We can use a <js:Div> component for the wrapper, and <js:Ul> and <js:Li> components for the rest. However, it is easier if we create at least one component to contain the ActionScript version of the JavaScript code which does its thing. We can create the component either in ActionScript or MXML. The advantage of MXML is that we can declare both ActionScript code and the CSS in the same file. If we would use an ActionScript version, the JavaScript (ActionScript) can be included, but the CSS must go elsewhere.

The simplest component which can be used as a base for an MXML file is <js:Group>, so I am going to use that.

Step 3: Creating the Wrapper Component

On the simplest level, adding a new MXML <js:Group> component looks like this:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</js:Group>

All CSS styling will go within the <fx:Style> section, and all code will go within the <fx:Script> section. The actual content does not need to be declared inside the component because this component will be used inside another MXML file which will declare the sub-content there. The only thing we might want to do would be to declare some class name so we could apply consistent styling to all tab wrappers in our app. We do that like this:

<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer">

The reason I’m using <typeNames> rather than <className> is because <className> is added to the list of <typeNames> defined in the component. This allows me to set specific <classNames> to instances of the component and add class-based styling to instances while preserving the global styling.

Step 4: Adding Code

I stripped out the JavaScript code which is not component-specific and the remaining original code looks like this:

$(document).ready(function(){
// Variables
var clickedTab = $(".tabs > .active");
var tabWrapper = $(".tab__content");
var activeTab = tabWrapper.find(".active");
var activeTabHeight = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function() {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function() {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
height: activeTabHeight
}, 500, function() {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
});

To convert this to ActionScript code, we could try and rewrite this to use actual references to FlexJS components. Ultimately this would probably be more efficient and allow hooks into FlexJS functionality, but for my use case, I don’t really care that much about that. I just want to get the functionality of this code as quickly and easily as possible. I’m already using jquery elsewhere in my app, so there’s no extra code loading for doing so.

FlexJS already has type definitions for jquery, so we can actually assign types to the jquery code and get code intelligence in an IDE (I am using Visual Studio Code).

Additionally, there’s no reason to call $(document).ready() in FlexJS. I use initComplete instead and my component becomes:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer" initComplete="init()">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
private function init():void {
// Variables
var clickedTab:jQuery = $(".tabs > .active");
var tabWrapper:jQuery = $(".tab__content");
var activeTab:jQuery = tabWrapper.find(".active");
var activeTabHeight:Number = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function():void {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function():void {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex:Number = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
"height": activeTabHeight
}, 500, function():void {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
}
]]>
</fx:Script>
</js:Group>

One thing worth noting: in the animate() function, I changed the literal object notation to use property names in quotes. The reason I did this is to prevent Google Closure Compiler from minimizing the height property. That’s all we need to do to migrate the JS code for FlexJS.

Step 5: Adding CSS

To add the CSS, it should be as simple as copying and paste the CSS into the style element:

<fx:Style>
@namespace "http://www.w3.org/1999/xhtml";
.tabs {
display: table;
table-layout: fixed;
width: 100%;
transform: translateY(5px);
}
.tabs > li {
transition-duration: .25s;
display: table-cell;
list-style: none;
text-align: center;
padding: 20px 20px 25px 20px;
position: relative;
overflow: hidden;
cursor: pointer;
color: white;
}
.tabs > li:before {
z-index: -1;
position: absolute;
content: "";
width: 100%;
height: 120%;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(100%);
transition-duration: .25s;
border-radius: 5px 5px 0 0;
}
.tabs > li:hover:before {
transform: translateY(70%);
}
.tabs > li.active {
color: #50555a;
}
.tabs > li.active:before {
transition-duration: .5s;
background-color: white;
transform: translateY(0);
}
.tab__content {
background-color: white;
position: relative;
width: 100%;
border-radius: 5px;
}
.tab__content > li {
width: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
list-style: none;
}
.tab__content > li .content__wrapper {
text-align: center;
border-radius: 5px;
width: 100%;
padding: 45px 40px 40px 40px;
background-color: white;
}
.content__wrapper h2 {
width: 100%;
text-align: center;
padding-bottom: 20px;
font-weight: 300;
}
.content__wrapper img {
width: 100%;
height: auto;
border-radius: 5px;
}
</fx:Style>

To handle native HTML selectors like <li> it’s necessary to add the default namespace @namespace "http://www.w3.org/1999/xhtml";

That allows the compiler to understand unmodified CSS.

Step 6: Using the Component

Using the component is very straight-forward. We just follow the markup pattern in the original HTML using FlexJS markup syntax:

<palette:TabContainer>
<js:Ul className="tabs" id="tabList">
<js:Li className="active">
<js:TextNode text="{tabTitle1}"/>
</js:Li>
<js:Li>
<js:TextNode text="{tabTitle2}"/>
</js:Li>
</js:Ul>
<js:Ul className="tab__content" id="contentList">
<js:Li className="active">
<js:Div className="content__wrapper">
<palette:TabContent1/>
</js:Div>
</js:Li>
<js:Li>
<js:Div className="content__wrapper">
<palette:TabContent2/>
</js:Div>
</js:Li>
</js:Ul>
</palette:TabContainer>

The actual content is declared elsewhere. I added ids to the <ul> for the tabs and content to make it possible to set the correct classNames programmatically in addition to the automatic changes done by jquery.

Conclusion

That’s it. I’ve now incorporated some random HTML, JS and CSS into my project.

Of course, if I wanted to implement an actual cross-platform FlexJS component, it would be much more work (and ultimately more flexible), but I think this “hacking together” of random HTML found on the web is a pretty common need and I hope this tutorial is helpful.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Adapting HTML CSS JS project

ok-at-github edited this page Aug 28, 2017 · 5 revisions

The origin version of this document was written by Harbs. Thanks for contributing this awesome stuff!

CodePen live demo of the origin JavaScript project

Table of contents

Introduction
Step 1: Understanding the Structure
Step 2: Deciding what components we need
Step 3: Creating the Wrapper Component
Step 4: Adding Code
Step 5: Adding CSS
Step 6: Using the Component
Conclusion

Introduction

I needed a tabbed interface for an app and FlexJS does not yet have a built-in component which does this. I searched for some nicely formatted tabbed UIs and I found one I liked which was created by Lewi Hussey. Download it as zip or run the origin live demo via CodePen.
If you open the project, you will see there’s a specific hierarchy of HTML, CSS and JS that’s all needed for it to work correctly. I thought this would be a great opportunity to explain how to incorporate something like this into a project.

Step 1: Understanding the Structure

I stripped the content down to its core. This left me with the following HTML structure:

<section class="wrapper">
<ul class="tabs">
<li class="active">Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<ul class="tab__content">
<li class="active">
<div class="content__wrapper">
<h2>Section 1</h2>
<p>Section 1 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 2</h2>
<p>Section 2 text</p>
</div>
</li>
<li>
<div class="content__wrapper">
<h2>Section 3</h2>
<p>Section 3 text</p>
</div>
</li>
</ul>
</section>

The significant part of this is that we need the following pieces:

  • A “wrapper” around everything
  • A <ul> element for the tabs
  • A <ul> element for the content
  • A <li> element for each of the tabs
  • A <li> element for each of the content sections.

Step 2: Deciding what components we need

Technically we do not need any custom elements to create this setup. We can use a <js:Div> component for the wrapper, and <js:Ul> and <js:Li> components for the rest. However, it is easier if we create at least one component to contain the ActionScript version of the JavaScript code which does its thing. We can create the component either in ActionScript or MXML. The advantage of MXML is that we can declare both ActionScript code and the CSS in the same file. If we would use an ActionScript version, the JavaScript (ActionScript) can be included, but the CSS must go elsewhere.

The simplest component which can be used as a base for an MXML file is <js:Group>, so I am going to use that.

Step 3: Creating the Wrapper Component

On the simplest level, adding a new MXML <js:Group> component looks like this:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</js:Group>

All CSS styling will go within the <fx:Style> section, and all code will go within the <fx:Script> section. The actual content does not need to be declared inside the component because this component will be used inside another MXML file which will declare the sub-content there. The only thing we might want to do would be to declare some class name so we could apply consistent styling to all tab wrappers in our app. We do that like this:

<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer">

The reason I’m using <typeNames> rather than <className> is because <className> is added to the list of <typeNames> defined in the component. This allows me to set specific <classNames> to instances of the component and add class-based styling to instances while preserving the global styling.

Step 4: Adding Code

I stripped out the JavaScript code which is not component-specific and the remaining original code looks like this:

$(document).ready(function(){
// Variables
var clickedTab = $(".tabs > .active");
var tabWrapper = $(".tab__content");
var activeTab = tabWrapper.find(".active");
var activeTabHeight = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function() {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function() {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
height: activeTabHeight
}, 500, function() {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
});

To convert this to ActionScript code, we could try and rewrite this to use actual references to FlexJS components. Ultimately this would probably be more efficient and allow hooks into FlexJS functionality, but for my use case, I don’t really care that much about that. I just want to get the functionality of this code as quickly and easily as possible. I’m already using jquery elsewhere in my app, so there’s no extra code loading for doing so.

FlexJS already has type definitions for jquery, so we can actually assign types to the jquery code and get code intelligence in an IDE (I am using Visual Studio Code).

Additionally, there’s no reason to call $(document).ready() in FlexJS. I use initComplete instead and my component becomes:

<?xml version="1.0" encoding="utf-8"?>
<js:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:js="library://ns.apache.org/flexjs/basic"
typeNames="TabContainer" initComplete="init()">
<fx:Style>
</fx:Style>
<fx:Script>
<![CDATA[
private function init():void {
// Variables
var clickedTab:jQuery = $(".tabs > .active");
var tabWrapper:jQuery = $(".tab__content");
var activeTab:jQuery = tabWrapper.find(".active");
var activeTabHeight:Number = activeTab.outerHeight();
// Show tab on page load
activeTab.show();
// Set height of wrapper on page load
tabWrapper.height(activeTabHeight);
$(".tabs > li").on("click", function():void {
// Remove class from active tab
$(".tabs > li").removeClass("active");
// Add class active to clicked tab
$(this).addClass("active");
// Update clickedTab variable
clickedTab = $(".tabs .active");
// fade out active tab
activeTab.fadeOut(250, function():void {
// Remove active class all tabs
$(".tab__content > li").removeClass("active");
// Get index of clicked tab
var clickedTabIndex:Number = clickedTab.index();
// Add class active to corresponding tab
$(".tab__content > li").eq(clickedTabIndex).addClass("active");
// update new active tab
activeTab = $(".tab__content > .active");
// Update variable
activeTabHeight = activeTab.outerHeight();
// Animate height of wrapper to new tab height
tabWrapper.stop().delay(50).animate({
"height": activeTabHeight
}, 500, function():void {
// Fade in active tab
activeTab.delay(50).fadeIn(250);
});
});
});
}
]]>
</fx:Script>
</js:Group>

One thing worth noting: in the animate() function, I changed the literal object notation to use property names in quotes. The reason I did this is to prevent Google Closure Compiler from minimizing the height property. That’s all we need to do to migrate the JS code for FlexJS.

Step 5: Adding CSS

To add the CSS, it should be as simple as copying and paste the CSS into the style element:

<fx:Style>
@namespace "http://www.w3.org/1999/xhtml";
.tabs {
display: table;
table-layout: fixed;
width: 100%;
transform: translateY(5px);
}
.tabs > li {
transition-duration: .25s;
display: table-cell;
list-style: none;
text-align: center;
padding: 20px 20px 25px 20px;
position: relative;
overflow: hidden;
cursor: pointer;
color: white;
}
.tabs > li:before {
z-index: -1;
position: absolute;
content: "";
width: 100%;
height: 120%;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(100%);
transition-duration: .25s;
border-radius: 5px 5px 0 0;
}
.tabs > li:hover:before {
transform: translateY(70%);
}
.tabs > li.active {
color: #50555a;
}
.tabs > li.active:before {
transition-duration: .5s;
background-color: white;
transform: translateY(0);
}
.tab__content {
background-color: white;
position: relative;
width: 100%;
border-radius: 5px;
}
.tab__content > li {
width: 100%;
position: absolute;
top: 0;
left: 0;
display: none;
list-style: none;
}
.tab__content > li .content__wrapper {
text-align: center;
border-radius: 5px;
width: 100%;
padding: 45px 40px 40px 40px;
background-color: white;
}
.content__wrapper h2 {
width: 100%;
text-align: center;
padding-bottom: 20px;
font-weight: 300;
}
.content__wrapper img {
width: 100%;
height: auto;
border-radius: 5px;
}
</fx:Style>

To handle native HTML selectors like <li> it’s necessary to add the default namespace @namespace "http://www.w3.org/1999/xhtml";

That allows the compiler to understand unmodified CSS.

Step 6: Using the Component

Using the component is very straight-forward. We just follow the markup pattern in the original HTML using FlexJS markup syntax:

<palette:TabContainer>
<js:Ul className="tabs" id="tabList">
<js:Li className="active">
<js:TextNode text="{tabTitle1}"/>
</js:Li>
<js:Li>
<js:TextNode text="{tabTitle2}"/>
</js:Li>
</js:Ul>
<js:Ul className="tab__content" id="contentList">
<js:Li className="active">
<js:Div className="content__wrapper">
<palette:TabContent1/>
</js:Div>
</js:Li>
<js:Li>
<js:Div className="content__wrapper">
<palette:TabContent2/>
</js:Div>
</js:Li>
</js:Ul>
</palette:TabContainer>

The actual content is declared elsewhere. I added ids to the <ul> for the tabs and content to make it possible to set the correct classNames programmatically in addition to the automatic changes done by jquery.

Conclusion

That’s it. I’ve now incorporated some random HTML, JS and CSS into my project.

Of course, if I wanted to implement an actual cross-platform FlexJS component, it would be much more work (and ultimately more flexible), but I think this “hacking together” of random HTML found on the web is a pretty common need and I hope this tutorial is helpful.

Clone this wiki locally