InnovaStudio
Documentation
ContentBox.js is a web page designer. It uses ContentBuilder.js as its HTML editor with added features for page designing. You can use it to create your own CMS or online site builder.
2
…………………………………………………………………………………. 3
…………………….. 5
..……………………………….……………………………………………………………………… 7
.……………………………………… 9
..…………………………………………………………………………….. 10
……..……..……………………. 11
…………………..………………………………….………………………………………… 21
………………………………………………………………………… 24
………………………………..………..………………………………………… 27
…………………………………………………………………………………. 28
…..……………….. 29
..……… 31
…………………………..……………………………………… 34
..…..………………………………………………….. 35
.……..……………………. 37
..……..…………………………………………………………………………… 38
………………………………………………………………………………………………… 38
.………..………………………………………… 39
.
…..………………………………………… 42
Include the ContentBuilder css files:
<link href="assets/minimalist-blocks/content.css" rel="stylesheet" type="text/css" /> <!-- for snippets --> <link href="contentbuilder/contentbuilder.css" rel="stylesheet" type="text/css" />
and the main ContentBox css file:
<link href="contentbox/contentbox.css" rel="stylesheet" type="text/css" />
Step 1
CSS
3
Install as Web Library
<script src="contentbox/contentbox.min.js" type="text/javascript"></script>
Then import into your project:
import ContentBox from '@innovastudio/contentbox';
Step 2
JS
Or Install with NPM
npm install @innovastudio/contentbox
4
<link href="box/box-flex.css" rel="stylesheet" type="text/css" />
For viewing content, additional includes are also needed.
On the head section:
Before the end of the body tag:
<script src="box/box-flex.js" type="text/javascript">
5
Asset files (eg. template or snippet files) are also needed to run the ContentBox. They are located in the assets folder in the package.
Note: location of asset related files are flexible and can be configured. For example, you can move the asset files on different server (eg. CDN server).
<link href="box/box.css" rel="stylesheet" type="text/css" />
Note: this is the same as in the previous version.
On the head section:
Before the end of the body tag:
<script src="path-to/jquery.min.js"> /* for running the slider */ <script src="box/box.js" type="text/javascript">
The JQuery include is needed here because the previous version of ContentBox includes predesigned sliders (using Slick slider) that require JQuery to run. If you are not using the slider in your content, then you do not need JQuery include and you can change the box.css & box.js includes with the box-flex.css & box-flex.js which exclude the JQuery dependency.
6
<div class="is-wrapper"> </div>
const builder = new ContentBox({ wrapper: '.is-wrapper', });
7
To get the edited content:
1. Get the HTML content
let html = builder.html();
2. Get the styles
let mainCss = builder.mainCss(); // Returns the default typography style for the page. let sectionCss = builder.sectionCss(); // Returns the typography styles for specific sections on the page
Then you can do anything with the content, for example, posting it to the server for saving, etc.
In production, the saved HTML content should be rendered with the styles.
8
ContentBox.js is written in pure Javascript (ES6) so you can use it in most situations. Sample use in simple HTML, PHP, React and Vue projects are included.
React and Vue project examples are provided in separate downloads in the user area.
9
To run the HTML example, open using your browser: public/example.html from localhost or from your server.
10
To start building a page, you can click the (+) button on the top left sidebar. This will open a selection of predesigned sections that you can add into your page.
11
12
If you click ALL CATEGORIES, 2 sets of templates will be displayed:
13
These 2 set of templates are located in the folder:
Each folder contains:
The templates are loaded using the following configuration:
14
const builder = new ContentBox({ wrapper: '.is-wrapper', templates: [ { url: 'assets/simplestart/templates.js', path: 'assets/simplestart/', pathReplace: [ ] }, { url: 'assets/quickstart/templates.js', path: 'assets/quickstart/', pathReplace: [ ] }, ], });
Using the templates parameter, you can configure the template file (url), the asset location (path), and optionally, use pathReplace property to replace string found on the template file.
Here is an example of a different assets location:
const builder = new ContentBox({ wrapper: '.is-wrapper', templates: [ { url: 'https://path-to/assets/simplestart/templates.js', path: 'https://path-to/assets/simplestart/', pathReplace: [ ] }, { url: 'https://path-to/assets/quickstart/templates.js', path: 'https://path-to/assets/quickstart/', pathReplace: [ ] }, ], });
const builder = new ContentBox({ wrapper: '.is-wrapper', designUrl1: 'assets/designs/basic.js', designUrl2: 'assets/designs/examples.js', designPath: 'assets/designs/', });
15
In the old ContentBox, you can configure the template location by setting the designUrl1, designUrl2 and designPath parameters. These still work. Note that in the old version, templates are located in assets/designs/ folder.
In case of a different assets location, path adjustment may be needed. Here you can use the designPathReplace parameter.
const builder = new ContentBox({ wrapper: '.is-wrapper', designUrl1: 'https://path-to/assets/designs/basic.js', designUrl2: 'https://path-to/assets/designs/examples.js', designPath: 'https://path-to/assets/designs/', designPathReplace: ['assets/designs/', 'https://path-to/assets/designs/'], // replace the default path to the new location });
In this example, the default location is changed to https://path-to/assets/designs/
With this, you can place all the assets in a separate server or different host (e.g. from a CDN).
16
Let’s see one of the template file, the Simple Start template: assets/simplestart/templates.js.
var data_templates = { name: 'Simple Start', categories: [ { id: 1, name: 'Basic' }, { id: 2, name: 'Slider' }, { id: 3, name: 'Video' }, { id: 4, name: 'Custom' }, ], designs: [ { 'thumbnail': 'preview/simple-01.png', 'category': '1', 'contentCss': 'type-poppins.css', 'contentClass': 'type-poppins', 'html': ` <div class="is-section is-box is-section-100 type-poppins"> ... </div>` }, ... ] }; try { template_list.push(data_templates); } catch(e) { // }
In this JSON format, you can define the template set name, categories, and the template collection (designs).
Ini this set, we have 4 categories:
1. Basic
2. Slider
3. Video
4. Custom
For each section template, you need to specify:
With the same format, you can create your own template set and load it in ContentBox.
17
Let’s the other template file, the Quick Start template: assets/quickstart/templates.js.
var data_templates = { name: 'Quick Start', categories: [ { id: 1, name: 'Header' }, { id: 2, name: 'Article' }, { id: 3, name: 'Photos' }, { id: 4, name: 'Profile' }, { id: 5, name: 'Products, Services' }, { id: 6, name: 'Features' }, { id: 7, name: 'Process' }, { id: 8, name: 'Pricing' }, { id: 9, name: 'Skills' }, { id: 10, name: 'Achievements' }, { id: 11, name: 'Quotes' }, { id: 12, name: 'Partners' }, { id: 13, name: 'As Featured On' }, { id: 14, name: 'Page Not Found' }, { id: 15, name: 'Coming Soon' }, { id: 16, name: 'Help, FAQ' }, { id: 17, name: 'Contact' }, { id: 18, name: 'Footer' }, ], designs: [ ... ] }; try { template_list.push(data_templates); } catch(e) { // }
Ini this set, we have 18 categories, from Header, Article, to Footer.
18
The two template files (assets/simplestart/templates.js and assets/quickstart/templates.js) are loaded by registering them in the templates parameter:
const builder = new ContentBox({ wrapper: '.is-wrapper', templates: [ { url: 'assets/simplestart/templates.js', path: 'assets/simplestart/', pathReplace: [ ] }, { url: 'assets/quickstart/templates.js', path: 'assets/quickstart/', pathReplace: [ ] }, ], });
const builder = new ContentBox({ ... featuredCategories: [ { id: 1, designId: 1, name: 'Basic' }, { id: 2, designId: 1, name: 'Slider' }, { id: 1, designId: 2, name: 'Header' }, { id: 2, designId: 2, name: 'Article' }, { id: 3, designId: 2, name: 'Photos' }, ], });
You can feature certain categories that will be displayed on the front using featuredCategories parameter:
Template loading is asynchronous so it won’t block the initial page loading. In this configuration, we load the simplestart/templates.js set first and then the quickstart/templates.js.
The simplestart set has designId=1 and the quickstart set has designId=2 (according to the load order).
The id refers to the category id.
19
Then choose which category to display on the first open:
const builder = new ContentBox({ ... defaultCategory: { id: 1, designId: 1 }, });
Here we choose the Basic category (id: 1), from the simplestart set (designId: 1).
20
To adjust the template’s thumbnail size, use templateThumbnailSize parameter:
const builder = new ContentBox({ ... templateThumbnailSize: 'small', });
The default is empty string (means dynamic or auto adjust based on the screen size).
For specific size, use: small, medium, or large.
Small
Medium
Large
Snippets are predesigned blocks that you can add or drag & drop into your content.
Snippet selection can be opened from the left sidebar.
21
Snippet files are located in the folder:
assets/minimalist-blocks/
It contains:
You can configure the snippets location by setting the snippetUrl and snippetPath parameters:
const builder = new ContentBox({ wrapper: '.is-wrapper', snippetUrl: 'assets/minimalist-blocks/content.js', // Snippet file snippetPath: 'assets/minimalist-blocks/', // Location of snippets' assets });
22
In case of a different location, path adjustment may be needed. Here you can use the snippetPathReplace parameter.
Example:
const builder = new ContentBox({ wrapper: '.is-wrapper', snippetUrl: 'https://path-to/assets/minimalist-blocks/content.js', // Snippet file snippetPath: 'https://path-to/assets/minimalist-blocks/', // Location of snippets' assets snippetPathReplace: ['assets/', 'https://path-to/assets/'], // replace the default path to the new location });
In this example, the default location is changed to https://path-to/assets/minimalist-blocks/
With this, you can place all the snippet assets in a separate server or different host (e.g. from a CDN).
23
A selection of typography styles is provided for you to choose to format your page. The selection can be opened from the left sidebar.
24
The style can be used to format the entire page or just a specific section of your page.
To apply the typography style to a specific box area, open the Box Settings dialog, select the Text tab and click Change Style.
This will re-open the typography selection and your selection will be applied to the chosen box area only.
25
Typography style files are located in the folder:
assets/styles/
It contains all the css needed and its preview images. You can change its location using the contentStylePath parameter.
const builder = new ContentBox({ wrapper: '.is-wrapper', contentStylePath: 'assets/styles/', });
26
<link href="assets/scripts/glide/css/glide.core.css" rel="stylesheet" type="text/css" /> <link href="assets/scripts/glide/css/glide.theme.css" rel="stylesheet" type="text/css" /> <script src="assets/scripts/glide/glide.js" type="text/javascript">
The new version includes predesigned slider templates (using Glide slider) that require some includes:
To enable the slider:
const builder = new ContentBox({ /*...*/ slider: 'glide' // default: 'slick' (old version slider) });
Values:
27
With the Language file, you can translate the ContentBox.js interface into another language.
The language file is located in:
contentbox/lang/en.js
To enable the language file, you need to add the file before including ContentBox.js:
<script src="contentbox/lang/en.js" type="text/javascript">
Here is the language file content as seen on en.js:
var _txt = new Array(); _txt['Bold'] = 'Bold'; _txt['Italic'] = 'Italic';
You can create your own language file by copying/modifying this file.
28
To add custom buttons on the sidebar, use the addButton method.
Here is an example of adding the Undo & Redo button. For the undo and redo operation, we call the undo() and redo() methods.
builder.addButton({ 'pos': 2, // button position 'title': 'Undo', // title 'html': '<svg class="is-icon-flex" style="width:14px;height:14px;">', // icon 'onClick': ()=>{ builder.undo(); } }); builder.addButton({ 'pos': 3, // button position 'title': 'Redo', // title 'html': '<svg class="is-icon-flex" style="width:14px;height:14px;">', // icon 'onClick': ()=>{ builder.redo(); } });
29
The addButton method has 4 parameters:
builder.addButton({ 'pos': 5, 'title': 'Preview', 'html': '<svg class="is-icon-flex" style="width:16px;height:16px;">', 'onClick': ()=>{ var html = builder.html(); localStorage.setItem('preview-html', html); var mainCss = builder.mainCss(); localStorage.setItem('preview-maincss', mainCss); var sectionCss = builder.sectionCss(); localStorage.setItem('preview-sectioncss', sectionCss); window.open('/preview.html', '_blank').focus(); } });
Here is another example for adding a Preview button. If clicked, the button will open a separate page (preview.html) that we use to preview our edited page as in production.
Here we get the content and its styles using the html(), mainCss(), and sectionCss() methods and save them into the browser’s local storage. The content will then be used in the preview.html for viewing.
30
In the Box Settings, you can specify a box’s cover or background image.
31
However, to quickly upload an image without opening the Box Settings, you can click the box image button. This allows you to browse local images and select an image to upload as a box image cover (background).
32
33
There are 2 methods for uploading cover image:
Form Method
Here we use the coverImageHandler parameter to specify the upload handler for saving images on the server.
const builder = new ContentBox({ wrapper: '.is-wrapper', coverImageHandler: 'savecover.php', });
As examples, you can use the provided handler:
34
AJAX Post Method
Here we use the onUploadCoverImage parameter to specify a custom upload function.
const builder = new ContentBox({ wrapper: '.is-wrapper', onUploadCoverImage: (e) => { uploadFile(e, (response)=>{ const uploadedImageUrl = response.url; // get saved image url builder.boxImage(uploadedImageUrl); // change cover image }); }, }); function uploadFile(e, callback) { const selectedFile = e.target.files[0]; const formData = new FormData(); formData.append('file', selectedFile); fetch('/upload', { method: 'POST', body: formData, }) .then(response=>response.json()) .then(response=>{ console.log(response) if(callback) callback(response); }); }
The example above uses the boxImage(url) method to apply the image url as a background cover.
35
In the example, the image is posted to an endpoint: /upload
If you’re using Node.js, you can implement the endpoint to save the image using:
const express = require('express'); const fs = require('fs'); const app = express(); const path = require('path'); const cors = require('cors'); const serveStatic = require('serve-static'); const formidable = require('formidable-serverless'); const sharp = require('sharp'); //Specify url path var $path = __dirname + '/public/uploads/'; // Physical path var $urlpath = 'uploads/'; // URL path app.use(cors()); app.use(express.urlencoded({ extended: true })); app.use(express.json({ limit: '50mb' })); app.use(serveStatic(path.join(__dirname, '/public'))); app.post('/upload', (req, res) => { const form = new formidable.IncomingForm(); form.parse(req, async (err, fields, files) => { if (err) return res.status(500).json({ ok:true, status: 500, error: 'Something went wrong.' }); let extension = path.extname(files.file.name).toLowerCase(); if(extension !== '.jpeg' && extension !== '.jpg' && extension !== '.png' && extension !== '.gif' && extension !== '.webp' && extension !== '.webm' && extension !== '.mp4') {
36
res.status(500).json({ ok:true, status: 500, error: 'File type not allowed.' }); return; } const file = fs.readFileSync(files.file.path); let imageFile = file; if(extension === '.jpeg' || extension === '.jpg') { imageFile = await sharp(files.file.path).resize(1600, 1600, { fit: sharp.fit.inside, withoutEnlargement: true, }) .jpeg({ quality: 80, progressive: true, force: false }) .toBuffer(); } fs.writeFile($path + files.file.name, imageFile, async (err)=>{ if (err) { res.status(500).json({ ok:true, status: 500, error: 'Something went wrong.' }); return } res.status(200).json({ ok:true, status: 200, url: $urlpath + files.file.name }); }); }); });
Content consists of HTML and its styles (e.g. typography styles/css includes). As explained previously, you get the edited content using the following methods:
1. To get the HTML
let html = builder.html();
2. To get the styles
let mainCss = builder.mainCss(); // Returns the default typography style for the page. let sectionCss = builder.sectionCss(); // Returns the typography styles for specific sections on the page
You can save the HTML and its styles above into a database. And when you need to load the content back for editing, use the loadHtml() and loadStyles methods.
builder.loadHtml(html); builder.loadStyles(mainCss, sectionCss);
37
To undo:
builder.undo();
To redo:
builder.redo();
38
To destroy the ContentBox:
builder.destroy();
ContentBox.js uses ContentBuilder.js as its HTML editor. So most of the ContentBuilder.js options/parameters can be accessed through the ContentBox.js object.
For example, to specify a custom file browser (or Asset Manager):
const builder = new ContentBox({ wrapper: '.is-wrapper', imageSelect: 'assets.html', fileSelect: 'assets.html', videoSelect: 'assets.html', });
39
const builder = new ContentBox({ wrapper: '.is-wrapper', onMediaUpload: (e)=>{ uploadFile(e, (response)=>{ ... }); }, onVideoUpload: (e)=>{ uploadFile(e, (response)=>{ ... }); }, });
And to specify custom upload functions:
40
The editing toolbar from ContentBuilder.js has a Preview button to view the page result in a modal.
In ContentBox, you can define the preview URL using previewURL parameter. The default value is ‘preview.html’.
const builder = new ContentBox({ wrapper: '.is-wrapper', previewURL: 'preview.html' });
The preview.html is used to view the edited page result (without the builder). The file is located in public folder.
More configuration options of ContentBuilder.js can be found in the ContentBuilder.js documentation:
https://demo.innovastudio.com/docs/ContentBuilder.pdf
41
We will look on how to add a button on the sidebar that opens a custom panel. You can create your own custom panel by creating a simple html page. In this example, we will have a panel with multiple buttons that can add a custom content/section into your page. You can try the example in the package by opening: public/example-custom.html. (from localhost or from your server).
42
Click the buttons to try adding a new custom content/section into the page.
43
Let’s look at the code.
To add a button on the sidebar, use addButton() method (this method has been explained in the previous chapter: Adding Custom Buttons on the Sidebar):
The src property is set with your custom html page, mypanel.html. This simple html page contains the buttons for adding content. Each button simply calls the addSection() method.
The addSection() method accepts two parameters:
parent.contentbox.addSection(html, css)
mypanel.html
builder.addButton({ 'pos': 0, 'title': 'Products', 'src': 'mypanel.html', 'html': '<svg style="width:17px;height:17px;" viewBox="0 0 2048 2048" xmlns="http://www.w3.org/2000/svg">' + // ... '</svg>', 'class': 'sidebar-sections' });
example-custom.html
Example:
44
Here we choose type-rufina-oxygen.css for the typography css. Then we added type-rufina-oxygen class in the div.is-section element. This will format the content with the Rufina & Oxygen fonts.
<div class="is-section is-box is-section-100 type-rufina-oxygen"> ... </div>
Use the same format as in the example if you want to create your own content. Please leave the other classes in the example as they are needed by ContentBox to format the content.
mypanel.html
parent.contentbox.addSection(` <div class="is-section is-box is-section-100 type-rufina-oxygen"> <div class="is-boxes"> <div class="is-box-centered"> <div class="is-container v2 is-content-960 leading-13 size-17"> <div class="row"> <div class="column full"> <h1 class="text-center leading-09 size-92">Product One</h1> </div> </div> </div> </div> </div> </div> `, 'type-rufina-oxygen.css');
To make the content protected (non editable), please add protected class on the div.is-section. and do not use is-container class. The is-container class is used for text content inside the section and it is always editable.
45
If you need to add custom Javascript, please use the following format:
<div class="is-section is-box is-section-100 type-rufina-oxygen protected"> <div class="is-overlay"> <div class="is-overlay-content" data-module="code" data-module-desc="My Code" data-html="[... encoded custom script here ...]"> </div> </div> </div>
mypanel.html
<div class="is-section is-box is-section-100 type-rufina-oxygen protected"> ... </div>
mypanel.html
45
For the complete code, please open the mypanel.html with your code editor.
Here is an example:
mypanel.html
parent.contentbox.addSection(` <div class="is-section is-box is-section-100 is-light-text type-rufina-oxygen protected"> <div class="is-overlay"> <div class="is-overlay-content" data-module="code" data-module-desc="Custom HTML or Javascript " data-html="${encodeURIComponent(` <!-- custom script here --> `)}"> </div> </div> </div> `, 'type-rufina-oxygen.css');
© 2023 InnovaStudio