You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3139 lines
79 KiB

/*
Copyright 2017 Ziadin Givan
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
https://github.com/givanz/VvvebJs
*/
// Simple JavaScript Templating
// John Resig - https://johnresig.com/ - MIT Licensed
(function(){
var cache = {};
var startTag = "{%";
var endTag = "%}";
var re1 = new RegExp(`((^|${endTag})[^\t]*)'`,"g");
var re2 = new RegExp(`\t=(.*?)${endTag}`,"g");
this.tmpl = function tmpl(str, data){
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = /^[-a-zA-Z0-9]+$/.test(str) ?
cache[str] = cache[str] ||
tmpl(document.getElementById(str).innerHTML) :
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +
// Introduce the data as local variables using with(){}
"with(obj){p.push('" +
// Convert the template into pure JavaScript
str
.replace(/[\r\t\n]/g, " ")
.split(startTag).join("\t")
.replace(re1, "$1\r")
.replace(re2, "',$1,'")
.split("\t").join("');")
.split(endTag).join("p.push('")
.split("\r").join("\\'")
+ "');}return p.join('');");
// Provide some basic currying to the user
return data ? fn( data ) : fn;
};
})();
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
function isElement(obj){
return (typeof obj==="object") &&
(obj.nodeType===1) && (typeof obj.style === "object") &&
(typeof obj.ownerDocument ==="object")/* && obj.tagName != "BODY"*/;
}
if (Vvveb === undefined) var Vvveb = {};
Vvveb.defaultComponent = "_base";
Vvveb.preservePropertySections = true;
//icon = use component icon when dragging | html = use component html to create draggable element
Vvveb.dragIcon = 'icon';
//if empty the html of the component is used to view dropping in real time but for large elements it can jump around for this you can set a html placeholder with this option
Vvveb.dragHtml = '<div style="background:limegreen;;width:100%;height:3px;border:1px solid limegreen;box-shadow:0px 0px 2px 1px rgba(0,0,0,0.14);"></div>';
Vvveb.baseUrl = document.currentScript?document.currentScript.src.replace(/[^\/]*?\.js$/,''):'';
Vvveb.imgBaseUrl = Vvveb.baseUrl;
Vvveb.ComponentsGroup = {};
Vvveb.SectionsGroup = {};
Vvveb.BlocksGroup = {};
Vvveb.Components = {
_components: {},
_nodesLookup: {},
_attributesLookup: {},
_classesLookup: {},
_classesRegexLookup: {},
componentPropertiesElement: "#right-panel .component-properties",
componentPropertiesDefaultSection: "content",
get: function(type) {
return this._components[type];
},
updateProperty: function(type, key, value) {
let properties = this._components[type]["properties"];
for (property in properties) {
if (key == properties[property]["key"]) {
return this._components[type]["properties"][property] =
Object.assign(properties[property], value);
}
}
},
getProperty: function(type, key) {
let properties = this._components[type]["properties"];
for (property in properties) {
if (key == properties[property]["key"]) {
return properties[property];
}
}
},
add: function(type, data) {
data.type = type;
this._components[type] = data;
if (data.nodes)
{
for (var i in data.nodes)
{
this._nodesLookup[ data.nodes[i] ] = data;
}
}
if (data.attributes)
{
if (data.attributes.constructor === Array)
{
for (var i in data.attributes)
{
this._attributesLookup[ data.attributes[i] ] = data;
}
} else
{
for (var i in data.attributes)
{
if (typeof this._attributesLookup[i] === 'undefined')
{
this._attributesLookup[i] = {};
}
if (typeof this._attributesLookup[i][ data.attributes[i] ] === 'undefined')
{
this._attributesLookup[i][ data.attributes[i] ] = {};
}
this._attributesLookup[i][ data.attributes[i] ] = data;
}
}
}
if (data.classes)
{
for (var i in data.classes)
{
this._classesLookup[ data.classes[i] ] = data;
}
}
if (data.classesRegex)
{
for (var i in data.classesRegex)
{
this._classesRegexLookup[ data.classesRegex[i] ] = data;
}
}
},
extend: function(inheritType, type, data) {
var newData = data;
if (inheritData = this._components[inheritType])
{
newData = $.extend(true,{}, inheritData, data);
newData.properties = $.merge( $.merge([], inheritData.properties?inheritData.properties:[]), data.properties?data.properties:[]);
}
//sort by order
newData.properties.sort(function (a,b)
{
if (typeof a.sort === "undefined") a.sort = 0;
if (typeof b.sort === "undefined") b.sort = 0;
if (a.sort < b.sort)
return -1;
if (a.sort > b.sort)
return 1;
return 0;
});
/*
var output = array.reduce(function(o, cur) {
// Get the index of the key-value pair.
var occurs = o.reduce(function(n, item, i) {
return (item.key === cur.key) ? i : n;
}, -1);
// If the name is found,
if (occurs >= 0) {
// append the current value to its list of values.
o[occurs].value = o[occurs].value.concat(cur.value);
// Otherwise,
} else {
// add the current item to o (but make sure the value is an array).
var obj = {name: cur.key, value: [cur.value]};
o = o.concat([obj]);
}
return o;
}, newData.properties);
*/
this.add(type, newData);
},
matchNode: function(node) {
var component = {};
if (!node || !node.tagName) return false;
if (node.attributes && node.attributes.length)
{
//search for attributes
for (var i in node.attributes)
{
if (node.attributes[i])
{
attr = node.attributes[i].name;
value = node.attributes[i].value;
if (attr in this._attributesLookup)
{
component = this._attributesLookup[ attr ];
//currently we check that is not a component by looking at name attribute
//if we have a collection of objects it means that attribute value must be checked
if (typeof component["name"] === "undefined")
{
if (value in component)
{
return component[value];
}
} else
return component;
}
}
}
for (var i in node.attributes)
{
attr = node.attributes[i].name;
value = node.attributes[i].value;
//check for node classes
if (attr == "class")
{
classes = value.split(" ");
for (j in classes)
{
if (classes[j] in this._classesLookup)
return this._classesLookup[ classes[j] ];
}
for (regex in this._classesRegexLookup)
{
regexObj = new RegExp(regex);
if (regexObj.exec(value))
{
return this._classesRegexLookup[ regex ];
}
}
}
}
}
tagName = node.tagName.toLowerCase();
if (tagName in this._nodesLookup) return this._nodesLookup[ tagName ];
return false;
//return false;
},
render: function(type, panel = false) {
var component = this._components[type];
if (panel) {
componentsPanel = panel;
} else {
panel = this.componentPropertiesElement;
}
var componentsPanel = $(panel);
var defaultSection = this.componentPropertiesDefaultSection;
var componentsPanelSections = {};
$(panel + " .tab-pane").each(function ()
{
var sectionName = this.dataset.section;
componentsPanelSections[sectionName] = $(this);
$('.section[data-section!="default"]', this).remove();
$('label[for!="header_default"]', this).remove();
$('input[id!="header_default"]', this).remove();
});
var section = componentsPanelSections[defaultSection].find('.section[data-section="default"]');
if (!(Vvveb.preservePropertySections && section.length))
{
componentsPanelSections[defaultSection].html('').append(tmpl("vvveb-input-sectioninput", {key:"default", header:component.name}));
section = componentsPanelSections[defaultSection].find(".section");
}
componentsPanelSections[defaultSection].find('[data-header="default"] span').html(component.name);
section.html("")
if (component.beforeInit) component.beforeInit(Vvveb.Builder.selectedEl.get(0));
var element;
var fn = function(component, property) {
return property.input.on('propertyChange', function (event, value, input) {
var element = Vvveb.Builder.selectedEl;
if (property.child) element = element.find(property.child);
if (property.parent) element = element.parent(property.parent);
if (property.onChange)
{
element = property.onChange(element, value, input, component);
}/* else */
if (property.htmlAttr)
{
oldValue = element.attr(property.htmlAttr);
if (property.htmlAttr == "class" && property.validValues)
{
element.removeClass(property.validValues.join(" "));
element = element.addClass(value);
}
else if (property.htmlAttr == "style")
{
oldStyle = $("#vvvebjs-styles", window.FrameDocument).html();
element = Vvveb.StyleManager.setStyle(element, property.key, value);
}
else if (property.htmlAttr == "innerHTML")
{
element = Vvveb.ContentManager.setHtml(element, value);
}
else
{
//if value is empty then remove attribute useful for attributes without values like disabled
if (value)
{
element = element.attr(property.htmlAttr, value);
} else
{
element = element.removeAttr(property.htmlAttr);
}
}
if (property.htmlAttr == "style") {
mutation = {
type: 'style',
target: element.get(0),
attributeName: property.htmlAttr,
oldValue: oldStyle,
newValue: $("#vvvebjs-styles", window.FrameDocument).html()};
Vvveb.Undo.addMutation(mutation);
} else {
Vvveb.Undo.addMutation(
{type: 'attributes',
target: element.get(0),
attributeName: property.htmlAttr,
oldValue: oldValue,
newValue: element.attr(property.htmlAttr)});
}
}
if (component.onChange)
{
element = component.onChange(element, property, value, input);
}
if (!property.child || !property.parent) Vvveb.Builder.selectNode(element);
return element;
});
};
var nodeElement = Vvveb.Builder.selectedEl;
for (var i in component.properties)
{
var property = component.properties[i];
var element = nodeElement;
if (property.beforeInit) property.beforeInit(element.get(0))
if (property.child) element = element.find(property.child);
if (property.data) {
property.data["key"] = property.key;
} else
{
property.data = {"key" : property.key};
}
if (typeof property.group === 'undefined') property.group = null;
property.input = property.inputtype.init(property.data);
let value;
if (property.init)
{
property.inputtype.setValue(property.init(element.get(0)));
} else if (property.htmlAttr)
{
if (property.htmlAttr == "style")
{
//value = element.css(property.key);//jquery css returns computed style
value = Vvveb.StyleManager.getStyle(element, property.key);//getStyle returns declared style
} else
if (property.htmlAttr == "innerHTML")
{
value = Vvveb.ContentManager.getHtml(element);
} else
{
value = element.prop(property.htmlAttr);
if (!value && property.key=="src") {
value = element.prevObject.prop(property.htmlAttr);
}
}
//if attribute is class check if one of valid values is included as class to set the select
if (value && property.htmlAttr == "class" && property.validValues)
{
value = value.split(" ").filter(function(el) {
return property.validValues.indexOf(el) != -1
});
}
if (!value && property.defaultValue) {
value = property.defaultValue;
}
property.inputtype.setValue(value);
} else {
if (!value && property.defaultValue) {
value = property.defaultValue;
}
property.inputtype.setValue(value);
}
fn(component, property);
var propertySection = defaultSection;
if (property.section)
{
propertySection = property.section;
}
if (property.inputtype == SectionInput)
{
section = componentsPanelSections[propertySection].find('.section[data-section="' + property.key + '"]');
if (Vvveb.preservePropertySections && section.length)
{
section.html("");
} else
{
componentsPanelSections[propertySection].append(property.input);
section = componentsPanelSections[propertySection].find('.section[data-section="' + property.key + '"]');
}
}
else
{
var row = $(tmpl('vvveb-property', property));
row.find('.input').append(property.input);
section.append(row);
}
if (property.inputtype.afterInit)
{
property.inputtype.afterInit(property.input);
}
if (property.afterInit)
{
property.afterInit(element.get(0), property.input);
}
}
if (component.init) component.init(Vvveb.Builder.selectedEl.get(0));
}
};
Vvveb.Blocks = {
_blocks: {},
get: function(type) {
return this._blocks[type];
},
add: function(type, data) {
data.type = type;
this._blocks[type] = data;
},
};
Vvveb.Sections = {
_sections: {},
get: function(type) {
return this._sections[type];
},
add: function(type, data) {
data.type = type;
this._sections[type] = data;
},
};
Vvveb.WysiwygEditor = {
isActive: false,
oldValue: '',
doc:false,
editorSetStyle: function (tag, style = {}, toggle = false) {
let iframeWindow = Vvveb.Builder.iframe.contentWindow;
let selection = iframeWindow.getSelection();
let element = this.element;
let range;
if (!tag) {
tag = "span";
}
if (selection.rangeCount > 0) {
//check if the whole text is inside an existing node to use the node directly
if ((selection.baseNode && selection.baseNode.nextSibling == null && selection.baseNode.previousSibling == null
&& selection.anchorOffset == 0 && selection.focusOffset == selection.baseNode.length)
|| (selection.anchorOffset == selection.focusOffset)) {
element = selection.baseNode.parentNode;
} else {
element = document.createElement(tag);
range = selection.getRangeAt(0);
range.surroundContents(element);
range.selectNodeContents(element.childNodes[0], 0);
}
}
if (element && style) {
for (name in style) {
if ( !style[name] ||
(toggle && element.style.getPropertyValue(name))) {
element.style.removeProperty(name);
} else {
element.style.setProperty(name, style[name]);
}
}
}
//if edited text is an empty span remove the span
if (element.tagName == "SPAN" && element.style.length == 0 && element.attributes.length <= 1) {
let textNode = iframeWindow.document.createTextNode(element.innerText);
element.replaceWith(textNode);
element = textNode;
range = iframeWindow.document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
return element;
},
init: function(doc) {
this.doc = doc;
let self = this;
$("#bold-btn").on("click", function (e) {
//doc.execCommand('bold',false,null);
//self.editorSetStyle("b", {"font-weight" : "bold"}, true);
self.editorSetStyle(false, {"font-weight" : "bold"}, true);
e.preventDefault();
return false;
});
$("#italic-btn").on("click", function (e) {
//doc.execCommand('italic',false,null);
//self.editorSetStyle("i", {"font-style" : "italic"}, true);
self.editorSetStyle(false, {"font-style" : "italic"}, true);
e.preventDefault();
return false;
});
$("#underline-btn").on("click", function (e) {
//doc.execCommand('underline',false,null);
//self.editorSetStyle("u", {"text-decoration" : "underline"}, true);
self.editorSetStyle(false, {"text-decoration" : "underline"}, true);
e.preventDefault();
return false;
});
$("#strike-btn").on("click", function (e) {
//doc.execCommand('strikeThrough',false,null);
//self.editorSetStyle("strike", {"text-decoration" : "line-through"}, true);
self.editorSetStyle(false, {"text-decoration" : "line-through"}, true);
e.preventDefault();
return false;
});
$("#link-btn").on("click", function (e) {
//doc.execCommand('createLink',false,"#");
self.editorSetStyle("a");
e.preventDefault();
return false;
});
$("#fore-color").on("change", function (e) {
//doc.execCommand('foreColor',false,this.value);
self.editorSetStyle(false, {"color" : this.value});
e.preventDefault();
return false;
});
$("#back-color").on("change", function (e) {
//doc.execCommand('hiliteColor',false,this.value);
self.editorSetStyle(false, {"background-color" : this.value});
e.preventDefault();
return false;
});
$("#font-size").on("change", function (e) {
//doc.execCommand('fontSize',false,this.value);
self.editorSetStyle(false, {"font-size" : this.value});
e.preventDefault();
return false;
});
let sizes = "<option value=''>Default</option>";
for (i = 1;i <= 128; i++) {
sizes += "<option value='"+ i +"px'>"+ i +"</option>";
}
$("#font-size").html(sizes);
$("#font-family").on("change", function (e) {
let option = this.options[this.selectedIndex];
let element = self.editorSetStyle(false, {"font-family" : this.value});
Vvveb.FontsManager.addFont(option.dataset.provider, this.value, element);
//doc.execCommand('fontName',false,this.value);
e.preventDefault();
return false;
});
$("#justify-btn a").on("click", function (e) {
//var command = "justify" + this.dataset.value;
//doc.execCommand(command,false,"#");
self.editorSetStyle(false, {"text-align" : this.dataset.value});
e.preventDefault();
return false;
});
},
undo: function(element) {
this.doc.execCommand('undo',false,null);
},
redo: function(element) {
this.doc.execCommand('redo',false,null);
},
edit: function(element) {
element.attr({'contenteditable':true, 'spellcheckker':false});
$("#wysiwyg-editor").show();
this.element = element;
this.isActive = true;
this.oldValue = element.html();
$("#font-familly").val(getComputedStyle(element[0])['font-family']);
},
destroy: function(element) {
element.removeAttr('contenteditable spellcheckker');
$("#wysiwyg-editor").hide();
this.isActive = false;
node = this.element.get(0);
Vvveb.Undo.addMutation({type:'characterData',
target: node,
oldValue: this.oldValue,
newValue: node.innerHTML});
}
}
Vvveb.Builder = {
component : {},
dragMoveMutation : false,
isPreview : false,
runJsOnSetHtml : false,
designerMode : false,
highlightEnabled : false,
selectPadding: 0,
leftPanelWidth: 275,
ignoreClasses: ["clearfix"],
init: function(url, callback) {
var self = this;
self.loadControlGroups();
self.loadBlockGroups();
self.loadSectionGroups();
self.selectedEl = null;
self.highlightEl = null;
self.initCallback = callback;
self.documentFrame = $("#iframe-wrapper > iframe");
self.canvas = $("#canvas");
self._loadIframe(url);
self._initDragdrop();
self._initBox();
self.dragElement = null;
self.highlightEnabled = true;
self.leftPanelWidth = $("#left-panel").width();
self.adjustListsHeight();
},
/* controls */
loadControlGroups : function() {
var componentsList = $(".components-list");
componentsList.empty();
var item = {}, component = {};
var count = 0;
componentsList.each(function ()
{
var list = $(this);
var type = this.dataset.type;
count ++;
for (group in Vvveb.ComponentsGroup)
{
list.append(
`<li class="header" data-section="${group}" data-search="">
<label class="header" for="${type}_comphead_${group}${count}">
${group}<div class="header-arrow"></div>
</label>
<input class="header_check" type="checkbox" checked="true" id="${type}_comphead_${group}${count}">
<ol></ol>
</li>`);
//list.append('<li class="header clearfix" data-section="' + group + '" data-search=""><label class="header" for="' + type + '_comphead_' + group + count + '">' + group + ' <div class="header-arrow"></div>\
// </label><input class="header_check" type="checkbox" checked="true" id="' + type + '_comphead_' + group + count + '"> <ol></ol></li>');
var componentsSubList = list.find('li[data-section="' + group + '"] ol');
components = Vvveb.ComponentsGroup[ group ];
for (i in components)
{
componentType = components[i];
component = Vvveb.Components.get(componentType);
if (component)
{
item = $(`<li data-section="${group}" data-drag-type="component" data-type="${componentType}" data-search="${component.name.toLowerCase()}">
<a href="#">${component.name}</a>
</li>`);
//item = $('<li data-section="' + group + '" data-drag-type=component data-type="' + componentType + '" data-search="' + component.name.toLowerCase() + '"><a href="#">' + component.name + "</a></li>");
if (component.image) {
item.css({
backgroundImage: "url(" + Vvveb.imgBaseUrl + component.image + ")",
backgroundRepeat: "no-repeat"
})
}
componentsSubList.append(item)
}
}
}
});
},
loadSectionGroups : function() {
var sectionsList = $(".sections-list");
sectionsList.empty();
var item = {};
sectionsList.each(function ()
{
var list = $(this);
var type = this.dataset.type;
for (group in Vvveb.SectionsGroup)
{
list.append(
`<li class="header" data-section="${group}" data-search="">
<label class="header" for="${type}_sectionhead_${group}">
${group}<div class="header-arrow"></div>
</label>
<input class="header_check" type="checkbox" checked="true" id="${type}_sectionhead_${group}">
<ol></ol>
</li>`);
var sectionsSubList = list.find('li[data-section="' + group + '"] ol');
sections = Vvveb.SectionsGroup[ group ];
for (i in sections)
{
sectionType = sections[i];
section = Vvveb.Sections.get(sectionType);
if (section)
{
item = $(`<li data-section="${group}" data-type="${sectionType}" data-search="${section.name.toLowerCase()}">
<a class="name" href="#">${section.name}</a>
<a class="add-section-btn" href="" title="Add section"><i class="la la-plus"></i></a>
<img class="preview" src="" loading="lazy">
</li>`);
if (section.image) {
var image = ((section.image.indexOf('/') == -1) ? Vvveb.imgBaseUrl:'') + section.image;
item.css({
//backgroundImage: "url(" + image + ")",
backgroundRepeat: "no-repeat"
}).find("img").attr("src", image);
}
sectionsSubList.append(item)
}
}
}
});
},
loadBlockGroups : function() {
var blocksList = $(".blocks-list");
blocksList.empty();
var item = {};
blocksList.each(function ()
{
var list = $(this);
var type = this.dataset.type;
for (group in Vvveb.BlocksGroup)
{
list.append(
`<li class="header" data-section="${group}" data-search="">
<label class="header" for="${type}_blockhead_${group}">
${group}<div class="header-arrow"></div>
</label>
<input class="header_check" type="checkbox" checked="true" id="${type}_blockhead_${group}">
<ol></ol>
</li>`);
var blocksSubList = list.find('li[data-section="' + group + '"] ol');
blocks = Vvveb.BlocksGroup[ group ];
for (i in blocks)
{
blockType = blocks[i];
block = Vvveb.Blocks.get(blockType);
if (block)
{
item = $(`<li data-section="${group}" data-drag-type="block" data-type="${blockType}" data-search="${block.name.toLowerCase()}">
<a class="name" href="#">${block.name}</a>
<img class="preview" src="" loading="lazy">
</li>`);
if (block.image) {
var image = ((block.image.indexOf('/') == -1) ? Vvveb.imgBaseUrl:'') + block.image;
item.css({
backgroundImage: "url(" + image + ")",
backgroundRepeat: "no-repeat"
}).find("img").attr("src", image);
}
blocksSubList.append(item)
}
}
}
});
},
adjustListsHeight: function () {
let lists = $(".drag-elements-sidepane > div:not(.block-preview)");
let properties =$(".component-properties >.tab-content");
let wHeight = $(window).height();
function adjust(elements) {
let maxOffset = 0;
elements.each(function (i,e) {
maxOffset = Math.max(maxOffset, e.getBoundingClientRect()["top"]);
});
elements.each(function (i,e) {
e.style.height = (wHeight - maxOffset) + "px";
});
}
adjust(lists);
adjust(properties);
},
loadUrl : function(url, callback) {
var self = this;
$("#select-box").hide();
self.initCallback = callback;
if (Vvveb.Builder.iframe.src != url) Vvveb.Builder.iframe.src = url;
},
/* iframe */
_loadIframe : function(url) {
var self = this;
self.iframe = this.documentFrame.get(0);
self.iframe.src = url;
return this.documentFrame.on("load", function()
{
window.FrameWindow = self.iframe.contentWindow;
window.FrameDocument = self.iframe.contentWindow.document;
var addSectionBox = $("#add-section-box");
var highlightBox = $("#highlight-box").hide();
$(window.FrameWindow).on( "beforeunload", function(event) {
if (Vvveb.Undo.undoIndex >= 0) {
var dialogText = "You have unsaved changes";
event.returnValue = dialogText;
return dialogText;
}
});
$(window.FrameWindow).on( "unload", function(event) {
$(".loading-message").addClass("active");
});
$(window.FrameWindow).on("scroll resize", function(event) {
if (self.selectedEl)
{
var offset = self.selectedEl.offset();
$("#select-box").css(
{"top": offset.top - self.frameDoc.scrollTop() - self.selectPadding,
"left": offset.left - self.frameDoc.scrollLeft() - self.selectPadding,
});
}
if (self.highlightEl)
{
var offset = self.highlightEl.offset();
highlightBox.css(
{"top": offset.top - self.frameDoc.scrollTop() - self.selectPadding,
"left": offset.left - self.frameDoc.scrollLeft() - self.selectPadding,
});
//addSectionBox.hide();
}
self.adjustListsHeight();
});
Vvveb.WysiwygEditor.init(window.FrameDocument);
Vvveb.StyleManager.init(window.FrameDocument);
Vvveb.ColorPaletteManager.init(window.FrameDocument);
if (self.initCallback) self.initCallback();
return self._frameLoaded();
});
},
_frameLoaded : function() {
var self = Vvveb.Builder;
self.frameDoc = $(window.FrameDocument);
self.frameHtml = $(window.FrameDocument).find("html");
self.frameBody = $(window.FrameDocument).find("body");
self.frameHead = $(window.FrameDocument).find("head");
//insert editor helpers like non editable areas
self.frameHead.append('<link data-vvveb-helpers href="' + Vvveb.baseUrl + '../../css/vvvebjs-editor-helpers.css" rel="stylesheet">');
self._initHighlight();
$(window).triggerHandler("vvveb.iframe.loaded", self.frameDoc);
$(".loading-message").removeClass("active");
},
_getElementType: function(el) {
//search for component attribute
var componentName = '';
var componentAttribute = '';
if (el.attributes) {
for (var j = 0; j < el.attributes.length; j++){
var nodeName = el.attributes[j].nodeName;
if (nodeName.indexOf('data-component') > -1) {
componentName = nodeName.replace('data-component-', '');
}
if (nodeName.indexOf('data-v-') > -1) {
componentAttribute = (componentAttribute ? componentAttribute + " - " : "") +
nodeName.replace('data-v-', '') + " ";
}
}
}
if (componentName != '') return componentName;
return el.tagName + (componentName ? " - " + componentName : "" ) + (componentAttribute ? " - " + componentAttribute : "");
},
loadNodeComponent: function(node) {
data = Vvveb.Components.matchNode(node);
var component;
if (data)
component = data.type;
else
component = Vvveb.defaultComponent;
console.log(component, 'component>>>>>>>>>>>')
// 判断是否为导航栏,是导航栏,获取实时导航栏配置
if (component == 'html/HuoCMSNav') {
initNav()
}
Vvveb.component = Vvveb.Components.get(component);
Vvveb.Components.render(component);//渲染组件
return component;
},
moveNodeUp: function(node) {
if (!node) {
node = Vvveb.Builder.selectedEl.get(0);
}
oldParent = node.parentNode;
oldNextSibling = node.nextSibling;
next = $(node).prev();
if (next.length > 0)
{
next.before(node);
} else
{
$(node).parent().before(node);
}
newParent = node.parentNode;
newNextSibling = node.nextSibling;
Vvveb.Undo.addMutation({type: 'move',
target: node,
oldParent: oldParent,
newParent: newParent,
oldNextSibling: oldNextSibling,
newNextSibling: newNextSibling});
},
moveNodeDown: function(node) {
if (!node) {
node = Vvveb.Builder.selectedEl.get(0);
}
oldParent = node.parentNode;
oldNextSibling = node.nextSibling;
next = $(node).next();
if (next.length > 0)
{
next.after(node);
} else
{
$(node).parent().after(node);
}
newParent = node.parentNode;
newNextSibling = node.nextSibling;
Vvveb.Undo.addMutation({type: 'move',
target: node,
oldParent: oldParent,
newParent: newParent,
oldNextSibling: oldNextSibling,
newNextSibling: newNextSibling});
},
cloneNode: function(node) {
if (!node) {
node = Vvveb.Builder.selectedEl;
}
clone = node.clone();
node.after(clone);
node = clone.click();
element = clone.get(0);
Vvveb.Undo.addMutation({type: 'childList',
target: node.parentNode,
addedNodes: [element],
nextSibling: node.nextSibling});
},
//选择元素触发事件
selectNode: function(node) {
var self = this;
if (!node)
{
$("#select-box").hide();
return;
}
if (self.texteditEl && self.selectedEl.get(0) != node)
{
Vvveb.WysiwygEditor.destroy(self.texteditEl);
self.selectPadding = 0;
$("#select-box").removeClass("text-edit").find("#select-actions").show();
self.texteditEl = null;
}
var target = $(node);
if (target)
{
self.selectedEl = target;
try {
var offset = target.offset();
$("#select-box").css(
{"top": offset.top - self.frameDoc.scrollTop() - self.selectPadding,
"left": offset.left - self.frameDoc.scrollLeft() - self.selectPadding,
"width" : target.outerWidth() + self.selectPadding * 2,
"height": target.outerHeight() + self.selectPadding * 2,
"display": "block",
});
Vvveb.Breadcrumb.loadBreadcrumb(target.get(0));
} catch(err) {
console.log(err);
return false;
}
}
$("#highlight-name").html(this._getElementType(node));
},
/* iframe highlight */
_initHighlight: function() {
var self = Vvveb.Builder;
self.frameBody.on("mousemove dragover touchmove", function(event) {
if (self.highlightEnabled == true && event.target && isElement(event.target) && event.originalEvent)
{
self.highlightEl = target = $(event.target);
var offset = target.offset();
var height = target.outerHeight();
var halfHeight = Math.max(height / 2, 50);
var width = target.outerWidth();
var halfWidth = Math.max(width / 2, 50);
var prepend = true;
var x = event.originalEvent.x;
var y = event.originalEvent.y;
if (self.isResize) {
if (!self.initialPosition) {
self.initialPosition = {x,y};
}
var deltaX = x - self.initialPosition.x;
var deltaY = y - self.initialPosition.y;
offset = self.selectedEl.offset();
width = self.initialSize.width;
height = self.initialSize.height;
switch (self.resizeHandler) {
// top
case "top-left":
height -= deltaY;
width -= deltaX;
break;
case "top-center":
height -= deltaY;
break;
case "top-right":
height -= deltaY;
width += deltaX;
break;
// center
case "center-left":
width -= deltaX;
break;
case "center-right":
width += deltaX;
break;
// bottom
case "bottom-left":
width -= deltaX;
height += deltaY;
break;
case "bottom-center":
height += deltaY;
break;
case "bottom-right":
width += deltaX;
height += deltaY;
break;
}
if (self.resizeMode == "css") {
self.selectedEl.css({width, height});
} else {
self.selectedEl.attr({width, height});
}
$("#select-box").css(
{"top": offset.top - self.frameDoc.scrollTop() ,
"left": offset.left - self.frameDoc.scrollLeft() ,
"width" : width,
"height": self.selectedEl.outerHeight(),
});
} else
if (self.isDragging)
{
var parent = self.highlightEl;
try {
if ((offset.top < (y - halfHeight)) || (offset.left < (x - halfWidth)))
{
self.dragElement.appendTo(parent);
prepend = true;
} else
{
prepend = false;
self.dragElement.prependTo(parent);
};
if (self.designerMode)
{
var parentOffset = self.dragElement.offsetParent().offset();
self.dragElement.css({
"position": "absolute",
'left': x - (parentOffset.left - self.frameDoc.scrollLeft()),
'top': y - (parentOffset.top - self.frameDoc.scrollTop()),
});
}
/*
$("#drop-highlight-box").css(
{"top": offset.top - self.frameDoc.scrollTop() ,
"left": offset.left - self.frameDoc.scrollLeft() ,
"width" : parentWidth,
"height": "5px",
"display" :"block",
});
*/
} catch(err) {
console.log(err);
return false;
}
if (!self.designerMode && self.iconDrag) {
self.iconDrag.css({'left': x + self.leftPanelWidth + 10, 'top': y + 60});
}
}// else //uncomment else to disable parent highlighting when dragging
{
$("#highlight-box").css(
{"top": offset.top - self.frameDoc.scrollTop() ,
"left": offset.left - self.frameDoc.scrollLeft() ,
"width" : width,
"height": height,
"display" : event.target.hasAttribute('contenteditable')?"none":"block",
"border":self.isDragging?"1px dashed #0d6efd":"",//when dragging highlight parent with green
});
if (height < 50)
{
$("#section-actions").addClass("outside");
} else
{
$("#section-actions").removeClass("outside");
}
$("#highlight-name").html(self._getElementType(event.target));
}
}
});
self.frameHtml.on("mouseup dragend touchend", function(event) {
self.isResize = false;
$("#section-actions, #highlight-name, #select-box").show();
// 目标不是huocms标签套过的代码,允许编辑
// let target = $(event.target);
// if (!isHuoCmsComponents(target)) {
// $("#select-actions").hide();
// }
if (self.isDragging)
{
self.isDragging = false;
Vvveb.Builder.highlightEnabled = true;
if (self.iconDrag) self.iconDrag.remove();
$("#component-clone").remove();
if (self.dragMoveMutation === false)
{
if (self.component.dragHtml || Vvveb.dragHtml) { //if dragHtml is set for dragging then set real component html
newElement = $(self.component.html);
self.dragElement.replaceWith(newElement);
self.dragElement = newElement;
}
if (self.component.afterDrop) self.dragElement = self.component.afterDrop(self.dragElement);
}
self.dragElement.css("border", "");
node = self.dragElement.get(0);
self.selectNode(node);
self.loadNodeComponent(node);
if (self.dragMoveMutation === false)
{
Vvveb.Undo.addMutation({type: 'childList',
target: node.parentNode,
addedNodes: [node],
nextSibling: node.nextSibling});
} else
{
self.dragMoveMutation.newParent = node.parentNode;
self.dragMoveMutation.newNextSibling = node.nextSibling;
Vvveb.Undo.addMutation(self.dragMoveMutation);
self.dragMoveMutation = false;
}
Vvveb.SectionList.loadSections();
}
});
self.frameHtml.on("dblclick", function(event) {
if (Vvveb.Builder.isPreview == false) {
// console.log(self.frameHtml.find('.nav'), '双击编辑>>>>>>>>>>>')
self.selectPadding = 10;
self.texteditEl = target = $(event.target);
Vvveb.WysiwygEditor.edit(self.texteditEl);
_updateSelectBox = function(event) {
if (!self.texteditEl) return;
var offset = self.selectedEl.offset();
$("#select-box").css({
"top": offset.top - self.frameDoc.scrollTop() - self.selectPadding,
"left": offset.left - self.frameDoc.scrollLeft() - self.selectPadding,
"width" : self.texteditEl.outerWidth() + self.selectPadding * 2,
"height": self.texteditEl.outerHeight() + self.selectPadding * 2
});
};
//update select box when the text size is changed
self.texteditEl.on("blur keyup paste input", _updateSelectBox);
_updateSelectBox();
$("#select-box").addClass("text-edit").find("#select-actions").hide();
$("#highlight-box").hide();
// 目标是huocms内置组件,不允许编辑
if (isHuoCmsComponents(target)) {
Vvveb.WysiwygEditor.destroy(self.texteditEl);
self.selectPadding = 0;
$("#select-box").removeClass("text-edit").find("#select-actions").show();
self.texteditEl = null;
}
}
});
self.frameHtml.on("click", function(event) {
if (Vvveb.Builder.isPreview == false){
if (event.target) {
// 目标是huocms组件,不允许编辑
if (isHuoCmsComponents($(target))) {
$("#select-box").hide()
return false;
}
//if component properties is loaded in left panel tab instead of right panel show tab
if ($(".component-properties-tab").is(":visible"))//if properites tab is enabled/visible
$('.component-properties-tab a').show().tab('show');
self.selectNode(event.target);
self.loadNodeComponent(event.target);
if (Vvveb.component.resizable) {
$("#select-box").addClass("resizable");
self.resizeMode = Vvveb.component.resizeMode;
} else {
$("#select-box").removeClass("resizable");
}
}
$("#add-section-box").hide();
event.preventDefault();
return false;
}
});
},
_initBox: function() {
var self = this;
$("#drag-btn").on("mousedown", function(event) {
self.dragElement = self.selectedEl.css("position","");
self.isDragging = true;
$("#section-actions, #highlight-name, #select-box").hide();
node = self.dragElement.get(0);
self.dragMoveMutation = {type: 'move',
target: node,
oldParent: node.parentNode,
oldNextSibling: node.nextSibling};
//self.selectNode(false);
event.preventDefault();
return false;
});
$(".resize > div").on("mousedown", function(event) {
$("#section-actions, #highlight-name, #highlight-box").hide();
self.isResize = true;
self.initialSize = {"width" : self.selectedEl.outerWidth(), "height" : self.selectedEl.outerHeight()};
self.initialPosition = false;
self.resizeHandler = this.className;
event.preventDefault();
return false;
});
$("#down-btn").on("click", function(event) {
$("#select-box").hide();
Vvveb.Builder.moveNodeDown();
event.preventDefault();
return false;
});
$("#up-btn").on("click", function(event) {
$("#select-box").hide();
Vvveb.Builder.moveNodeUp();
event.preventDefault();
return false;
});
$("#clone-btn").on("click", function(event) {
Vvveb.Builder.cloneNode();
event.preventDefault();
return false;
});
$("#parent-btn").on("click", function(event) {
node = self.selectedEl.parent().get(0);
self.selectNode(node);
self.loadNodeComponent(node);
event.preventDefault();
return false;
});
$("#delete-btn").on("click", function(event) {
$("#select-box").hide();
node = self.selectedEl.get(0);
Vvveb.Undo.addMutation({type: 'childList',
target: node.parentNode,
removedNodes: [node],
nextSibling: node.nextSibling});
self.selectedEl.remove();
Vvveb.SectionList.loadSections();
event.preventDefault();
return false;
});
var addSectionBox = $("#add-section-box");
var addSectionElement = {};
$("#add-section-btn").on("click", function(event) {
addSectionElement = self.highlightEl;
var offset = $(addSectionElement).offset();
var top = (offset.top - self.frameDoc.scrollTop()) + addSectionElement.outerHeight();
var left = (offset.left - self.frameDoc.scrollLeft()) + (addSectionElement.outerWidth() / 2) - (addSectionBox.outerWidth() / 2);
var outerHeight = $(window.FrameWindow).height() + self.frameDoc.scrollTop();
//check if box is out of viewport and move inside
if (left < 0) left = 0;
if (top < 0) top = 0;
if ((left + addSectionBox.outerWidth()) > self.frameDoc.outerWidth()) left = self.frameDoc.outerWidth() - addSectionBox.outerWidth();
if (((top + addSectionBox.outerHeight()) + self.frameDoc.scrollTop()) > outerHeight) top = top - addSectionBox.outerHeight();
addSectionBox.css(
{"top": top,
"left": left,
"display": "block",
});
Vvveb.SectionList.loadSections();
event.preventDefault();
return false;
});
$("#close-section-btn").on("click", function(event) {
addSectionBox.hide();
});
function addSectionComponent(html, after = true)
{
var node = $(html);
if (after)
{
addSectionElement.after(node);
} else
{
addSectionElement.append(node);
}
node = node.get(0);
Vvveb.Undo.addMutation({type: 'childList',
target: node.parentNode,
addedNodes: [node],
nextSibling: node.nextSibling});
}
$(".components-list li ol li", addSectionBox).on("click", function(event) {
var html = Vvveb.Components.get(this.dataset.type).html;
addSectionComponent(html, ($("[name='add-section-insert-mode']:checked").val() == "after"));
addSectionBox.hide();
});
$(".blocks-list li ol li", addSectionBox).on("click", function(event) {
var html = Vvveb.Blocks.get(this.dataset.type).html;
addSectionComponent(html, ($("[name='add-section-insert-mode']:checked").val() == "after"));
addSectionBox.hide();
});
$(".sections-list li ol li", addSectionBox).on("click", function(event) {
var html = Vvveb.Sections.get(this.dataset.type).html;
addSectionComponent(html, ($("[name='add-section-insert-mode']:checked").val() == "after"));
addSectionBox.hide();
});
},
/* drag and drop */
_initDragdrop : function() {
var self = this;
self.isDragging = false;
$('.drag-elements-sidepane ul > li > ol > li[data-drag-type]').on("mousedown touchstart", function(event) {
$this = $(this);
$("#component-clone").remove();
$("#section-actions, #highlight-name, #select-box").hide();
if ($this.data("drag-type") == "component") {
self.component = Vvveb.Components.get($this.data("type"));
}
else if ($this.data("drag-type") == "section") {
self.component = Vvveb.Sections.get($this.data("type"));
}
else if ($this.data("drag-type") == "block") {
self.component = Vvveb.Blocks.get($this.data("type"));
}
if (self.component.dragHtml) {
html = self.component.dragHtml;
} else if (Vvveb.dragHtml) {
html = Vvveb.dragHtml;
} else {
html = self.component.html;
}
self.dragElement = $(html);
//self.dragElement.css("border", "1px dashed #4285f4");
if (self.component.dragStart) self.dragElement = self.component.dragStart(self.dragElement);
self.isDragging = true;
if (Vvveb.dragIcon == 'html')
{
self.iconDrag = $(html).attr("id", "dragElement-clone").css('position', 'absolute');
}
else if (self.designerMode == false)
{
self.iconDrag = $('<img src=""/>').attr({"id": "dragElement-clone", 'src': $this.css("background-image").replace(/^url\(['"](.+)['"]\)/, '$1')}).
css({'z-index':100, 'position':'absolute', 'width':'64px', 'height':'64px', 'top': event.originalEvent.y, 'left': event.originalEvent.x});
}
$('body').append(self.iconDrag);
event.preventDefault();
return false;
});
$('body').on('mouseup dragend touchend', function(event) {
if (self.iconDrag && self.isDragging == true)
{
self.isDragging = false;
$("#component-clone").remove();
$("#section-actions, #highlight-name, #select-box").show();
// 目标不是huocms标签套过的代码,允许编辑
// let target = $(event.target);
// if (!isHuoCmsComponents(target)) {
// $("#select-actions").hide();
// }
self.iconDrag.remove();
if(self.dragElement){
self.dragElement.remove();
}
}
});
$('body').on('mousemove dragover touchmove', function(event) {
if (self.iconDrag && self.isDragging == true)
{
var x = (event.clientX || event.originalEvent.clientX);
var y = (event.clientY || event.originalEvent.clientY);
self.iconDrag.css({'left': x - 60, 'top': y - 30});
elementMouseIsOver = document.elementFromPoint(x - 60, y - 40);
//if drag elements hovers over iframe switch to iframe mouseover handler
return;
if (elementMouseIsOver && elementMouseIsOver.tagName == 'IFRAME')
{
self.frameBody.trigger("mousemove", event);
event.stopPropagation();
self.selectNode(false);
}
}
});
$('.drag-elements-sidepane ul > ol > li > li').on("mouseup dragend touchend", function(event) {
self.isDragging = false;
$("#component-clone").remove()
$("#section-actions, #highlight-name, #select-box").show();
// 目标不是huocms标签套过的代码,允许编辑
// let target = $(event.target);
// if (!isHuoCmsComponents(target)) {
// $("#select-actions").hide();
// }
});
},
removeHelpers: function (html, keepHelperAttributes = false)
{
//tags like stylesheets or scripts
html = html.replace(/<[^>]+?data-vvveb-helpers.+?>/gi, "");
//attributes
if (!keepHelperAttributes)
{
html = html.replace(/\s*data-vvveb-\w+(=["'].*?["'])?\s*/gi, "");
}
return html;
},
getHtml: function(keepHelperAttributes = true)
{
var doc = window.FrameDocument;
var hasDoctpe = (doc.doctype !== null);
var html = "";
$("[contenteditable]", doc).removeAttr("contenteditable");
$("[spellcheckker]", doc).removeAttr("spellcheckker");
$(window).triggerHandler("vvveb.getHtml.before", doc);
if (hasDoctpe) html =
"<!DOCTYPE "
+ doc.doctype.name
+ (doc.doctype.publicId ? ' PUBLIC "' + doc.doctype.publicId + '"' : '')
+ (!doc.doctype.publicId && doc.doctype.systemId ? ' SYSTEM' : '')
+ (doc.doctype.systemId ? ' "' + doc.doctype.systemId + '"' : '')
+ ">\n";
html += doc.documentElement.innerHTML + "\n</html>";
html = this.removeHelpers(html, keepHelperAttributes);
Vvveb.FontsManager.cleanUnusedFonts();
$(window).triggerHandler("vvveb.getHtml.after", doc);
var filter = $(window).triggerHandler("vvveb.getHtml.filter", html);
if (filter) return filter;
return html;
},
setHtml: function(html)
{
//update only body to avoid breaking iframe css/js relative paths
start = html.indexOf("<body");
end = html.indexOf("</body");
if (start >= 0 && end >= 0) {
body = html.slice(html.indexOf(">", start) + 1, end);
} else {
body = html
}
if (this.runJsOnSetHtml)
self.frameBody.html(body);
else
window.FrameDocument.body.innerHTML = body;
//below methods brake document relative css and js paths
//return self.iframe.outerHTML = html;
//return self.documentFrame.html(html);
//return self.documentFrame.attr("srcdoc", html);
},
saveAjax: function(fileName, startTemplateUrl, callback, saveUrl)
{
var data = {};
// data["file"] = (fileName && fileName != "") ? fileName : Vvveb.FileManager.getCurrentFileName();
data["file"] = Vvveb.FileManager.getCurrentFile();
data["startTemplateUrl"] = startTemplateUrl;
if (!startTemplateUrl || startTemplateUrl == null)
{
data["html"] = this.getHtml();
}
let site_id = getCookie('webSiteId')
let lang = getCookie('lang')
data["website_id"] = site_id
data["lang"] = lang
let headers = createHeader()
loading('saveAjax', '', '代码生成中')
$.ajax({
type: "POST",
url: saveUrl,//set your server side save script url
data: data,
headers: headers,
cache: false,
success: function (data) {
if (callback) callback(data);
removeLoading('saveAjax')
$('#historyList').removeClass('open')
},
error: function (data) {
alert(data.responseText);
removeLoading('saveAjax')
}
});
},
publishAjax: function (fileName, startTemplateUrl, callback, saveUrl)
{
var data = {};
// data["file"] = (fileName && fileName != "") ? fileName : Vvveb.FileManager.getCurrentFileName();
data["file"] = Vvveb.FileManager.getCurrentFile();
data["startTemplateUrl"] = startTemplateUrl;
if (!startTemplateUrl || startTemplateUrl == null)
{
data["html"] = this.getHtml();
}
let site_id = getCookie('webSiteId')
let lang = getCookie('lang')
data["website_id"] = site_id
data["lang"] = lang
let headers = createHeader()
loading('publishAjax', '', '代码生成中')
$.ajax({
type: "POST",
url: saveUrl,//set your server side save script url
data: data,
headers: headers,
cache: false,
success: function (data) {
if (callback) callback(data);
removeLoading('publishAjax')
$('#historyList').removeClass('open')
},
error: function (data) {
alert(data.responseText);
removeLoading('publishAjax')
}
});
},
setDesignerMode: function(designerMode = false)
{
this.designerMode = designerMode;
}
};
Vvveb.CodeEditor = {
isActive: false,
oldValue: '',
doc:false,
init: function(doc) {
$("#vvveb-code-editor textarea").val(Vvveb.Builder.getHtml());
$("#vvveb-code-editor textarea").keyup(function () {
delay(() => Vvveb.Builder.setHtml(this.value), 1000);
});
//load code on document changes
Vvveb.Builder.frameBody.on("vvveb.undo.add vvveb.undo.restore", function (e) { Vvveb.CodeEditor.setValue();});
//load code when a new url is loaded
Vvveb.Builder.documentFrame.on("load", function (e) { Vvveb.CodeEditor.setValue();});
this.isActive = true;
},
setValue: function(value) {
if (this.isActive)
{
$("#vvveb-code-editor textarea").val(Vvveb.Builder.getHtml());
}
},
destroy: function(element) {
//this.isActive = false;
},
toggle: function() {
if (this.isActive != true)
{
this.isActive = true;
return this.init();
}
this.isActive = false;
this.destroy();
}
}
Vvveb.Gui = {
init: function() {
$("[data-vvveb-action]").each(function () {
on = "click";
if (this.dataset.vvvebOn) on = this.dataset.vvvebOn;
$(this).on(on, Vvveb.Gui[this.dataset.vvvebAction]);
if (this.dataset.vvvebShortcut)
{
$(document).bind('keydown', this.dataset.vvvebShortcut, Vvveb.Gui[this.dataset.vvvebAction]);
$(window.FrameDocument, window.FrameWindow).bind('keydown', this.dataset.vvvebShortcut, Vvveb.Gui[this.dataset.vvvebAction]);
}
});
},
undo : function () {
if (Vvveb.WysiwygEditor.isActive)
{
Vvveb.WysiwygEditor.undo();
} else
{
Vvveb.Undo.undo();
}
Vvveb.Builder.selectNode();
},
redo : function () {
if (Vvveb.WysiwygEditor.isActive)
{
Vvveb.WysiwygEditor.redo();
} else
{
Vvveb.Undo.redo();
}
Vvveb.Builder.selectNode();
},
//show modal with html content
save : function () {
$('#textarea-modal textarea').val(Vvveb.Builder.getHtml());
$('#textarea-modal').modal();
},
//post html content through ajax to save to filesystem/db
saveAjax : function () {
var saveUrl = this.dataset.vvvebUrl;
var url = Vvveb.FileManager.getPageData('url');
return Vvveb.Builder.saveAjax(url, null, function (data) {
var messageModal = new bootstrap.Modal(document.getElementById('message-modal'), {
keyboard: false
});
$("#message-modal .modal-body").html(data);
messageModal.show()
}, saveUrl);
},
// 发布页面到模板文件
publishAjax : function () {
var saveUrl = this.dataset.vvvebUrl;
var url = Vvveb.FileManager.getPageData('url');
return Vvveb.Builder.publishAjax(url, null, function (data) {
var messageModal = new bootstrap.Modal(document.getElementById('message-modal'), {
keyboard: false
});
$("#message-modal .modal-body").html(data);
messageModal.show()
}, saveUrl);
},
download : function () {
filename = /[^\/]+$/.exec(Vvveb.Builder.iframe.src)[0];
uriContent = "data:application/octet-stream," + encodeURIComponent(Vvveb.Builder.getHtml());
var link = document.createElement('a');
if ('download' in link)
{
link.dataset.download = filename;
link.href = uriContent;
link.target = "_blank";
document.body.appendChild(link);
result = link.click();
document.body.removeChild(link);
link.remove();
} else
{
location.href = uriContent;
}
},
viewport : function () {
$("#canvas").attr("class", this.dataset.view);
},
toggleEditor : function () {
$("#vvveb-builder").toggleClass("bottom-panel-expand");
$("#toggleEditorJsExecute").toggle();
Vvveb.CodeEditor.toggle();
},
toggleEditorJsExecute : function () {
Vvveb.Builder.runJsOnSetHtml = this.checked;
},
preview : function () {
(Vvveb.Builder.isPreview == true)?Vvveb.Builder.isPreview = false:Vvveb.Builder.isPreview = true;
$("#iframe-layer").toggle();
$("#vvveb-builder").toggleClass("preview");
},
fullscreen : function () {
launchFullScreen(document); // the whole page
},
search : function () {
let searchText = this.value;
let panel = $("div > ul", this.parentNode.parentNode)
$("li ol li", panel).each(function () {
$this = $(this);
$this.hide();
if ($this.data("search").indexOf(searchText) > -1) $this.show();
});
},
clearSearch : function (e) {
$("input", this.parentNode).val("").keyup();
},
expand : function (e) {
$('input.header_check[type="checkbox"]', this.parentNode.parentNode.parentNode).prop("checked", true)
},
collapse : function (e) {
$('input.header_check[type="checkbox"]', this.parentNode.parentNode.parentNode).prop("checked", false)
},
//Pages, file/components tree
newPage : function () {
var newPageModal = $('#new-page-modal');
newPageModal.modal("show").find("form").off("submit").submit(function( e ) {
var data = {};
$.each($(this).serializeArray(), function() {
data[this.name] = this.value;
});
var name = data['name'] = data['file'];
data['url'] = data['file'] = data['folder'] + "/" + data['file'];
Vvveb.FileManager.addPage(data.name, data);
e.preventDefault();
return Vvveb.Builder.saveAjax(data.file, data.startTemplateUrl, function (data) {
Vvveb.FileManager.loadPage(name);
Vvveb.FileManager.scrollBottom();
newPageModal.modal("hide");
}, this.action);
});
},
deletePage : function () {
},
setDesignerMode : function () {
//aria-pressed attribute is updated after action is called and we check for false instead of true
var designerMode = this.attributes["aria-pressed"].value != "true";
Vvveb.Builder.setDesignerMode(designerMode);
},
//layout
togglePanel: function (panel, cssVar) {
var panel = $(panel);
var body = $("body");
var prevValue = body.css(cssVar);
if (prevValue !== "0px")
{
panel.data("layout-toggle", prevValue);
body.css(cssVar, "0px");
panel.hide();
return false;
} else
{
prevValue= panel.data("layout-toggle");
body.css(cssVar, '');
panel.show();
return true;
}
},
toggleFileManager: function () {
Vvveb.Gui.togglePanel("#filemanager", "--builder-filemanager-height");
},
toggleLeftColumn: function () {
Vvveb.Gui.togglePanel("#left-panel", "--builder-left-panel-width");
},
toggleRightColumn: function (rightColumnEnabled = null) {
rightColumnEnabled = Vvveb.Gui.togglePanel("#right-panel", "--builder-right-panel-width");
$("#vvveb-builder").toggleClass("no-right-panel");
$(".component-properties-tab").toggle();
Vvveb.Components.componentPropertiesElement = (rightColumnEnabled ? "#right-panel" :"#left-panel") + " .component-properties";
if ($("#properties").is(":visible")) $('.component-tab a').show().tab('show');
},
}
Vvveb.StyleManager = {
styles: {},
cssContainer: false,
mobileWidth: '320px',
tabletWidth: '768px',
init: function (doc) {
if (doc) {
var style = false;
var _style = false;
//check if editor style is present
for (let i = 0; i < doc.styleSheets.length; i++) {
_style = doc.styleSheets[i];
if (_style.ownerNode.id && _style.ownerNode.id == "vvvebjs-styles") {
style = _style;
break;
}
}
//if style element does not exist create it
if (!style) {
this.cssContainer = $('<style id="vvvebjs-styles"></style>');
$(doc.head).append(this.cssContainer);
return this.cssContainer;
}
//if style exist then load all css styles for editor
for (let j = 0; j < style.cssRules.length; j++) {
media = (typeof style.cssRules[j].media === "undefined") ?
"desktop" : (style.cssRules[j].media[0] === "screen and (max-width: 1220px)")
? "tablet" : (style.cssRules[j].media[0] === "screen and (max-width: 320px)")
? "mobile" : "desktop";
selector = (media === "desktop") ? style.cssRules[j].selectorText : style.cssRules[j].cssRules[0].selectorText;
styles = (media === "desktop") ? style.cssRules[j].style : style.cssRules[j].cssRules[0].style;
if (media) {
this.styles[media] = {};
if (selector) {
this.styles[media][selector] = {};
for (let k = 0; k < styles.length; k++) {
property = styles[k];
value = styles[property];
this.styles[media][selector][property] = value;
}
}
}
}
return this.cssContainer = $("#vvvebjs-styles", doc);
}
},
getSelectorForElement: function (element) {
var currentElement = element;
var selector = [];
while (currentElement.parentElement) {
let elementSelector = "";
let classSelector = Array.from(currentElement.classList).map(function (className) {
if (Vvveb.Builder.ignoreClasses.indexOf(className) == -1) {
return "." + className;
}
}).join("");
//stop at a unique element (with id)
if (currentElement.id) {
elementSelector = "#" + currentElement.id;
selector.push(elementSelector);
break;
} else if (classSelector) {
//class selector
elementSelector = classSelector;
} else {
//element (tag) selector
var tag = currentElement.tagName.toLowerCase();
//exclude top most element body unless the parent element is body
if (tag != "body" || (tag == "body" && selector.length <= 1)) {
elementSelector = tag
}
}
if (elementSelector) {
selector.push(elementSelector);
}
currentElement = currentElement.parentElement;
}
return selector.reverse().join(" > ");
},
setStyle: function (element, styleProp, value) {
if (typeof(element) == "string") {
selector = element;
} else {
selector = this.getSelectorForElement(element.get(0));
}
media = $("#canvas").hasClass("tablet") ? "tablet" : $("#canvas").hasClass("mobile") ? "mobile" : "desktop";
//styles[media][selector][styleProp] = value
if (!this.styles[media]) {
this.styles[media] = {};
}
if (!this.styles[media][selector]) {
this.styles[media][selector] = {};
}
if (!this.styles[media][selector][styleProp]) {
this.styles[media][selector][styleProp] = {};
}
this.styles[media][selector][styleProp] = value;
this.generateCss(media);
return element;
//uncomment bellow code to set css in element's style attribute
//return element.css(styleProp, value);
},
generateCss: function (media) {
//var css = "";
//for (selector in this.styles[media]) {
// css += `${selector} {`;
// for (property in this.styles[media][selector]) {
// value = this.styles[media][selector][property];
// css += `${property}: ${value};`;
// }
// css += '}';
//}
//this.cssContainer.html(css);
//return element;
var css = "";
for (media in this.styles) {
if (media === "tablet" || media === "mobile") {
css += `@media screen and (max-width: ${(media === 'tablet') ? this.tabletWidth : this.mobileWidth}){`
}
for (selector in this.styles[media]) {
css += `${selector} {`;
for (property in this.styles[media][selector]) {
value = this.styles[media][selector][property];
css += `${property}: ${value};`;
}
css += '}';
}
if (media === "tablet" || media === "mobile") {
css += `}`
}
}
this.cssContainer.html(css);
return element;
},
_getCssStyle: function (element, styleProp) {
var value = "";
var el = element.get(0);
if (typeof(element) == "string") {
selector = element;
} else {
selector = this.getSelectorForElement(el);
}
media = $("#canvas").hasClass("tablet") ? "tablet" : $("#canvas").hasClass("mobile") ? "mobile" : "desktop";
if (el.style && el.style.length > 0 && el.style[styleProp])//check inline
var value = el.style[styleProp];
else if (this.styles[media] !== undefined && this.styles[media][selector] !== undefined && this.styles[media][selector][styleProp] !== undefined) { //check defined css
var value = this.styles[media][selector][styleProp];
}
else if (window.getComputedStyle) {
var value = document.defaultView.getDefaultComputedStyle ?
document.defaultView.getDefaultComputedStyle(el, null).getPropertyValue(styleProp) :
window.getComputedStyle(el, null).getPropertyValue(styleProp);
}
return value;
},
getStyle: function (element, styleProp) {
return this._getCssStyle(element, styleProp);
}
}
Vvveb.ContentManager = {
getAttr: function(element, attrName) {
return element.attr(attrName);
},
setAttr: function(element, attrName, value) {
return element.attr(attrName, value);
},
setHtml: function(element, html) {
return element.html(html);
},
getHtml: function(element) {
return element.html();
},
};
function getNodeTree (node, parent, allowedComponents) {
function getNodeTreeTraverse (node, parent) {
if (node.hasChildNodes()) {
for (var j = 0; j < node.childNodes.length; j++) {
child = node.childNodes[j];
//skip text and comments nodes
if (child.nodeType == 3 || child.nodeType == 8) {
continue;
}
if (child && child["attributes"] != undefined &&
(matchChild = Vvveb.Components.matchNode(child))) {
if (Array.isArray(allowedComponents)
&& allowedComponents.indexOf(matchChild.type) == -1) {
element = getNodeTreeTraverse(child, parent);
continue;
}
element = {
name: matchChild.name,
image: matchChild.image,
type: matchChild.type,
node: child,
children: []
};
element.children = [];
parent.push(element);
element = getNodeTreeTraverse(child, element.children);
} else
{
element = getNodeTreeTraverse(child, parent);
}
}
}
return false;
}
getNodeTreeTraverse(node, parent);
}
function drawComponentsTree(tree) {
var j = 1;
var prefix = Math.floor(Math.random() * 100);
function drawComponentsTreeTraverse(tree) {
var html = $("<ol></ol>");
j++;
for (i in tree)
{
var node = tree[i];
var id = prefix + '-' + j + '-' + i;
if (tree[i].children.length > 0)
{
var li = $('<li data-component="' + node.name + '">\
<label for="id' + id + '" style="background-image:url(' + Vvveb.imgBaseUrl + node.image + ')"><span>' + node.name + '</span></label>\
<input type="checkbox" id="id' + id + '">\
</li>');
li.append(drawComponentsTreeTraverse(node.children));
}
else
{
var li =$('<li data-component="' + node.name + '" class="file">\
<label for="id' + id + '" style="background-image:url(' + Vvveb.imgBaseUrl + node.image + ')"><span>' + node.name + '</span></label>\
<input type="checkbox" id="id' + id + '">\
</li>');
}
li.data("node", node.node);
html.append(li);
}
return html;
}
return drawComponentsTreeTraverse(tree);
}
var selected = null;
var dragover = null;
Vvveb.SectionList = {
selector: '.sections-container',
allowedComponents: {},
init: function(allowedComponents = {}) {
this.allowedComponents = allowedComponents;
$(this.selector).on("click", "> div .controls", function (e) {
var node = $(e.currentTarget.parentNode).data("node");
if (node) {
delay(
() => Vvveb.Builder.frameHtml.animate({
scrollTop: $(node).offset().top - ($(node).height() / 2)
}, 500),
300);
//node.click();
Vvveb.Builder.selectNode(node);
Vvveb.Builder.loadNodeComponent(node);
}
}).on("dblclick", "> div", function (e) {
node = $(e.currentTarget).data("node");
node.click();
});
$(this.selector).on("click", "li[data-component] label ", function (e) {
node = $(e.currentTarget.parentNode).data("node");
delay(
() => Vvveb.Builder.frameHtml.animate({
scrollTop: $(node).offset().top - ($(node).height() / 2)
}, 1000),
300);
node.click();
}).on("mouseenter", "li[data-component] label", function (e) {
node = $(e.currentTarget.parentNode).data("node");
delay(
() => Vvveb.Builder.frameHtml.animate({
scrollTop: $(node).offset().top - ($(node).height() / 2)
}, 500),
1000);
$(node).trigger("mousemove");
});
$(this.selector).on("dragstart", "> div", this.dragStart);
$(this.selector).on("dragover", "> div", this.dragOver);
$(this.selector).on("dragend", "> div", this.dragEnd);
$(this.selector).on("click", ".delete-btn", function (e) {
var section = $(e.currentTarget).parents(".section-item");
var node = section.data("node");
node.remove();
section.remove();
e.stopPropagation();
e.preventDefault();
});
$(".sections-list").on("mouseenter", "li[data-section]", function (e) {
var src = $("img", this).attr("src");
$(".block-preview img").attr("src", src ).show();
}).on("mouseleave", "li[data-section]", function (e) {
$(".block-preview img").attr("src", "").hide();
});
/*
$(this.selector).on("click", ".up-btn", function (e) {
var section = $(e.currentTarget).parents(".section-item");
var node = section.data("node");
Vvveb.Builder.moveNodeUp(node);
Vvveb.Builder.moveNodeUp(section.get(0));
e.preventDefault();
});
$(this.selector).on("click", ".down-btn", function (e) {
var section = $(e.currentTarget).parents(".section-item");
var node = section.data("node");
Vvveb.Builder.moveNodeDown(node);
Vvveb.Builder.moveNodeDown(section.get(0));
e.preventDefault();
});
*/
var self = this;
$("#sections .sections-list").on("click", " .add-section-btn", function (e) {
var section = Vvveb.Sections.get(this.parentNode.dataset.type);
var node = $(section.html);
var sectionType = node[0].tagName.toLowerCase();
var afterSection = $(sectionType + ":last", Vvveb.Builder.frameBody);
if (afterSection.length) {
afterSection.after(node);
} else {
if (sectionType != "footer") {
afterSection = $("footer:first", Vvveb.Builder.frameBody);
if (afterSection.length) {
afterSection.before(node);
} else {
$(Vvveb.Builder.frameBody).append(node);
}
} else {
$(Vvveb.Builder.frameBody).append(node);
}
}
Vvveb.Builder.frameHtml.animate({
scrollTop: $(node).offset().top
}, 1000);
delay(() => node.click(), 1000);
node = node.get(0);
Vvveb.Undo.addMutation({type: 'childList',
target: node.parentNode,
addedNodes: [node],
nextSibling: node.nextSibling});
self.loadSections();
e.preventDefault();
});
$(this.selector).on("click", ".properties-btn", function (e) {
var section = $(e.currentTarget).parents(".section-item");
var node = section.data("node");
node.click();
e.preventDefault();
});
},
getSections: function() {
var sections = [];
var sectionList =
$('> section, > header, > footer, > main, > nav', window.FrameDocument.body);
sectionList.each(function (i, node) {
var id = node.id ? node.id : node.dataset.name;
if (!id) {
id = 'section-' + Math.floor(Math.random() * 10000);
}
var section = {
name: id.replace(/[^\w+]+/g,' '),
id: node.id,
type: node.tagName.toLowerCase(),
node: node
};
sections.push(section);
});
return sections;
},
loadComponents: function(sectionListItem, section, allowedComponents = {}) {
var tree = [];
getNodeTree(section, tree, allowedComponents);
var html = drawComponentsTree(tree);
$("ol", sectionListItem).replaceWith(html);
},
addSection: function(data) {
var section = $(tmpl("vvveb-section", data));
section.data("node", data.node);
$(this.selector).append(section);
this.loadComponents(section, data.node, this.allowedComponents);
},
loadSections: function() {
var sections = this.getSections();
$(this.selector).html("");
for (i in sections) {
this.addSection(sections[i]);
}
},
//drag and drop
dragOver: function(e) {
if (e.target != dragover &&
e.target.className == "section-item") {
if (dragover) {
dragover.classList.remove("drag-over");
}
dragover = e.target;
dragover.classList.add("drag-over");
}
},
dragEnd: function (e) {
if (dragover) {
var parent = selected.parentNode;
var selectedNode = $(selected).data("node");
var replaceNode = $(dragover).data("node");
if ((dragover.offsetTop > selected.offsetTop)) {
//replace section item list
parent.insertBefore(selected, dragover.nextElementSibling);
//replace section
replaceNode.parentNode.insertBefore(selectedNode, replaceNode.nextElementSibling);
} else {
//replace section item list
parent.insertBefore(selected, dragover);
//replace section
replaceNode.parentNode.insertBefore(selectedNode, replaceNode);
}
dragover.classList.remove("drag-over");
var node = selectedNode.get(0);
self.dragMoveMutation = {type: 'move',
target: node,
oldParent: node.parentNode,
oldNextSibling: node.nextSibling};
}
selected = null
dragover = null
},
dragStart: function (e) {
selected = e.target
},
}
Vvveb.FileManager = {
tree:false,
pages:{},
currentPage: false,
allowedComponents: {},
init: function(allowedComponents = {}) {
this.allowedComponents = allowedComponents;
this.tree = $("#filemanager .tree > ol").html("");
$(this.tree).on("click", "a", function (e) {
e.preventDefault();
return false;
});
$(this.tree).on("click", "li[data-page] label", function (e) {
var page = $(this.parentNode).data("page");
if (page) Vvveb.FileManager.loadPage(page, allowedComponents);
return false;
})
$(this.tree).on("click", "li[data-component] label ", function (e) {
node = $(e.currentTarget.parentNode).data("node");
delay(
() => Vvveb.Builder.frameHtml.animate({
scrollTop: $(node).offset().top - ($(node).height() / 2)
}, 500),
500);
node.click();
}).on("mouseenter", "li[data-component] label", function (e) {
node = $(e.currentTarget.parentNode).data("node");
delay(
() => Vvveb.Builder.frameHtml.animate({
scrollTop: $(node).offset().top - ($(node).height() / 2)
}, 500),
1000);
$(node).trigger("mousemove");
});
},
addPage: function(name, data) {
this.pages[name] = data;
data['name'] = name;
var folder = this.tree;
if (data.folder)
{
if (!(folder = this.tree.find('li[data-folder="' + data.folder + '"]')).length)
{
data.folderTitle = data.folder[0].toUpperCase() + data.folder.slice(1);
folder = $(tmpl("vvveb-filemanager-folder", data));
this.tree.append(folder);
}
folder = folder.find("> ol");
}
folder.append(
tmpl("vvveb-filemanager-page", data));
},
addPages: function(pages) {
for (page in pages)
{
this.addPage(pages[page]['name'], pages[page]);
}
},
addComponent: function(name, url, title, page) {
$("[data-page='" + page + "'] > ol", this.tree).append(
tmpl("vvveb-filemanager-component", {name:name, url:url, title:title}));
},
loadComponents: function(allowedComponents = {}) {
var tree = [];
getNodeTree(window.FrameDocument.body, tree, allowedComponents);
var html = drawComponentsTree(tree);
$("[data-page='" + this.currentPage + "'] > ol", this.tree).replaceWith(html);
},
getCurrentUrl: function() {
if (this.currentPage)
return this.pages[this.currentPage]['url'];
},
getPageData: function(key) {
if (this.currentPage)
return this.pages[this.currentPage][key];
},
getCurrentFileName: function() {
if (this.currentPage)
{
var folder = this.pages[this.currentPage]['folder'];
folder = folder ? folder + '/': '';
return folder + this.pages[this.currentPage]['file'];
}
},
getCurrentFile:function () {
if (this.currentPage)
return this.pages[this.currentPage]['file'];
},
reloadCurrentPage: function() {
if (this.currentPage)
return this.loadPage(this.currentPage);
},
loadPage: function(name, allowedComponents = false, disableCache = true) {
$("[data-page]", this.tree).removeClass("active");
$("[data-page='" + name + "']", this.tree).addClass("active");
console.log(name, this.pages[name])
this.currentPage = name;
var url = this.pages[name]['url'];
Vvveb.Builder.loadUrl(url + (disableCache ? (url.indexOf('?') > -1 ? '&r=':'?r=') + Math.random():''),
function () {
Vvveb.FileManager.loadComponents(allowedComponents);
Vvveb.SectionList.loadSections(allowedComponents);
Vvveb.StyleManager.init();
});
},
scrollBottom: function() {
var scroll = this.tree.parent();
scroll.scrollTop(scroll.prop("scrollHeight"));
},
}
Vvveb.Breadcrumb = {
tree:false,
init: function() {
this.tree = $(".breadcrumb-navigator > .breadcrumb").html("");
$(this.tree).on("click", ".breadcrumb-item", function (e) {
var node = $(this).data("node");
if (node) {
node.click();
}
e.preventDefault();
}).on("mouseenter", ".breadcrumb-item", function (e) {
var node = $(this).data("node");
delay(
() => Vvveb.Builder.frameHtml.animate({
scrollTop: $(node).offset().top - ($(node).height() / 2)
}, 500),
1000);
$(node).trigger("mousemove");
});
},
addElement: function(data, element) {
var li = $(tmpl("vvveb-breadcrumb-navigaton-item", data));
li.data("node", element);
$(this.tree).prepend(li);
},
loadBreadcrumb: function(element) {
this.tree.html("");
var currentElement = element;
while (currentElement.parentElement) {
this.addElement({
"name": Vvveb.Builder._getElementType(currentElement).toLowerCase(),
}, currentElement);
currentElement = currentElement.parentElement;
}
}
}
Vvveb.FontsManager = {
activeFonts:[],
providers: {},//{"google":GoogleFontsManager};
addProvider: function(provider, Obj) {
this.providers[provider] = Obj;
},
//add also element so we can keep track of the used fonts to remove unused ones
addFont: function(provider, fontFamily, element = false) {
if (!provider) return;
let providerObj = this.providers[provider];
if (providerObj) {
providerObj.addFont(fontFamily);
this.activeFonts.push({provider, fontFamily, element});
}
},
removeFont: function(provider, fontFamily) {
let providerObj = this.providers[provider];
if (provider!= "default" && providerObj) {
providerObj.removeFont(fontFamily);
}
},
//check if the added fonts are still used for the elements they were set and remove unused ones
cleanUnusedFonts: function (){
for (i in this.activeFonts) {
let elementFont = this.activeFonts[i];
if (elementFont.element) {
//if (getComputedStyle(elementFont.element)['font-family'] != elementFont.fontFamily) {
if (Vvveb.StyleManager.getStyle(element,'font-family') != elementFont.fontFamily) {
this.removeFont(elementFont.provider, elementFont.fontFamily);
}
}
}
}
};
Vvveb.ColorPaletteManager = {
getAllCSSVariableNames: function (styleSheets = document.styleSheets, selector){
let cssVars = {"font": {}, "color" : {}, "dimensions": {}};
for(var i = 0; i < styleSheets.length; i++){
try{
let cssRules = styleSheets[i].cssRules;
for( var j = 0; j < cssRules.length; j++){
try{
let style = cssRules[j].style;
if (selector && cssRules[j].selectorText && cssRules[j].selectorText != selector) continue;
for(var k = 0; k < style.length; k++){
let name = style[k];
let value = style.getPropertyValue(name).trim();
let type = "";
if(name.startsWith("--")){
//ignore bootstrap rgb variables
if (name.endsWith("-rgb")) continue;
//ignore variables depending on other variables
if (value.startsWith("var(")) continue;
let friendlyName = name.replace("--bs-","").replaceAll("-", " ");
if (value.startsWith("#")) {
type = "color";
} else if (value.indexOf('"') > 0) {
type = "font";
} else if (value.endsWith('em') > 0 || value.endsWith('px') > 0) {
type = "dimensions";
} else if (!isNaN(parseFloat(value))) {
type = "dimensions";
}
if (type) {
if (!cssVars[type]) cssVars[type] = {};
cssVars[type][name] = {value, type, friendlyName};
}
}
}
} catch (error) {}
}
} catch (error) {}
}
return cssVars;
},
init: function(document) {
Vvveb.Builder.selectedEl = $(document.body);
Vvveb.Components.render("config/bootstrap", "#configuration .component-properties")
},
};
// Toggle fullscreen
function launchFullScreen(document) {
if(document.documentElement.requestFullScreen) {
if (document.FullScreenElement)
document.exitFullScreen();
else
document.documentElement.requestFullScreen();
//mozilla
} else if(document.documentElement.mozRequestFullScreen) {
if (document.mozFullScreenElement)
document.mozCancelFullScreen();
else
document.documentElement.mozRequestFullScreen();
//webkit
} else if(document.documentElement.webkitRequestFullScreen) {
if (document.webkitFullscreenElement)
document.webkitExitFullscreen();
else
document.documentElement.webkitRequestFullScreen();
//ie
} else if(document.documentElement.msRequestFullscreen) {
if (document.msFullScreenElement)
document.msExitFullscreen();
else
document.documentElement.msRequestFullscreen();
}
}
let fontList = [{
value: "",
text: "Default"
}, {
value: "Arial, Helvetica, sans-serif",
text: "Arial"
}, {
value: "'Lucida Sans Unicode', 'Lucida Grande', sans-serif",
text: 'Lucida Grande'
}, {
value: "'Palatino Linotype', 'Book Antiqua', Palatino, serif",
text: 'Palatino Linotype'
}, {
value: "'Times New Roman', Times, serif",
text: 'Times New Roman'
}, {
value: "Georgia, serif",
text: "Georgia, serif"
}, {
value: "Tahoma, Geneva, sans-serif",
text: "Tahoma"
}, {
value: "'Comic Sans MS', cursive, sans-serif",
text: 'Comic Sans'
}, {
value: "Verdana, Geneva, sans-serif",
text: 'Verdana'
}, {
value: "Impact, Charcoal, sans-serif",
text: 'Impact'
}, {
value: "'Arial Black', Gadget, sans-serif",
text: 'Arial Black'
}, {
value: "'Trebuchet MS', Helvetica, sans-serif",
text: 'Trebuchet'
}, {
value: "'Courier New', Courier, monospace",
text: 'Courier New'
}, {
value: "'Brush Script MT', sans-serif",
text: 'Brush Script'
}];