Jemt / SitemagicCMS

Sitemagic CMS - world's most beautiful Content Management System
http://sitemagic.org
Other
16 stars 11 forks source link

SMDesigner - Designer elements should have the ability to span page #110

Open Jemt opened 5 years ago

Jemt commented 5 years ago

Consider the following example.


image


Using pseudo elements we can make a container "stretch" across the page, just like a header image. It would be great if this was supported out of the box for a container registered as a designer element (SMDesignerElement class).

<div class="SMDesignerElement FrontPageSection1" data-id="Front page section 1" data-preserve="true">Content aligns beautifully with the ordinary content</div>
/* Generated using Designer's default controls for designer elements */
.SMDesignerElement[data-id='Front page section 1']
{
    height: 14em;
    margin-top: 2em;
    margin-bottom: 2em;
    background: #2999C2;
    color: #FCFCFC;
}

/* Applied using Advanced in Designer */
div.FrontPageSection1
{
    padding: 1.5em;
    overflow: hidden;
}
html.SMPagesFilenameIndex div.FrontPageSection1:before, html.SMPagesEditor.SMPagesFilenameIndex div.FrontPageSection1:before
{
    content: "";
    margin-top: -1.5em; /* Same value as padding above, but as a negative */
    background: inherit;
    position: absolute;
    padding: inherit;
    padding-left: 0px;
    padding-right: 0px;
    left: 0px;
    width: 100%;
    height: inherit; /* Notice: height MUST be set in designer for this to work! */
    z-index: -1;
}
Jemt commented 5 years ago

Unfortunately the approach described above scales poorly on mobile. When the width of the screen is reduced, text takes up more space vertically. Defining a height with the 'em' unit is not sufficient. So the text can either overflow, become hidden, or cause scroll.

We need to support this using JavaScript. The example below (review - quick and dirty!) calculates the height of the designer element, and adds a pseudo element behind it that spans the page, with the same height.

SMEventHandler.AddEventHandler(document, "DOMContentLoaded", function(e)
{
    // Helpers (copied from Fit.UI)

    var UpperCaseFirst = function(str)
    {
        Fit.Validation.ExpectString(str);

        if (str === "")
            return str;

        return str[0].toUpperCase() + str.slice(1);
    }

    var ForEach = SMCore.ForEach;

    var GetComputedStyle = function(elm, style)
    {
        var res = null;

        if (window.getComputedStyle) // W3C
        {
            res = window.getComputedStyle(elm)[style];
        }
        else if (elm.currentStyle)
        {
            if (style.indexOf("-") !== -1) // Turn e.g. border-bottom-style into borderBottomStyle which is required by legacy browsers
            {
                var items = style.split("-");
                style = "";

                /*Fit.Array.*/ForEach(items, function(i)
                {
                    if (style === "")
                        style = i;
                    else
                        style += /*Fit.String.*/UpperCaseFirst(i);
                });
            }

            res = elm.currentStyle[style]; // Might return strings rather than useful values - e.g. "3em" or "medium"

            // IE Computed Style fix by Dean Edwards - http://disq.us/p/myl99x
            // Transform values such as 2em or 4pt to actual pixel values.

            if (res !== undefined && res !== null && /^\d+/.test(res) === true && res.toLowerCase().indexOf("px") === -1) // Non-pixel numeric value
            {
                // Save original value
                var orgLeft = elm.style.left;

                // Calculate pixel value
                var runtimeStyle = elm.runtimeStyle.left;
                elm.runtimeStyle.left = elm.currentStyle.left;
                elm.style.left = ((style === "fontSize") ? "1em" : res || 0); // Throws error for a value such as "medium"
                res = elm.style.pixelLeft + "px";

                // Restore value
                elm.style.left = orgLeft;
                elm.runtimeStyle.left = runtimeStyle;
            }
        }

        return (res !== undefined ? res : null);
    }

    var bars = document.querySelectorAll(".page-wide-bar");

    // Configure bars

    SMCore.ForEach(bars, function(bar)
    {
        var s = document.createElement("style");
        s.type = "text/css";
        document.getElementsByTagName("head")[0].appendChild(s);

        if (!bar.id)
        {
            bar.id = "rid_" + SMRandom.CreateGuid(); // Random ID (rid)
        }
        else if (bar.className.indexOf("SMDesignerElement") > -1 && !bar.getAttribute("data-id"))
        {
            bar.setAttribute("data-id", bar.id);
        }

        bar.__pageWideBarStyle = s;

        //bar.style.boxSizing = "border-box";
    });

    // Define updator

    var designerOpen = false;

    var updateBars = function()
    {
        SMCore.ForEach(bars, function(bar)
        {
            var newHeight = bar.offsetHeight;

            if (designerOpen === false && newHeight === bar.__prevBarOffsetHeight)
            {
                //console.log("Escaping (offset height)");
                return; // Skip
            }

            bar.__prevBarOffsetHeight = newHeight;

            // TODO: Include borders etc!
            var paddingTop = /*SMDom.*/GetComputedStyle(bar, "paddingTop");
            var paddingTopFloat = parseFloat(paddingTop);
            var paddingBottomFloat = parseFloat(/*SMDom.*/GetComputedStyle(bar, "paddingBottom"));
            var checkSum = newHeight + "#" + paddingTop + "#" + paddingTopFloat + "#" + paddingBottomFloat;

            if (bar.__prevBarCheckSum === checkSum)
            {
                //console.log("Escaping (checksum)");
                return; // Skip
            }

            bar.__prevBarCheckSum = checkSum;

            bar.__prevAlternateValue = !bar.__prevAlternateValue;

            var css = "#" + bar.id + ":before";
            css += "\n{";
            css += "\n\t content: '" + (bar.__prevAlternateValue ? "" : " ") + "';"; // Value MUST change to make the element update in Legacy IE
            css += "\n\t margin-top: -" + paddingTop + ";";
            css += "\n\t background: inherit;";
            //css += "\n\t background: orange;";
            css += "\n\t position: absolute;";
            css += "\n\t padding: inherit;";
            css += "\n\t padding-left: 0px;";
            css += "\n\t padding-right: 0px;";
            css += "\n\t left: 0px;";
            css += "\n\t width: 100%;";
            css += "\n\t height: " + (bar.offsetHeight - paddingTopFloat - paddingBottomFloat) + "px;"; // Does not take borders into account!
            css += "\n\t z-index: -1;";
            css += "\n}";

            console.log("Updating CSS: ", css);

            if (bar.__pageWideBarStyle.styleSheet)
            {
                bar.__pageWideBarStyle.styleSheet.cssText = css; // Legacy IE
            }
            else
            {
                bar.__pageWideBarStyle.innerHTML = css;
            }
        });
    }

    updateBars();

    // Monitor - update when necessary

    setInterval(function() { updateBars(); }, (designerOpen === true ? 500 : 1500));
    SMEventHandler.AddEventHandler(window, "resize", function(e) { updateBars(); });
});