UNPKG

sheercms

Version:

Sheer Cliff CMS is a simple and powerful content management system (CMS) for Node JS.

486 lines (431 loc) 18 kB
$(document).ready(function () { var pd = new PageDesigner(); pd.init(); }); function PageDesigner() { var self = this; self.init = function() { self.loadDesignerStyles(); self.loadToolbar(); }; self.loadDesignerStyles = function() { var head = document.getElementsByTagName('head')[0]; var link = document.createElement('link'); link.id = "designerStyles"; link.rel = 'stylesheet'; link.type = 'text/css'; link.href = '/cms/static/css/designer.css'; link.media = 'all'; head.appendChild(link); }; self.loadToolbar = function() { if ($("#DesignToolbar").length == 0) { //create the toolbar $("body").prepend('<div id="DesignToolbar"><div class="design-toolbar-loading">Loading designer toolbar...</div></div>'); } var contentId = $("#DesignerScript").attr("data-item"); if ($("#DesignToolbar").length > 0) { $("#DesignToolbar").designer({ contentId: contentId }); } }; } (function ($) { $.Designer = function (element, options) { // plugin's default options var defaults = { contentId: '' }; var plugin = this; plugin.settings = {}; //other variables var $element = $(element), // reference to the jQuery version of DOM element element = element // reference to the actual DOM element //CONSTRUCTOR plugin.init = function () { plugin.settings = $.extend({}, defaults, options); //show the dashed border when you hover over a field $(".design-field").hover(function () { $(this).addClass("design-hover"); }, function () { $(this).removeClass("design-hover"); }); //load the toolbar content $element.load('/cms/designer/toolbar', { contentId: plugin.settings.contentId }, function () { //on loaded var mainbar = $('#DesignToolbar').detach(); $('body').append(mainbar); //add margin to the body to push it down below the toolbar $("body").css({ "margin-top": "65px" }); updateLinks(); //figure out which mode to start in var bDesign = plugin.cmsCookieMode() === 'design'; setupPageMode(bDesign); setupContentEditables(); $element.find("a").on("click", function () { if ($(this).hasClass("disabled")) return false; var btnName = $(this).attr("data-cmd"); if (btnName) btnName = btnName.toLowerCase(); if (btnName == "design") { setupPageMode(true); } else if (btnName === 'preview') { var designMode = $(this).hasClass("selected"); setupPageMode(designMode); } else if (btnName === 'save') { plugin.save(); } else if (btnName === 'publish') { plugin.publish(); } else if (btnName === 'unpublish') { if (confirm('Are you sure you want to unpublish & remove this page from the live website?')) { plugin.unpublish(); } } else if (btnName === 'outline') { if ($(this).hasClass("selected")) { $(this).removeClass("selected"); $("body").removeClass("outline"); } else { $(this).addClass('selected'); $("body").addClass("outline"); } } else if (btnName === 'reload') { if (plugin.needsSaving() === true) { if (confirm('Are you sure you want to reload the page and lose any unsaved changes?')) { plugin.reloadPage(); } } else plugin.reloadPage(); } else if (btnName === 'exit') { plugin.exit(); } else { var cmd = $(this).attr("data-name"); plugin.execute(cmd); } }); }); } //PUBLIC METHODS plugin.save = function () { var data = getFieldData(false); if (!data) { setDesignerMessage("There are no changes to save!", true, false, 5000); } else { setDesignerMessage("Saving changes...", false, true); executeCommand("save", data); } }, plugin.publish = function () { var data = getFieldData(true); if (!data) { setDesignerMessage("There are no changes to publish!", true, false, 5000); } else { setDesignerMessage("Publishing changes...", false, true); executeCommand("publish", data); } }, plugin.unpublish = function () { setDesignerMessage("Removing page from live site...", false, true); executeCommand("unpublish"); }, plugin.execute = function (cmd) { setDesignerMessage("Processing...", false, true); $.post("/cms/design/command", { itemId: plugin.settings.itemId, command: cmd }, function (data) { if (data == "success") plugin.reloadPage(); else setDesignerMessage(data, true, false); }); }, plugin.reloadPage = function () { window.location.href = window.location.href; }, plugin.exit = function () { plugin.cmsCookieMode('live'); var status = plugin.designData('status'); if (status === "P" || status === "M") //published or modified plugin.reloadPage(); else //this page is not live, so just close the window window.close(); }, plugin.needsSaving = function() { return needsSaving(); }, plugin.cmsCookieMode = function(mode) { if (mode) { //set the mode $.cookie('cmsmode', mode, {path:'/'}); } else { //get the mode return $.cookie('cmsmode'); } }, plugin.designData = function(key, value) { if (key) { if (key.indexOf('data-') !== 0) key = 'data-' + key; var $this = $("#DesignData"); if (value) { //set the value $this.attr(key, value); } else { //get the value return $this.attr(key); } } }; //PRIVATE METHODS function setupContentEditables() { $('body').on('focus', '[contenteditable]', function() { var $this = $(this); $this.data('before', $this.html()); $this.addClass('design-editing'); return $this; }).on('blur keyup paste input', '[contenteditable]', function() { var $this = $(this); $this.removeClass('design-editing'); if ($this.data('before') !== $this.html()) { $this.data('before', $this.html()); $this.addClass('design-changed'); updateNeedsSavingLabel(); } return $this; }); $('[data-placeholder]').each(function() { var $this = $(this); checkPlaceholder($this); $this.on('focus', function() { var ph = $this.attr('data-placeholder'); if ($this.text() === ph) $this.html("<br>"); }).on('blur', function() { //see if we need to set the placeholder checkPlaceholder($(this)); }); }); } function checkPlaceholder(editable) { var ph = editable.attr('data-placeholder'); if (ph && ph.length > 0) { var isRich = editable.attr("data-rich") === 'true'; var val = isRich ? editable.html() : editable.text(); if (val.length === 0) editable.text(ph); } } function setupDesignEditors() { // This property tells CKEditor to not activate every element with contenteditable=true element. CKEDITOR.disableAutoInline = true; $(".design-field[data-rich='true']").each(function () { var element = $(this); var obj = element[0]; var editor = CKEDITOR.inline(obj, { /*customConfig: '/areas/cms/libraries/CKEditor/designer_config.js', filebrowserWindowWidth: 900, filebrowserWindowHeight: 700*/ }); editor.on('afterSetData', function() { element.addClass('design-changed'); updateNeedsSavingLabel(); }); //assign the editor as data on the dom element so we can access it later element.data("editor", editor); }); } function destroyEditors() { for (name in CKEDITOR.instances) { var editor = CKEDITOR.instances[name]; if (editor) { if (editor.element) $(editor.element).removeData("editor"); editor.destroy(); } } } function setStatusText(status) { //update the status code on the toolbar plugin.designData('status', status); var lbl = $("#DesignStatusLabel"); lbl.removeClass("design-status-new design-status-saved design-status-published design-status-modified design-status-deleted"); if (status == "N") //New lbl.addClass("design-status-new").text("New"); else if (status == "S") //Saved lbl.addClass("design-status-saved").text("Saved"); else if (status == "D") //Deleted lbl.addClass("design-status-deleted").text("Deleted"); else if (status == "P") //Published lbl.addClass("design-status-published").text("Published"); else if (status == "M") //Modified lbl.addClass("design-status-modified").text("Modified"); } function updateNeedsSavingLabel() { if (needsSaving() === true) $("#NeedsSavingLabel").addClass("needs-saving").text("Yes"); else $("#NeedsSavingLabel").removeClass("needs-saving").text("No"); } function saveCleanup() { $(".design-changed").removeClass("design-changed"); updateNeedsSavingLabel(); } function needsSaving() { if ($(".design-changed").length > 0) return true; else return false; } function updateLinks() { $("body").delegate("a", "click.sheercms", function () { if (!$(this).hasClass("design-link")) { if ($("body").hasClass("design")) //don't redirect to link's URL if we are in design mode return false; } }); } function setupPageMode(isDesign) { //set the cookie var cmsmode = isDesign ? 'design' : 'preview'; plugin.cmsCookieMode(cmsmode); if (isDesign) { //enable/disable main toolbar buttons $("#DesignToolbar").find("a").removeClass("selected").removeClass("disabled"); $("#DesignToolbar").find("a[data-cmd='preview']").removeClass("selected"); //tell the page we are in design mode (for css) $("body").removeClass("preview").addClass("design"); //mark all of the designable fields as editable $(".design-field").attr("contenteditable", true); setupDesignEditors(); } else { $("#DesignToolbar").find("a[data-cmd='preview']").addClass("selected"); //disable some buttons $("#DesignToolbar").find("a").each(function() { var cmd = $(this).attr("data-cmd"); if (cmd !== 'preview' && cmd !== 'exit') $(this).addClass("disabled").removeClass("selected"); }); //tell the page we are in preview mode (for css) $("body").removeClass("design").removeClass("outline").addClass("preview"); //mark all of the designable fields as NOT editable $(".design-field").attr("contenteditable", false); destroyEditors(); } } function getFieldData(allData) { var arr = new Array(); var selector = allData === true ? ".design-field" : ".design-changed"; $(selector).each(function () { var $this = $(this); var val = ""; var isRich = $this.attr("data-rich") === 'true'; //see if there is an editor associated with this field var editor = $this.data("editor"); if (editor) val = editor.getData(); else if (isRich) val = $this.html(); else val = $this.text(); if (val == $this.attr("data-placeholder")) val = ""; var obj = { itemId: $this.attr("data-item"), fieldName: $this.attr("data-field"), value: val }; arr.push(obj); }); if (arr.length === 0) return null; else { var d = { pageItemId: plugin.settings.contentId, fields: arr }; return d; } } function executeCommand(command, data, callback) { var url = "/cms/designer/command"; var sData = data ? JSON.stringify(data) : null; $.ajax({ type: "POST", url: url, data: { json: sData, command: command, contentId: plugin.settings.contentId } }).done(function (result, textStatus, jqXHR) { if (result) { if (result.success === true) saveCleanup(); setDesignerMessage(result.message, (result.success !== true), false, 5000); if (result.status) setStatusText(result.status); } callback(null, result); }) .fail(function (xhr, textStatus, errorThrown) { setDesignerMessage("Error executing the command!", true, false, 5000); console.error(xhr.responseText); callback(xhr.responseText); }); } /*=== Designer Message ===*/ var designerMsgTimeout = 0; function setDesignerMessage(msg, isError, persist, ms) { if (isError) $("#DesignMessage").addClass("design-error"); else $("#DesignMessage").removeClass("design-error"); $("#DesignMessage").text(msg); var dWidth = $(document).width(); var mWidth = $("#DesignMessage").width(); var left = (dWidth / 2) - (mWidth / 2); $("#DesignMessage").css("left", left).show(); clearTimeout(designerMsgTimeout); var msTimeout = ms ? ms : 5000; if (!persist) { designerMsgTimeout = setTimeout(function () { clearDesignerMessage(); }, msTimeout); } } function clearDesignerMessage() { $("#DesignMessage").fadeOut('slow'); } /*=== End of Designer Message ===*/ //CALL CONSTRUCTOR plugin.init(); }; // add the plugin to the jQuery.fn object $.fn.designer = function (options) { // iterate through the DOM elements we are attaching the plugin to return this.each(function () { // if plugin has not already been attached to the element if (undefined == $(this).data('designer')) { var plugin = new $.Designer(this, options); // in the jQuery version of the element // element.data('designer').publicMethod(arg1, arg2, ... argn) or // element.data('designer').settings.propertyName $(this).data('designer', plugin); } }); } }(jQuery));