Lief's Layout Manager is a Typescript/Javascript 'div' management framework, which add layout and event capabilities to your client code. It works in addition to all your current layout techniques.
Lief's Layout Manager was designed to make the following easier:
Lief's Layout Manager is a simply a small amount of javascript code. Simply add one line to the beginning of your code.
</script>
This will be published on NPM in the near future.
The above code shows a basic example of how to use Liefs-layout-manager.
Lief's Layout manager is TINY! (Full is about half of Jquery), however, you can only load what you need. If you want the entire layout manager, simply use:
By using this link, you are ensured to have all the components properly loaded. This is the equivelent to the following:
Lief's Layout Manager is divided in Components, so that you can only load, what you only need, keeping your code size TINY
Lief's Layout Manager "Core" is the essentials to work this software.
By combining DisplayCells with Element_s and Events, you can layout ANY rectangular web page.
Liefs's Layout Manager Objects use "By Type, then Index" notation, rather than standard, "By Index" notation. Normally, when you define an object or function, the order is critical:
But Lief's layout manager sees the above as One Number, One String, and One Function. The order is not important unless you have multiple entryies as the same type. This means that Lief's Layout Manager sees this as equivelent to:
Lief's Layout Manager implements FunctionStack, which is a simple way to stack functions on all events. It works on any event.
window.onmousemove = FunctionStack.push(window.onmousemove, function one(){console.log("one")});
window.onmousemove = FunctionStack.push(window.onmousemove, function two(){console.log("two")});
window.onmousemove = FunctionStack.push(window.onmousemove, function three(){console.log("three")});
window.onmousemove = FunctionStack.push(window.onmousemove, function four(){console.log("four")});
Now, the window.onmousemove event triggers ALL of the functions. To remove an object, just pop it using the name of the function
window.onmousemove = FunctionStack.pop(window.onmousemove, "one");
You can try the above code in the Console (F12) now.
A Coord Object simply stores the x, y, width, height, and zindex of an element. The instance properties are as follows:
label:string; // label of the Coord
frozen:boolean; // if true, it cant be changed until set to false again
x: number; // the x component
y: number; // the y component
width_: number; // the width component
height: number; // the height component
x2:number; // read only - returns x + width
y2:number; // read only - return y + width
zindex: number;
within: Within = new Within();
hideWidth: boolean;
offset: {x:number, y:number, width:number, height:number};
setOffset(x=0, y=0, width=0, height=0);
assign(x=undefined, y=undefined, width=undefined, height=undefined,
wx=undefined, wy=undefined, wwidth=undefined, wheight=undefined, zindex=undefined);
copy(fromCoord:Coord,
x:number=undefined, y:number=undefined, width:number=undefined, height:number=undefined,
zindex:number=undefined):Coord;
log();
isCoordCompletelyOutside(WITHIN: Coord|Within = this.within):boolean;
isPointIn(x:number, y:number): boolean;
Lief's layout manager creates a "Render Tree". There is a root object, then children of that, then children of those, and so on. Each of these "nodes" are wrapped in a DisplayCell Object,
let myNewDisplayCell = new DisplayCell("someName")
There are a few ways of implementing this wrapping process.
let myNewDisplayCell = new DisplayCell( new Element_("myElementName") );
let myNewDisplayCell = new DisplayCell().addComponent( new Element_("myElementName"));
let myNewDisplayCell = I("myElementName");
The above lines are all equivelent. It depends on how you like to build your project.
A DisplayCell Instance has the following properties and methods
coord: Coord; // Each DisplayCell has a Co-ordinates Object (Assigned Automatically)
children: Component[]; // Array of children Objects in render Tree
parentDisplayCell: DisplayCell; // If not the root DisplayCell, it's parent DisplayCel
marginLeft: number; // optional Margin
marginRight: number; // optional Margin
marginTop: number; // optional Margin
marginBottom: number; // optional Margin
node: node_; // Render Node - Created during the Render Process (Designed as Read Only)
dim: string; // a number string ending with either "px" or "%" - used with DisplayGroup
min: number; // a minimum number of pixels this cell will be in a DisplayGroup (Default 1)
addComponent(component: Component): DisplayCell; // Add a child Component.
getComponent(type: string, label?: string): object; // Get a Child Component for example ("DisplayGroup", "myDisplayGroup")
deleteComponent(type: string, label?: string): boolean; // Delete a child Component for example ("DisplayGroup", "myDisplayGroup")
addEvents(Argument: object): void; // Assuming Child "Element_" -> Adds events to the child
//Example
let leftSideElement = new Element_("Left Side", "Left Side InnerHtml");
let leftSide = new DisplayCell( "200px",{
marginLeft: 10,
marginRight: 5,
marginTop: 2,
marginBottom : 7,
}).addComponent( leftSideElement ).addEvent({onclick:function(){console.log("left clicked")}});
let rightSide = I("Right Side","Right Side InnerHtml", events({console.log("right clicked")}));
let horizontal = h("horizontalDisplayGroup",leftSide, rightSide)
horizontal.marginLeft = 20;
H("SomeHandler", horizontal);
DisplayCell Object (static, not instance) has the following properties:
static instances:{[key: string]: DisplayCell;} = {};
static defaults:{[key: string]: any;};
static argMap:{[key: string]: Array;}
static objectTypes:Set;
//to look at these type this in the Console:
DisplayCell.instances // Stores all instances Created in an Object
DisplayCell.defaults // Default instance values
DisplayCell.argMap // A mapping of argument types, to properties
DisplayCell.objectTypes // All Componenets registered (to check if non core componenet is loaded)
DisplayGroups divide a DisplayCell in to either a Horizontal Array, or a Vertical Array. The size of each item in the Array is determined by the "dim" value of each child DisplayCell. Any string that ends with "%" or "px" is recgonized as a "dim" value. DisplayGroups are the most common way to layout your screen.
The Above example illistrates how to nest 'DisplayGroups' with 'Element_'s.
allowScrollBar:boolean; // set to be true, if a scrollbar is desired (and loaded - Componenet, not Core)
label:string; // the label for this instance
dim:string; // Used if this DisplayGroup, is a child of a different DisplayGroup
margin:number; // The distance bewteen the Cells of the DisplayGroup
node:node_; // Render Node -> Created a Render stage.
parentDisplayCell:DisplayCell; // It's DisplayCell Parent
children: DisplayCell[] = []; // The Array of Child DisplayCells
isHor: boolean; // true (default) if Horizontal, false if vertical
scrollbar: ScrollBar; // Active Scrollbar (Assuming allowScrollBar is true, and Scrollbar Comonenet is loaded)
offset:number; // Internal use -> offset provided by scrollbar
DisplayGroup Object (static, not instance) has the following properties:
static instances:{[key: string]: DisplayGroup;}
static defaults:{[key: string]: any;};
static argMap:{[key: string]: Array;};
// So, in the Console, try:
DisplayGroup.instances
DisplayGroup.defaults
DisplayGroup.argMap
The "Handler" object is a "Root" node of a Render Tree. By Default, Handlers use the outer screen size as the default. Handler size can be assigned programatically, or assigned to some other 'div'
let myNewHandler = new Handler("someName"); let handlerDisplayCell = new DisplayCell( myNewHandler );
let handlerDisplayCell = new DisplayCell("someName").addComponent( new Handler("someName") );
let handlerDisplayCell = H("someName");
The above lines are all equivelent. Again, it depends how you like to program.
A Handler Instance has the following Properties:
type: string; // the type of Handler (modals go to the top layer)
label: string; // the label of the Hander
startRendered: boolean; // if true, render on define, if false await handlerInstance.show();
coord: Coord; // co-ordinate of the Handler ()
parentDisplayCell: DisplayCell; // Parent DisplayCell, holding the Handler
children: Component[]; // Children to be rendered
node: node_; // Render Node, Created when Rendered
preRenderCallBack: function(handler: Handler){}; // optional callback
postRenderCallBack: function(handler: Handler){}; // optional callback
show(): void; // shows the handler rendered
hide(): void; // remove the handler, and stop rendering it
A Handler static (not instance) methods are as follows:
Handler.instances:{[key: string]: Handler;};
Handler.defaults:{[key: string]: any;};
Handler.argMap:{[key: string]: Array;}
Handler.ScreenSizeCoord: Coord;
Lief's Layout Manager manages a div with an Element_ Object.
let myNewDisplayCell = new DisplayCell( new Element_("myElementName") );
let myNewDisplayCell = new DisplayCell().addComponent( new Element_("myElementName"));
let myNewDisplayCell = I("myElementName");
Lets stick to the 3rd method, because it uses less code. To create an element, ('div') simply create one as follows:
let myNewElement = I("SomeName", "This is the 'innerHTML' of the div", "cssClassName");
// Completely Created in Javascript
let myNewElement = I("SomeName", {css:"cssClassName"});
// since no innerHTML was specified, checks the dom for a 'div' with id="SomeName"
An Element_ instance has the following Properties:
ignoreInner:boolean; // set true if some "funtionality" sets the innerHTML
label:string; // label of the Element_
el:HTMLDivElement; // the actual div element in the dom
evalInner:function(THIS:Element_){return string}; // function to set the value of the innerHTML
innerHTML:string; // value of innerHTML (if constant)
css:string; // the class="css" value
dim:string; // used in DisplayGroup, and passed on to the parent DisplayCell
Css:Css; // Setting the CSS using a Css Instance
events:objectFunction; // an object that holds events ie: {onclick:function(){console.log("clicked")}}
processEvents:objectFunction; // a pre-holding place for events, so FunctionStack can be applied
attributes:objectString; // attribute object for the div element, for example {title:"On Hover Comment"}
parentDisplayCell: DisplayCell; // Parent DisplayCell (Co-Ordinates of Element_)
addEvents(eventObject:object); // add events (which can be stacked) to an Element_, for example {onclick:function(){console.log("clicked")}}
The Element_ Object has the following Static Properties
Element_.instances:{[key: string]: Element_;}
Element_.defaults:{[key: string]: any;}
Element_.argMap:{[key: string]: Array;}
Element_.customEvents:{[type: string]: (newData:any)=>object;};
Events are attached to 'Elements_' ('div')'s. This is done as shown:
let SomeNameEvents = events({onclick:function(e){console.log(e,this);}})
let myNewElement = I("SomeName", "This is the 'innerHTML' of the div", "cssClassName", SomeNameEvents);
// Completely Created in Javascript
let myNewElement = I("SomeName", {css:"cssClassName"}, events({onclick:function(e){console.log(e,this);}}));
// since no innerHTML was specified, checks the dom for a 'div' with id="SomeName"
In the above example, we have attached the same 'onclick' event to all Elements_, however we could attach any event(s) as selectivly as we choose.
Events Can be Stacked. For Example, you can add or remove multiple events of the same time to an element
a node_ is a basic tree object that has a parent, and children (so a tree object). By itself, it doesn't do a lot, but you can use it to assign data to a tree form. When objects are rendered, they produce a tree. For example: try this in the console:
function sample(){
let node = new node_(); // first you create a root node
node.newChild("One") // the first child IS the top node
.newChild("One-A")
.newChild("One-A-1")
.newSibling("One-A-2")
.parent() // be sure to use .parent() to move back up the tree
.newSibling("One-B")
.newChild("One-B-1")
.newSibling("One-B-2")
.newChild("One-B-2-1")
.parent() // be sure to use .parent() to move back up the tree
.parent() // be sure to use .parent() to move back up the tree
.newSibling("One-C")
.parent() // be sure to use .parent() to move back up the tree
.newSibling("Two")
.newChild("Two-A")
.newChild("Two-A-1")
.parent() // be sure to use .parent() to move back up the tree
.newSibling("Two-B")
.parent() // be sure to use .parent() to move back up the tree
.newSibling("Three")
return node;
}
This sample is built in to Lief's Layout manager. To view it, simply type:
// Try this in the console now! (F12)
let node = sample(); // create the above node tree
node.log() // show tree, without object nodes
node.log(true) // show tree with object nodes
This is the standard tree object used with Lief's layout manager. By looking at:
Render.node.log(true); // try this in the console now!
You can see how the elements on the page are rendered
The Render object renders the output to the screen. Whenever you change anything that changes the content on the screen, use:
Render.scheduleUpdate(); // tells the system to update on next tic (so now)
I hope the following Exmaples help explain how Lief's Layout Manager Works.
Components are additional functionality added to Lief's Layout Manager.
Context is simply a drop down menu. This could occur on a "right-click" or a "click" or a "onhover" etc... How it is used is up to you. Lets look at an example.
This Example shows context added to a Tree, Cell, and Pages. You can event Context, a Context if you want to.
A DragBar resizes one DisplayCell within a DisplayGroup.
A DragBar can be added to any DisplayCell. Argument are label:string, min:number, max:number, and width:number (optional)
A Modal is a Handler, defined within a "window". It has a "pre-built" style called a winModal. Try this example In the console now, or simply launch another instance
new winModal("MyModal_1", "My Title", "This is the Body")
Note, like all objects in Lief's Layout Manager, Each new Modal, or winModal must have it's own unique label. Note: By Default, a Modal/winModal does not "Stretch" - but this can easily be achieved by adding one:
new winModal("MyModal_2", "My Title", "This is the Body", {
sizer:{ minWidth:100, maxWidth:1000, minHeight:100, maxHeight:700, width:300, height:300 }
});
You can pass ANY displaycell instead of a Body String:
new winModal("MyModal_3", "My Title",
v("MyModal_3_v",
h("MyModal_3_h1",
I("MyModal_3_1","This", css("BlueBg","background:blue;color:white")),
I("MyModal_3_2","is", css("greyBG","background:gray;color:white;")),
),
h("MyModal_3_h2",
I("MyModal_3_3","my", css("orangeBG","background:orange")),
I("MyModal_3_4","modal", css("cyanBG", "background:cyan;")),
),
),
{sizer:{ minWidth:100, maxWidth:1000, minHeight:100, maxHeight:700, width:300, height:300 }}
);
By using a Basic Modal, rather than a winModal, you can add as many Drag/close options as you wish.
let purpleBG = css("purpleBG", "background:purple;");
let redBG = css("redBG", "background:red;");
let leftDragable = I("Modal4_LeftDraggable", redBG);
let leftClose = I("Modal4_LeftClose", "X", purpleBG, "20px");
let rightDragable = I("Modal4_RightDraggable", redBG);
let rightClose = I("Modal4_RightClose", "X", purpleBG, "20px");
let myNewModal = new Modal("MyModal_4",
h("MyModal_4_body",
v("MyModal_4_left", leftDragable, leftClose, "20px"),
v("MyModal_4_v",
h("MyModal_4_h1",
I("MyModal_4_1","This", css("BlueBg","background:blue;color:white")),
I("MyModal_4_2","is", css("greyBG","background:gray;color:white;")),
),
h("MyModal_4_h2",
I("MyModal_4_3","my", css("orangeBG","background:orange")),
I("MyModal_4_4","modal", css("cyanBG", "background:cyan;")),
),
),
v("MyModal_4_right", rightDragable, rightClose, "20px")
),
{sizer:{ minWidth:100, maxWidth:1000, minHeight:100, maxHeight:700, width:300, height:300 }}
)
myNewModal.dragWith(leftDragable, rightDragable);
myNewModal.closeWith(leftClose, rightClose)
myNewModal.show();
The Pages Object describes a 'div' that could have different values. Each Value, is refered to as a page.
Pages can be used with Select, to Select the Buttons When Pressed
Pages can be used with Tree, again Selection of Tree nodes is an option
This last example has the page change on "screen size" - so you will need a modal or window to see the effect
A ScrollBar
Something
Something
Let's look at our origional example again
The Above Examples Shows:
// * Note * try these lines one at a time, as each represents an object.
Css.instances.greenBG // By Defining Css in Javascript, you can modify it easily in Javascript
Css.instances.blueBG // a css file WILL work fine like normal, but I like it all in one place.
Handler.instances.core_00 // The Handler instance defined with H() (wrapped in a DisplayCell)
DisplayGroup.instances.core_00_h // The DisplayGroup instance h() 'h' for Horizontal, (wrapped in a DisplayCell)
Element_.instances.core_00_left // The Element_ instance "core_00_left" ('div') (wrapped in a DisplayCell)
Element_.instances.core_00_right // The Element_ instance "core_00_right" ('div') (wrapped in a DisplayCell)
DisplayCell.instances.core_00 // This is the DisplayCell that wraps the Handler,
DisplayCell.instances.core_00_h // This is the DisplayCell that wraps the DisplayGroup,
DisplayCell.instances.core_00_left // This is the DisplayCell that wraps the Element_ labeled left
DisplayCell.instances.core_00_right // This is the DisplayCell that wraps the Element_ labeled right
Margins can be set on ANY DisplayCell. The following shows how to apply Margins.