Showing posts with label css. Show all posts
Showing posts with label css. Show all posts


Chrome has a new flex layout support since version 29.0.1547.57, this cause a broken layout in Sencha Touch 2.2.1.

Fix this issue by changing the rule order of the st-box mixin.

Open resources/themes/stylesheets/sencha-touch/base/mixins/_Class.scss in a text editor and replace the mixin st-box with the following:

@mixin st-box($important: no) {
    @if $important == important {
        display: flex !important;
        display: -webkit-box !important;
        display: -ms-flexbox !important;
    } @else {
        display: flex;
        display: -webkit-box;
        display: -ms-flexbox;
    }
}
After re-compiling your css, your application layout should look as nice as in prior Chrome versions.


One element of themes in Sencha Touch 2.2 is the new use of icons as fonts. This is an awesome feature, because this offers the following new features:
  • size can be easily changed. 
  • color can be easily changed. 
  • shadow can be easily added to their shape. 
  • transparency nearly everywhere, unlike transparent png's in ie6. 
  • smaller in file size 
  • infinitely scaleable (because vector) 
The goal of using icon fonts is to replace the need to render icons on a web page using images.

Requirements

To use this new feature it is mandatory to setup your project with SASS. If your project not yet including SASS, take a look at this article "Theming Sencha Touch with SASS".

Out-of-the-box icons

The lightweight Sencha Touch 2.2 default theme already includes some basic icons. It is shipped with 27 icons in total.

The default icon set includes:
action, add, arrow_down, arrow_left, arrow_right, arrow_up, bookmarks, compose, delete, download, favorites, home, info, locate, maps, more, organize, refresh, reply, search, settings, star, team, time, trash and user.
Use the default icons above by typing:
{  xtype: 'button',  iconCls: 'user',  title: 'User'  }

Extend the Out-of-the-box icons

Sencha Touch 2.2 is now using the http://www.pictos.cc/font/ library. When you checkout this website, you'll find out that they have more to offer in terms of icons.

At the first glance, the icon collections on the website might be a little bit confusing. You might ask yourself how does the mapping works between the "iconCls" and the pictos.

Well, when you take a look inside the framework of Sencha Touch 2.2, you will find the following mapping in "Sencha Touch SDK/resources/themes/stylesheets/sencha-touch/base/mixins/_Class.scss":
@function icon-character-for-name($name) {
    // http://pictos.cc/font/

    // Row 1
    @if ($name == "anchor") { @return "a"; }
    @else if ($name == "box") { @return "b"; }
    @else if ($name == "upload") { @return "c"; }
    @else if ($name == "forbidden") { @return "d"; }
    @else if ($name == "lightning") { @return "e"; }
    @else if ($name == "rss") { @return "f"; }
    @else if ($name == "team") { @return "g"; }
    @else if ($name == "help") { @return "h"; }
    @else if ($name == "info") { @return "i"; }
    @else if ($name == "attachment") { @return "j"; }
    @else if ($name == "heart") { @return "k"; }
    @else if ($name == "list") { @return "l"; }
    @else if ($name == "music") { @return "m"; }
    @else if ($name == "table") { @return "n"; }
    @else if ($name == "folder") { @return "o"; }
    @else if ($name == "pencil") { @return "p"; }
    @else if ($name == "chat2") { @return "q"; }
    @else if ($name == "retweet") { @return "r"; }
    @else if ($name == "search") { @return "s"; }
    @else if ($name == "time") { @return "t"; }
    @else if ($name == "switch") { @return "u"; }
    @else if ($name == "camera") { @return "v"; }
    @else if ($name == "chat") { @return "w"; }
    @else if ($name == "settings2") { @return "x"; }
    @else if ($name == "settings") { @return "y"; }
    @else if ($name == "tags") { @return "z"; }

    // Row 2
    @else if ($name == "attachment2") { @return "A"; }
    @else if ($name == "bird") { @return "B"; }
    @else if ($name == "cloud") { @return "C"; }
    @else if ($name == "delete_black1") { @return "D"; }
    @else if ($name == "eye") { @return "E"; }
    @else if ($name == "file") { @return "F"; }
    @else if ($name == "browser") { @return "G"; }
    @else if ($name == "home") { @return "H"; }
    @else if ($name == "inbox") { @return "I"; }
    @else if ($name == "network") { @return "J"; }
    @else if ($name == "key") { @return "K"; }
    @else if ($name == "radio") { @return "L"; }
    @else if ($name == "mail") { @return "M"; }
    @else if ($name == "news") { @return "N"; }
    @else if ($name == "case") { @return "O"; }
    @else if ($name == "photos") { @return "P"; }
    @else if ($name == "power") { @return "Q"; }
    @else if ($name == "action") { @return "R"; }
    @else if ($name == "favorites") { @return "S"; }
    @else if ($name == "plane") { @return "T"; }
    @else if ($name == "user") { @return "U"; }
    @else if ($name == "video") { @return "V"; }
    @else if ($name == "compose") { @return "W"; }
    @else if ($name == "truck") { @return "X"; }
    @else if ($name == "chart2") { @return "Y"; }
    @else if ($name == "chart") { @return "Z"; }

    // Row 3
    @else if ($name == "expand") { @return "`"; }
    @else if ($name == "refresh") { @return "1"; }
    @else if ($name == "check") { @return "2"; }
    @else if ($name == "check2") { @return "3"; }
    @else if ($name == "play") { @return "4"; }
    @else if ($name == "pause") { @return "5"; }
    @else if ($name == "stop") { @return "6"; }
    @else if ($name == "forward") { @return "7"; }
    @else if ($name == "rewind") { @return "8"; }
    @else if ($name == "play2") { @return "9"; }
    @else if ($name == "refresh2") { @return "0"; }
    @else if ($name == "minus") { @return "-"; }
    @else if ($name == "battery") { @return "="; }
    @else if ($name == "left") { @return "["; }
    @else if ($name == "right") { @return "]"; }
    @else if ($name == "calendar") { @return "\005C"; }
    @else if ($name == "shuffle") { @return ";"; }
    @else if ($name == "wireless") { @return "'"; }
    @else if ($name == "speedometer") { @return ","; }
    @else if ($name == "more") { @return "."; }
    @else if ($name == "print") { @return "/"; }


    // Row 4
    @else if ($name == "download") { @return "~"; }
    @else if ($name == "warning_black") { @return "!"; }
    @else if ($name == "locate") { @return "@"; }
    @else if ($name == "trash") { @return "#"; }
    @else if ($name == "cart") { @return "$"; }
    @else if ($name == "bank") { @return "%"; }
    @else if ($name == "flag") { @return "^"; }
    @else if ($name == "add") { @return "&"; }
    @else if ($name == "delete") { @return "*"; }
    @else if ($name == "lock") { @return "("; }
    @else if ($name == "unlock") { @return ")"; }
    @else if ($name == "minus2") { @return "_"; }
    @else if ($name == "add2") { @return "+"; }
    @else if ($name == "up") { @return "{"; }
    @else if ($name == "down") { @return "}"; }
    @else if ($name == "screens") { @return "|"; }
    @else if ($name == "bell") { @return ":"; }
    @else if ($name == "quote") { @return "\""; }
    @else if ($name == "volume_mute") { @return "<"; }
    @else if ($name == "volume") { @return ">"; }
    @else if ($name == "help") { @return "?"; }

    // Backwards compat; icons that are not in the font
    @else if ($name == "arrow_left") { @return "["; }
    @else if ($name == "arrow_right") { @return "]"; }
    @else if ($name == "arrow_up") { @return "{"; }
    @else if ($name == "arrow_down") { @return "}"; }
    @else if ($name == "organize") { @return "I"; }
    @else if ($name == "bookmarks") { @return "I"; }
    @else if ($name == "loop2") { @return "r"; }
    @else if ($name == "star") { @return "S"; }
    @else if ($name == "maps") { @return "@"; }
    @else if ($name == "reply") { @return "R"; }

    @else {
        @return null;
    }
}
Ok, lets try this:
{  xtype: 'button',  iconCls: 'speedometer',  title: 'Speedometer'  }
But as you see in the result, the icon is still missing! This is because we did not included the icon in our "*.scss" file yet (because it is not in the range of the default icon set). To do this, add the following line to your "*.scss" file:
@include icon('speedometer');

Change the color or size of an icon

Changing the color of an icon is easier now than ever. All you need to do is adding the following line to your "*.scss" file:
.x-button-icon {
    color: #fff;
}
Now the color of your icon should change to white.

In case you want to change the size of the icon:
.x-button-icon {
    font-size: 50px;
}
Pretty simple, isn't it?

Add a icon to Ext.List

If you want to add a icon to Ext.List you need to define your own css class, because Ext.List do not have the iconCls config attribute.

In this example we add an user icon to Ext.List.

Open your "*.scss" file and add the following lines:
.userCls:before {
    font-family: "Pictos";
    content: "U";
    font-size: 1.5em;
}
Using the ":before" selector in CSS you can insert the user icon before the anchor text. Similarly, you can also use the :after selector to insert the icon after the text.

Ext.List item:
xtype : 'list',
store : 'your store',
itemTpl : new Ext.XTemplate(
 '<span class="userCls"></span>',
 '<span>{name}</span>',
 ...

Add more custom Icon-Fonts

If you need more icons, you can also attach icons from http://icomoon.io/app/ or checkout more icon collections.

The way to add custom Icon-Fonts is explained in this video: http://vimeo.com/66191690

Conclusion

Well, I hope this article helps. If you have any question, please contact me. In the mean time - let's keep developing apps guys.
One of the most important features of style sheets is that they specify how a document is to be presented on different media: screen, beamer, printer, with a speech synthesizer etc.

When you take a look at the ICEfaces TLD Reference you will ascertain, that the media attribute is not supported for ice:outputStyle tag.

When you now say, no problem - I'll take the normal HTML "link"-tag to do the same, you are wrong. When you need components like ice:inputFile, you must define your style sheets with ice:outputStyle. Otherwise your iFrame (where the input file component is placed) will not include the style information from the top site.

Here are the things I would like you to focus on:
  1. Change component class
  2. Change renderer class
  3. Register the custom classes in faces config
  4. Test and Hints

Change component class

At first we need the OutputStyle class from  ICEfaces svn http://www.icefaces.org/main/community/svninfo.iface.

My examples are based on ICEfaces V1.8.2 RC2.

Todo:
  • set a private string member "media"
  • implement public getter and setter methods for media
  • extend the existing saveState and restoreState methods with some "media" stuff. That should be self explanatory.
Here is the new OutputStyle class:

package com.yourcompany.faces.custom.component;

// Version: MPL 1.1/GPL 2.0/LGPL 2.1
//
// "The contents of this file are subject to the Mozilla Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations under
// the License.
//
// The Original Code is ICEfaces 1.5 open source software code, released
// November 5, 2006. The Initial Developer of the Original Code is ICEsoft
// Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
// 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
//
// Contributor(s): _____________________.
//
// Alternatively, the contents of this file may be used under the terms of
// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
// License), in which case the provisions of the LGPL License are
// applicable instead of those above. If you wish to allow use of your
// version of this file only under the terms of the LGPL License and not to
// allow others to use your version of this file under the MPL, indicate
// your decision by deleting the provisions above and replace them with
// the notice and other provisions required by the LGPL License. If you do
// not delete the provisions above, a recipient may use your version of
// this file under either the MPL or the LGPL License."


import javax.faces.component.UIComponentBase;
import javax.faces.el.ValueBinding;
import javax.faces.context.FacesContext;

public class OutputStyle extends UIComponentBase {

    public static final String COMPONENT_TYPE =
            "com.icesoft.faces.OutputStyleComp";
    public static final String COMPONENT_FAMILY =
            "com.icesoft.faces.OutputStyle";
    public static final String DEFAULT_RENDERER_TYPE =
            "com.icesoft.faces.style.OutputStyleRenderer";

    private String href;
    private String userAgent;
    private String media;

    public OutputStyle() {
        super();
    }

    public String getFamily() {
        return COMPONENT_FAMILY;
    }

    public String getRendererType() {
        return DEFAULT_RENDERER_TYPE;
    }

    public String getHref() {
        if (href != null) {
            return href;
        }
        ValueBinding vb = getValueBinding("href");
        if (vb != null) {
            return (String) vb.getValue(getFacesContext());
        }
        return null;
    }

    public String getUserAgent() {
        return userAgent;
    }

    public void setUserAgent(String userAgent) {
        this.userAgent = userAgent;
    }
    
    
    public String getMedia() {
        return media;
    }

    public void setMedia(String media) {
        this.media = media;
    }

    public void setHref(String href) {
        this.href = href;
    }

    public Object saveState(FacesContext context) {
        Object values[] = new Object[5];
        values[0] = super.saveState(context);
        values[1] = href;
        values[2] = userAgent;
        values[3] = media;
        return ((Object) (values));
    }

    public void restoreState(FacesContext context, Object state) {
        Object values[] = (Object[]) state;
        super.restoreState(context, values[0]);
        href = (String) values[1];
        userAgent = (String) values[2];
        media = userAgent = (String) values[3];
    }
}

Change renderer class

Now we need the OutputStyleRenderer class from svn.

Todo:
  • Correct the import directive for OutputStyles so that are custom component is pointed
  • Enhance the encodeEnd method with the new media attribute logic.
  • extend the existing saveState and restoreState methods with some "media" stuff. That should be self explanatory.
Here is the whole OutputStyleRenderer class:
package com.yourcompany.faces.custom.renderer;

// Version: MPL 1.1/GPL 2.0/LGPL 2.1
//
// "The contents of this file are subject to the Mozilla Public License
// Version 1.1 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations under
// the License.
//
// The Original Code is ICEfaces 1.5 open source software code, released
// November 5, 2006. The Initial Developer of the Original Code is ICEsoft
// Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
// 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
//
// Contributor(s): _____________________.
//
// Alternatively, the contents of this file may be used under the terms of
// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
// License), in which case the provisions of the LGPL License are
// applicable instead of those above. If you wish to allow use of your
// version of this file only under the terms of the LGPL License and not to
// allow others to use your version of this file under the MPL, indicate
// your decision by deleting the provisions above and replace them with
// the notice and other provisions required by the LGPL License. If you do
// not delete the provisions above, a recipient may use your version of
// this file under either the MPL or the LGPL License."

import com.icesoft.faces.context.DOMContext;
import com.icesoft.faces.renderkit.dom_html_basic.DomBasicRenderer;
import com.icesoft.faces.renderkit.dom_html_basic.HTML;
import com.icesoft.faces.util.CoreUtils;
import com.yourcompany.faces.custom.component.OutputStyle;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import java.beans.Beans;
import java.io.IOException;

public class OutputStyleRenderer extends DomBasicRenderer {

    private static Log log = LogFactory.getLog(OutputStyleRenderer.class);
    private static final String IE_EXTENTION = "_ie";
    private static final String IE_7_EXTENTION = "_ie7";
    private static final String IE_8_EXTENSION = "_ie8";
    private static final String SAFARI_EXTENTION = "_safari";
    private static final String SAFARI_MOBILE_EXTENTION = "_safarimobile";
    private static final String CSS_EXTENTION = ".css";
    private static final String DT_EXTENTION = "_dt";
    private static final String OPERA_EXTENTION = "_opera";
    private static final String OPERA_MOBILE_EXTENTION = "_operamobile";

    private static final int DEFAULT_TYPE = 0;
    private static final int IE = 1;
    private static final int SAFARI = 2;
    private static final int DT = 3;
    private static final int IE_7 = 4;
    private static final int SAFARI_MOBILE = 5;
    private static final int OPERA = 6;
    private static final int OPERA_MOBILE = 7;
    private static final int IE_8 = 8;

    public void encodeEnd(FacesContext facesContext, UIComponent uiComponent)
            throws IOException {
        validateParameters(facesContext, uiComponent, OutputStyle.class);
        try {
            DOMContext domContext =
                    DOMContext.attachDOMContext(facesContext, uiComponent);
            if (!domContext.isInitialized()) {
                OutputStyle outputStyle = (OutputStyle) uiComponent;
                Element styleEle = buildCssElement(domContext);
                String href = outputStyle.getHref();
                styleEle.setAttribute(HTML.HREF_ATTR, getResourceURL(facesContext,href));
                
                String media = outputStyle.getMedia();
                
                if(media != null) styleEle.setAttribute("media", getResourceURL(facesContext,media));
                
                domContext.setRootNode(styleEle);
                int browserType = browserType(facesContext, uiComponent);
                if (browserType != DEFAULT_TYPE) {
                    if (href.endsWith(CSS_EXTENTION)) {
                        int i = href.indexOf(CSS_EXTENTION);
                        if (i > 0) {
                            String start = href.substring(0, i);
                            Element ieStyleEle = buildCssElement(domContext);
                            String extention = IE_EXTENTION;
                            if (browserType == SAFARI) {
                                extention = SAFARI_EXTENTION;
                            }
                            if (browserType == DT) {
                                extention = DT_EXTENTION;
                            }
                            if(browserType == IE_7){
                                extention = IE_7_EXTENTION;
                            }
                            if(browserType == IE_8){
                                extention = IE_8_EXTENSION;
                            }
                            if(browserType == SAFARI_MOBILE){
                                extention = SAFARI_MOBILE_EXTENTION;
                            }
                            if(browserType == OPERA){
                                extention = OPERA_EXTENTION;
                            }
                            if(browserType == OPERA_MOBILE){
                                extention = OPERA_MOBILE_EXTENTION;
                            }
                            // W3C spec: To make a style sheet preferred, set the rel attribute to "stylesheet" and name the style sheet with the title attribute
                            ieStyleEle.setAttribute(HTML.TITLE_ATTR, extention);
                            String hrefURL = CoreUtils.resolveResourceURL(facesContext, start + extention + CSS_EXTENTION);
                            ieStyleEle.setAttribute(HTML.HREF_ATTR, hrefURL);
                            styleEle.getParentNode().appendChild(ieStyleEle);
                        } else {
                            throw new RuntimeException(
                                    "OutputStyle file attribute is too short. " +
                                    "Needs at least one character before .css. Current Value is [" +
                                    href + "]");
                        }
                    } else {
                        throw new RuntimeException(
                                "OutputStyle file attribute must end in .css. " +
                                "Current Value is [" + href + "]");
                    }
                }

            }
            domContext.stepOver();
        } catch (Exception e) {
            log.error("Error in OutputStyleRenderer", e);
        }
    }

    private Element buildCssElement(DOMContext domContext) {
        Element styleEle = domContext.createElement("link");
        styleEle.setAttribute(HTML.REL_ATTR, "stylesheet");
        styleEle.setAttribute(HTML.TYPE_ATTR, "text/css");
        return styleEle;
    }

    private int browserType(FacesContext facesContext, UIComponent uiComponent) {
        int result = DEFAULT_TYPE;
        String useragent = ((OutputStyle)uiComponent).getUserAgent();
        if(useragent != null){
            return _browserType(useragent);
        }

        Object o = facesContext.getExternalContext().getRequest();
        if (o != null) {
            if (o instanceof HttpServletRequest) {
                HttpServletRequest request = (HttpServletRequest) o;
                useragent = request.getHeader("user-agent");
                if(useragent == null){
                    useragent = ((OutputStyle)uiComponent).getUserAgent();
                }
                if(useragent == null){
                 if (log.isDebugEnabled()) {
                  log.debug("Not able to find user agent. Returning default");
                 }
                    return DEFAULT_TYPE;
                }
                if(((OutputStyle)uiComponent).getUserAgent() == null){
                    ((OutputStyle)uiComponent).setUserAgent(useragent.toLowerCase());
                }
                String user = useragent.toLowerCase();
                result = _browserType( user);

            } else {
             if (log.isDebugEnabled()) {
              log.debug(
                        "OutputStyleRenderer: Request is not HttpServletRequest. Its [" +
                        o.getClass().getName() + "]");
             }
            }
        } else {
         if (log.isDebugEnabled()) {
          log.debug(
                    "IceStyleReader: facesContext.getExternalContext().getRequest() is null");
         }
        }
        return result;
    }

    private int _browserType(String user) {
        int result = DEFAULT_TYPE;
        if (Beans.isDesignTime()) {
            result = DT;
        } else {
            if (user.indexOf("opera") < 0 && user.indexOf("msie") != -1) {
                result = IE;
                if(user.indexOf("msie 7") != -1){
                    result = IE_7;
                }
                if(user.indexOf("msie 8") != -1){
                    result = IE_8;
                }
            } else if (user.indexOf("safari") != -1) {
                result = SAFARI;
                if(user.indexOf("mobile") != -1) {
                    result = SAFARI_MOBILE;
                }
            } else if (user.indexOf("opera") != -1) {
                result = OPERA;
                if(user.indexOf("240x320") != -1) {
                    result = OPERA_MOBILE;
                }
            }
        }
        return result;
    }
}

Register the custom classes in faces config

The last step is to register our new logic in the faces-config.

<component>
  <description>Links one or more theme CSS files into the page</description>
  <display-name>Output Style</display-name>
  <component-type>com.icesoft.faces.OutputStyleComp</component-type>
  <component-class>com.yourcompany.faces.custom.component.OutputStyle</component-class>
  <component-extension>
   <base-component-type>com.sun.faces.Component</base-component-type>
   <component-family>com.icesoft.faces.OutputStyle</component-family>
   <renderer-type>com.yourcompany.faces.custom.renderer.OutputStyleRenderer</renderer-type>
  </component-extension>
</component>

<render-kit>
  <render-kit-id>ICEfacesRenderKit</render-kit-id>
  <render-kit-class>com.icesoft.faces.renderkit.D2DRenderKit</render-kit-class>
  <renderer>
   <component-family>com.icesoft.faces.OutputStyle</component-family>
   <renderer-type>com.icesoft.faces.style.OutputStyleRenderer</renderer-type>
   <renderer-class>com.yourcompany.faces.custom.renderer.OutputStyleRenderer</renderer-class>
  </renderer>
 </render-kit>

Test and Hints

When all changes are done the new tag should be avalaible now. Simply type in your template:

<ice:outputStyle href="/css/yourStyle.css" media="all"/>
<ice:outputStyle href="/css/yourPrintStyle.css" media="print"/>

Hint: When you want to use the media attribute in an iFrame component like ice:inputFile too, you need to modifiy some more things. In this case you've to modify the class InputFile and a re-build of the ICEfaces libs is essential.