1. #1
    Sencha User
    Join Date
    Mar 2010
    Posts
    25
    Vote Rating
    1
    BigSeanDawg is on a distinguished road

      0  

    Default HTML-focused DOM Layout for auto-height web applications (Ext 4.1)

    HTML-focused DOM Layout for auto-height web applications (Ext 4.1)


    Hey Ext community,

    We are making a new Ext application, and our team has Ext expertise, but our designers are providing a rich HTML/CSS experience that doesn't always fit nicely into the Ext Component hierarchy/layout. We need the browser scrolling (auto-height), and lots of custom HTML with heavy CSS.

    To address, I created what I'm calling a DOM layout, where a Container can provide the HTML around its children components. I'd love to get your thoughts or feedback!

    Dom.js

    Code:
    /**
     * @class jx.core.layout.Dom
     * @extends Ext.layout.container.Auto
     * 
     * Custom layout that reads a "domTpl" from the Container, and renders child "items" in the
     * template for the "section" attribute of children.
     */
    Ext.define('jx.core.layout.Dom', {
        alias: ['layout.dom', 'layout.domcontainer'],
        extend: 'Ext.layout.container.Auto',
        type: 'domcontainer',
        statics: {
            sectionRegexCache: {},
            catchAllSection: 'catch-all'
        },
        
        sectionTemplateDataPrefix: 'SECTION',
        
        renderTpl: [
            '{%this.renderBody(out,values)%}'
        ],
        
        /**
         * @property domTpl
         * Layout property that will render "items" into locations specified by the {@link #section}
         * attribute of child items.  This property can just be specified on the component instead
         * of in a "layoutConfig".
         */
        domTpl: null,
        
        /**
         * @property section
         * Read from each "item" to determine where it belongs in the {@link #domTpl}.
         */
        section: null,
    
        /**
         * Returns the section element for this layout.  If the sectionName is null or not found
         * the "catchAll" section is returned.
         */
        getSection: function(sectionName) {
            if (!sectionName || !this.sections[sectionName]) {
                sectionName = this.self.catchAllSection;
            }
            var section = this.sections[sectionName];
            if (section === this.self.catchAllSection) {
                section = this.owner.el;
            }
            else if (Ext.isString(section)) {
                //if we find a string, it is a section id, so we set it up to return the element next time
                var elId = this.owner.id + '-section-' + sectionName;
                this.sections[sectionName] = section = Ext.get(elId);
            }
            return section;
        },    
        
        /**
         * @Override
         * Check if the parent of the item has the correct "data-section" attribute
         */
        isValidParent : function(item, target, position) {
            var itemEl = item.el ? item.el.dom : Ext.getDom(item);
            var sectionName = this.getSectionName(item);
            
            var inSection = false;
            if (sectionName === this.self.catchAllSection) {
                inSection = this.owner.el.dom == itemEl.parentNode;
            }
            else {
                inSection =  (itemEl && Ext.fly(itemEl.parentNode).getAttribute('data-section') === sectionName);
            }
            return inSection;
        },
        
        /**
         * @Override
         * This is called when you add() an item to the layout.  We only need
         * to find the appropriate section node and render as a child.
         */
        renderItem: function(item) {
            var section = this.getSection(item.section);
            return this.callParent([item, section]);
        },
    
        /**
         * @Override
         * Here we override {@link Ext.layout.container.Container.doRenderItems} so that we can pass
         * in the "out" to {@link #getRenderTree}, since we are using that function to render all 
         * children in this one pass.
         */    
        doRenderItems: function (out, renderData) {
            renderData.$layout.getRenderTree(out);
        },
    
        /**
         * @Override
         * Overridden to take in the "out" variable, and then use the "renderCfgs" property to
         * render the HTML into the correct location in the {@link #domTpl}
         */
        getRenderTree: function(out) {
            // -- BEGIN SUPERCLASS IMPLEMENTATION --- //
            var result,
                items = this.owner.items,
                itemsGen,
                renderCfgs = {};
            
            do {
                itemsGen = items.generation;
                result = this.getItemsRenderTree(this.getLayoutItems(), renderCfgs);
            } while (items.generation !== itemsGen);
            //return result;
            // -- END SUPERCLASS IMPLEMENTATION --- //
            
            
            // -- BEGIN CUSTOM CODE --- //
            try {
                var cmp = this.owner,
                    domTplData = cmp.initRenderData(),
                    domTpl = cmp.domTpl || '';
                
                domTpl = this.parseDomTemplateSections(domTpl);
                this.setDomTemplateData(domTplData, renderCfgs);
                new Ext.XTemplate(domTpl).applyOut(domTplData, out);
            }
            catch (e) {
                this.logWarning(e);
            }
            // -- END CUSTOM CODE --- //
        },
        
        /**
         * @private
         * Reads the given template, looking for "data-section" attributes to set up as sections.
         * The new template is returned with the needed details to make adding/removing items
         * later possible.
         */
        parseDomTemplateSections: function(domTpl) {
            this.sections = {};
            var re = /(<(\S+)[^>]*\bdata-section=('|")(.*?)\3[^>]*>)(.*?)(<\/\2>)/g;
            var match;
            var newDomTpl = [];
            var lastStart = 0;
            
            /*
             * Here we setup the "catchAll" section, which is where we will always be able to render elements
             * who either don't have a section, or who point to a non-existant section.
             */
            domTpl += '{' + this.sectionTemplateDataPrefix + this.self.catchAllSection + '}';
            this.sections[this.self.catchAllSection] = this.owner.id;
            
            while (match = re.exec(domTpl)) {
                var fullMatch = match[0],
                    openTag = match[1],
                    tagName = match[2],
                    quoteUsed = match[3],
                    section = match[4],
                    tagContents = match[5],
                    closeTag = match[6];
                
                //throw an error if there are any ids declares on the tag, since dom layout needs to control the id
                if (/\bid=/i.exec(openTag)) {
                    throw "DOM Layout requires that no id be specified on section elements... " +
                        "Class: " + this.owner.self.getName() + ", Section: " + section + ", Tag: " + openTag;
                }
                
                var sectionId = "{id}-section-" + section;
                this.sections[section] = sectionId;
                var dataIndex = openTag.indexOf('data-section=');
                
                //pushing onto an array is much faster than replacing strings with "+="
                newDomTpl.push(domTpl.slice(lastStart, match.index));
                newDomTpl.push(openTag.slice(0, dataIndex))
                newDomTpl.push('id="' + sectionId);
                newDomTpl.push('" ');
                newDomTpl.push(openTag.slice(dataIndex));
                newDomTpl.push(tagContents);
                newDomTpl.push('{');
                newDomTpl.push(this.sectionTemplateDataPrefix);
                newDomTpl.push(section);
                newDomTpl.push('}');
                newDomTpl.push(closeTag);
                
                lastStart = match.index + fullMatch.length;
            }
            newDomTpl.push(domTpl.slice(lastStart));
            
            return newDomTpl.join('');
        },
        
        /**
         * @private
         * Sets up the domTplData so that child items get rendered into the proper sections
         */
        setDomTemplateData: function(domTplData, renderCfgs) {
            var layoutItems = this.getLayoutItems();
            for (var i = 0; i < layoutItems.length; i++) {
                var item = layoutItems[i];
                
                /*
                 * If the item has no section, we'll still render it in the "catchAll" section so that
                 * we don't get other errors about it not being rendered.
                 */
                var section = this.getSectionName(item, true);
                
                /*
                 * Insert an attribute in the template string: {SECTIONname}
                 */
                var tplAttr = this.sectionTemplateDataPrefix + section;
                domTplData[tplAttr] = (domTplData[tplAttr] || '') + Ext.DomHelper.markup(renderCfgs[item.id]);
            }
        },
        
        /**
         * @private
         */
        getSectionName: function(item, logWarning) {
            var sectionName = item.section;
            if (!sectionName) {
                sectionName = this.self.catchAllSection;
            }
            if (!this.sections[sectionName]) {
                if (logWarning) {
                    this.logWarning('No "' + sectionName + '" section found for class: ' + item.self.getName() + ' (id: ' + item.getId() + ')... The item will be rendered to the catchAll section!');
                }
                sectionName = this.self.catchAllSection;
            }
            return sectionName;
        },
        
        /**
         * @private
         */
        logWarning: function(err) {
            console && Ext.isFunction(console.warn) && console.warn(err);
        }
    
    });
    Here's the important parts:
    • Give your Ext.Container a domTpl attribute, which should be an XTemplate string
    • The template can have html elements with data-section attributes
    • Children of the container can have a section configuration attribute to say what section from the template they should be rendered into
    • If no section is provided (or the section doesn't exist) the component will be rendered at the bottom of the HTML segment generated from the component
    Example usage:

    Code:
    /**
     * Base class for all "App" pages, which sets up needed or common functionality.
     */
    Ext.define('jx.app.App', {
        extend: 'Ext.Container',
        requires: [
            'jx.core.layout.Dom',
            'jx.app.Header',
            'jx.app.Footer',
            'jx.artifact.ArtifactPage'
        ],
        
        initComponent: function() {
            Ext.apply(this, {
                layout: 'dom',
                domTpl: 
                    '<div data-section="header"></div>' +
                    
                    '<div class="container app-content">' +
                        '<div class="row">' +
                            '<div data-section="page" class="span12 page-content"></div>' +
                        '</div>' +
                        
                        '<div class="row">' +
                            '<div data-section="footer" class="span12"></div>' +
                        '</div>' +
                    '</div>',
                items: [
                    {
                        xtype: 'jx.app.Header',
                        section: 'header'
                    }, {
                        xtype: 'jx.app.Footer',
                        section: 'footer'
                    }, {
                        xtype: 'jx.artifact.ArtifactPage',
                        section: 'page'
                    }
                ]
            })
            this.callParent(arguments);
        }
        
    });
    In this example, I'm actually using the Bootstrap classes that produce really nice responsive layouts with minimal HTML. This markup would normally require 6 additional components.

    Does anyone think this is useful? Does Ext already support something similar? Any feedback, suggestions, or comments are welcome. Thanks!

  2. #2
    Sencha User
    Join Date
    Apr 2010
    Posts
    100
    Vote Rating
    0
    Dipish is an unknown quantity at this point

      0  

    Default


    It's difficult to get Ext's layout mechanism completely out of the way but I found it helpful to use Ext's auto layout in similar cases, possibly overriding some layout-related methods on components.

  3. #3
    Sencha User
    Join Date
    Mar 2010
    Posts
    25
    Vote Rating
    1
    BigSeanDawg is on a distinguished road

      0  

    Default


    Yeah, I hear you. Notice my layout class does actually extend Ext.layout.container.Auto so I am actually using "auto" layout. I just created this code to make it easy to have arbitrary children placed around a configurable dom tree, something our designers needed. The children can be removed and added at runtime, and the domTpl can change without messing with the order of the children.

  4. #4
    Sencha User
    Join Date
    Apr 2010
    Posts
    100
    Vote Rating
    0
    Dipish is an unknown quantity at this point

      0  

    Default


    Notice my layout class does actually extend Ext.layout.container.Auto so I am actually using "auto" layout
    Sorry, I actually overlooked this The issue is still relevant and it seems like Ext is making pure CSS layout more and more difficult to achieve with every new version.

    I opened a very similar issue today: Containers with CSS-driven layouts: how to make Ext get out of the way?
    Would love to see your input if you have any thoughts!

  5. #5
    Sencha User
    Join Date
    Dec 2012
    Posts
    4
    Vote Rating
    0
    faustofonseca is on a distinguished road

      0  

    Default Perfect

    Perfect


    My feedback about this is: you are a God! And all my children will be named after you (even if they are girls).

    This is really working and it is exactly what I needed. This should be integrated into ExtJs!

    Thank you very much!

  6. #6
    Sencha User
    Join Date
    Jun 2013
    Posts
    1
    Vote Rating
    0
    tyhwa is on a distinguished road

      0  

    Default


    It's realy cool! could you upload the whole examples?

film izle

hd film izle

film sitesi

takipci kazanma sitesi

takipci kazanma sitesi

güzel olan herşey

takipci alma sitesi

komik eğlenceli videolar