Frames
Frames are designed to display any content, allowing them to be embedded into any other interface components, including themselves. There can be empty frames, but usually they are tied to a Client object, meaning they load the Class/Client object profile and its fields, as well as the data of the specified record.
The developer can implement any layout but use templating to insert loaded fields, either with an editor or just the value. When inserting values with an editor, the display will be performed taking into account the editor settings for that field in the profile, as well as the editability settings. For a non-editable field, the corresponding editor will not be connected, but all other field attributes will be (e.g., tooltip).
Basically, bootstrap layout is usually used (seems like v3). Но you can write however you want.
In addition to outputting Class/CO fields, tables or other frames can also be embedded, as mentioned in the table description.
To embed a table, you need to output a div element with a certain class and data attributes; then, when the form/frame loads, the corresponding table will be loaded into this div. See the description “Tables. Inside a form or frame (in the layout)”.
<div data-tbls="CLASS_NAME.TABLE_CO_NAME" class="fn-child-tbl-holder marTop10"></div>
To embed a frame, you also need to output a div with a certain class and data attribute.
<div data-frame="CLASS_NAME.FRAME_CO_NAME" data-ids="{+{id}+}" data-new_if_not_id="true" class="fn-child-frm-holder"></div>
data-frame. Specify the class name and CO separated by a dot. CO can be omitted.
class. Must contain the class “fn-child-frm-holder”
data-ids. If “{+{id}+}” is specified, the ID of the record from the form or frame where it is inserted will be substituted.
data-new_if_not_id. Indicates that if the id is not passed, the record opens for creation (like a new row in a table). The value will be true only if the string is “true”; in all other cases, it will be false.
Other data attributes can be specified; they will be passed as params when creating the frame
How to Create
Creating a Profile
As mentioned above, you don’t have to create a separate profile for a table but can use the class profile.
If you need special profile settings different from the class profile settings, create a Client object as described in the section “Creating Client Objects”.
Layout and JS
Frame files must be created in the codebase and placed in public_src/html/frames. The directory name is the name of the frame, and inside there must be html and js files with the same name. Optionally, a css file can be placed. Usually, this name matches the name of the client object or has the form “frame_<class_name>”.
You can write any layout, as mentioned above.
In the js file, you can also organize the code however you like, but there are a few useful things to know.
All code is wrapped in a self-invoking function (function(){})().
To get a frame instance, write at the very beginning (already present in the example):
var frameID = MB.Frames.justLoadedId;
var frameInstance = MB.Frames.getFrame('frame_example', frameID);
Important! The first string parameter in the getFrame method must be replaced with the name of your frame.
Next, by analogy with tables, you can use this instance. You can get the profile settings of the Class/CO and its fields, loaded data, states (e.g., modified fields), and parent if present. You can also define functions that are called after certain frame events, such as afterLoad, afterReload, afterAdd.
Often, a frameEditor object is used to group all tasks of a specific frame, which has fields for storing state and various methods, such as load or setHandlers. This is just an example, and the code can be organized differently (more modernly) if there is any need for it.
See the example and use it as a reference for copy-pasting: C:\NET\CCS.ARLAN_SALON\public_src\html\frames\frame_example
Save Button
In the layout, you can place a save button and give it any styles. Button example:
<div class="save-traits mw-save-frame"><i class="fa fa-save"></i> Save</div>
The determining factor is the class mw-save-frame
If a button is not specified, the save function (and button highlighting when there are changes) is automatically passed to the parent, which in turn can do the same, up to the form (if it exists among the parents).
In addition, you can explicitly specify to whom to delegate the save via the saveBtnBy parameter (frame or form instance).
The parameter can be set in the frame’s code file:
frameInstance.saveBtnBy = frameInstance.parent;
// Or it can be any other frame, not necessarily among the parents.
If you set frameInstance.saveBtnBy, you can still keep the frame’s own button via layout. Then both will work.
Placement in the Interface
In the Main Menu
You need to create a menu item of type “Frame” in the menu editor (System->Menu editor), specify the Parent element (in which item to place it), select the Class, and optionally a Client object (if a client object is selected, it must be based on the same class as the selected class).
Such an element will appear in the menu, and when selected, the specified frame will be opened in the main content area.
No code writing will be required.
Inside a Form or Frame (in the layout)
In the layout of a form or frame, you can specify a special div element as described in the description of frames, see above.
By Code, into Any Container
To create a frame by code, you need to call MB.Frames.createFrame, passing parameters and a callback function. If this is done inside some other frame or form, then when it is updated or closed, the created child frame must also be destroyed.
Also, a frame can be created, for example, when switching a selected item in a list or a selected node in a tree. Below, let’s consider the example that exists in frame_example.js. It creates the corresponding frame when a node is clicked, having previously destroyed the old one (if present).
holder.on('select_node.jstree', function (e,a) {
var frame_class = a.node.original.item._content_class;
var frame_co = a.node.original.item._content_co;
const obj = {
container:frameEditor.frame_content,
class:frame_class,
client_object:frame_co,
parent:frameInstance,
ids:[a.node.original.item._id],
name:frame_co
}
if (frameEditor.current_frame && typeof frameEditor.current_frame.remove ==='function') {
frameEditor.current_frame.remove({remove_from_parent: true});
}
MB.Frames.createFrame(obj, (err, frame)=>{
frameEditor.current_frame = frame;
if (err) return console.error('Failed to create frame',err);
});
});
Here we take the necessary class and client object from the menu item/node that was clicked; if there is an old frame in frameEditor.current_frame, we destroy it, then create a new one and save it in frameEditor.current_frame.
Fields are similar to the table. The ids field raises questions, but it just takes the zeroth element. The name can basically be anything; parent might not be specified if, for example, you are creating a frame in a modal window or just in the main content area.