### Install and Run Total.js CMS Locally Source: https://github.com/totaljs/cms/blob/master/readme.md This snippet details the steps to install and run the Total.js CMS locally. It requires Node.js and involves navigating to the CMS directory, installing dependencies using npm, and then starting the application either via an npm script or directly with the Node.js executable. ```javascript npm install npm run start ``` ```javascript node index.js ``` -------------------------------- ### Install Widget in Total.js CMS Source: https://github.com/totaljs/cms/blob/master/plugins/widgets/public/form.html This function handles the installation of a selected widget. It retrieves the widget's ID and name, then prompts the user for confirmation. Upon confirmation, it fetches the widget's content via AJAX and saves it using a Total.js API, updating the UI to reflect the installation. ```javascript exports.install = function(el) { var id = ATTRD(el); var item = exports.data.items.findItem('id', id); SETTER('approve/show', '@(Are you sure you want to install the "{0}" widget?)'.format(item.name.encode()), '"ti ti-cloud-download" @(Install)', function() { exports.ajax('GET {0}'.format(item.url), function(response) { exports.tapi('widgets\_save @showloading', { id: id, html: response }, function(response) { el.aclass('installed'); EMIT('refresh\_widgets @hideloading'); }); }); }); }; ``` -------------------------------- ### Deploy Total.js CMS with Docker Source: https://github.com/totaljs/cms/blob/master/readme.md This snippet shows how to deploy the Total.js CMS using Docker. It involves pulling the official CMS Docker image and then running a container, mapping the host port 8000 to the container's port 8000. ```bash docker pull totalplatform/cms docker run -p 8000:8000 totalplatform/cms ``` -------------------------------- ### Display Widget List in Total.js CMS Source: https://github.com/totaljs/cms/blob/master/plugins/widgets/public/form.html This snippet shows how to render a list of widgets using a Total.js template. It iterates through a collection of widget data, displaying the preview image, name, and installation status. The HTML structure includes attributes for identifying the widget and its installation state. ```html
{{ m.name }}
``` -------------------------------- ### CMS Editor: Initialization and State Setting Source: https://github.com/totaljs/cms/blob/master/public/cmseditor/index.html Handles the initial setup of the editor, including writing the basic HTML structure and managing the rendering process based on the editor's state. It also initializes history and clears temporary data. ```javascript self.setter = function(value, path, type) { if (init === 0) { init = 1; self.write('
'); return; } if (type === 'norender' || init != 2) return; // temporary.copypaste = null; temporary.copypasteparent = null; // Sets the current instance of editor to global variable temporary.history = []; backup.innerHTML = ''; undobutton.aclass('hidden'); iframe.aclass('invisible'); if (value) { var css = []; if (value.widgets) { if (value.widgets inst ``` -------------------------------- ### Render Widget List (HTML) Source: https://github.com/totaljs/cms/blob/master/public/cmseditor/widgets.html This HTML snippet conditionally renders a list of available widgets or a message indicating no widgets are present. It uses Total.js templating syntax to iterate through widget data, displaying a preview, name, and providing an 'install' action. ```html {{ if !value.length }}
@(The app doesn't contain any widgets)
{{ fi }} {{ foreach m in value }} {{ end }} ``` -------------------------------- ### Total.js CMS: Iframe Toolbar Copy/Paste Functionality Source: https://github.com/totaljs/cms/blob/master/public/cmseditor/index.html This snippet indicates the start of a function related to copy-paste functionality within the iframe toolbar. It likely prepares elements for copying or pasting operations. ```javascript self.iframe_toolbar_copypaste = function() { var elements = self.iframe_toolba ``` -------------------------------- ### Search Widgets in Total.js CMS Source: https://github.com/totaljs/cms/blob/master/plugins/widgets/public/form.html This function implements a search feature for widgets using the Total.js spotlight component. It allows users to type a query, which is then used to filter the list of widgets. Matching widgets are displayed, and selecting one triggers the installation process. ```javascript exports.search = function() { var model = exports.data; var opt = {}; opt.id = 'widgetsimport'; opt.search = function(q, next) { q = q.toSearch(); var arr = []; for (var m of model.items) { if (m.search.indexOf(q) !== -1) arr.push(m); } next(arr.take(30)); }; opt.callback = function(item) { exports.install(item); }; SETTER('spotlight/show', opt); }; ``` -------------------------------- ### Iframe DOM Manipulation Helpers Source: https://github.com/totaljs/cms/blob/master/public/cmseditor/index.html Provides utility functions to interact with the iframe's content, including finding elements, accessing the document and window, and getting the parent container of a target element. ```javascript self.iframe_body = function() { return iframe.contents(); }; self.iframe_find = function(selector) { return iframe.contents().find(selector); }; self.iframe_document = function() { return self.iframe_window().document; }; self.iframe_window = function() { return iframe[0].contentWindow; }; self.iframe_container = function(max) { if (target.hclass('CMS_widget') || target.hclass('CMS_widgets')) return target; var parent = target.parent(); for (var i = 0; i < max; i++) { if (parent.hclass('CMS_widget') || parent.hclass('CMS_widgets')) return parent; parent = parent.parent(); } return null; }; ``` -------------------------------- ### Handle CMS Panel Click Events for Widget Operations Source: https://github.com/totaljs/cms/blob/master/public/cmseditor/index.html This snippet manages click events on span elements within the CMS panel. It triggers various actions based on the 'name' attribute of the clicked element, including hiding UI components, generating widget configurations, getting source code, selecting widgets, manipulating widget classes (CMS_mh, CMS_mv), copying, pasting, and reordering widgets. ```javascript body.find('#CMS_panel').on('click', 'span', function(e) { e.preventDefault(); e.stopPropagation(); var el = $(this); if (el.hclass('CMS_panel_disabled') || locked) return; var hide = function() { body.find('#CMS_panel').find('[data-name="hide"]').trigger('click'); }; var name = el.attrd('name'); var tmp; SETTER('!colorpicker/hide', true); SETTER('!icons/hide', true); SETTER('!datepicker/hide', true); SETTER('!directory/hide', true); switch (name) { case 'generate': var toolbar = self.iframe_toolbar(); var t = temporary.wrap || target; var opt = {}; var offset = toolbar.position(); var editor = self.element.offset(); var viewbox = self.find('ui-component[name="viewbox"]').component(); opt.x = (editor.left + offset.left) - viewbox.scrollbar.scrollLeft(); opt.y = (editor.top + offset.top + 46) - viewbox.scrollbar.scrollTop(); opt.element = t; opt.config = self.widget_config_parse(t); opt.isimage = t[0].tagName === 'IMG'; opt.instance = self; opt.text = $(t).text(); if (opt.isimage) { var tw = t.attrd('cms-width'); var th = t.attrd('cms-height'); opt.imgdefined = tw != null || th != null; if (!opt.imgdefined) { tw = t.attr('width'); th = t.attr('height'); } opt.width = t[0].width; opt.height = t[0].height; opt.datawidth = tw; opt.dataheight = th; opt.datasize = t.attrd('cms-size'); } config.generate && self.EXEC(config.generate, opt); break; case 'sourcecode': var t = temporary.wrap || target; var opt = {}; opt.element = t; opt.config = self.widget_config_parse(t); config.widgetsource && self.EXEC(config.widgetsource, opt); break; case 'selectwidget': var t = temporary.wrap || target; t && $(t).trigger('click'); break; case 'CMS_mh': case 'CMS_mv': var t = temporary.wrap || target; if (t.length) { t.tclass(name); el.tclass('CMS_is', t.hclass(name)); self.change(true); } break; case 'paste': target && self.close(); var clone = temporary.copypaste.clone(); clone = self.widget_config_clone(clone).rattr('contenteditable').rclass('CMS_selected').aclass('CMS_remove'); var parent = target.closest('.CMS_widget'); if (parent.parent()[0] === temporary.copypasteparent[0]) parent.after(clone); else temporary.copypasteparent.append(clone); self.autoresize(); self.change(true); break; case 'copy': temporary.copypaste = temporary.wrap.clone(); temporary.copypaste.rclass('CMS_operation CMS_selected'); self.iframe_toolbar_copypaste(); break; case 'up2': if (!target) { self.iframe_toolbar().hide(); return; } if (!target.hclass('CMS_repeat')) target = self.dom_parent_class('CMS_repeat'); if (!target.length) return hide(); var prev = target.prev(); if (!prev.length || !prev.hclass('CMS_repeat')) return hide(); tmp = prev.clone(); var n = target.clone(); prev.replaceWith(n); target.replaceWith(tmp); self.change(true); self.iframe_toolbar_move(); self.autoresize(); break; case 'down2': if (!target) { self.iframe_toolbar().hide(); return; } if (!target.hclass('CMS_repeat')) target = self.dom_parent_class('CMS_repeat'); if (!target.length) return hide(); var next = target.next(); if (!next.length || !next.hclass('CMS_repeat')) return hide(); tmp = next.clone(); var n = target.clone(); next.replaceWith(n); target.replaceWith(tmp); self.change(true); self.iframe_toolbar_move(); self.autoresize(); break; case 'up': tmp = temporary.wrap.prev(); if (tmp.length) { tmp.before(temporary.wrap); self.iframe_toolbar_move(); } else hide(); self.change(true); break; case 'down': tmp = temporary.wrap.next(); if (tmp.length) { tmp.after(temporary.wrap); self.iframe_toolbar_move(); } else hide(); self.change(true); break; case 'hide': if (!target) { self.iframe_toolbar().hide(); return; } self.iframe_toolbar().hide(); self.close(); self.check(target); target.rattr('contenteditable'); body.find('.CMS_selected').rclass('CMS_selected'); body.find('.CMS_selected_template').rclass('CMS_selected_templat ``` -------------------------------- ### Initialize Plugin and Load Widgets Source: https://github.com/totaljs/cms/blob/master/public/pages/editor.html Initializes the CMS plugin by loading widget configurations and setting up the preview link. It fetches widget data, parses JavaScript within widgets, sorts them, and updates the plugin's state. It also handles the visibility of the preview link based on the provided URL. ```javascript exports.init = function(opt) { meta = opt; exports.tapi('widgets_list', function(widgets) { for (var item of widgets) parsejs(item); widgets.quicksort('name'); exports.set({ name: opt.name, ready: true, html: { html: opt.html, layout: opt.layout, type: opt.type, widgets: widgets }} ); }); $('#{name}preview'.args(exports)).tclass('hidden', !opt.url).attr('href', opt.url || ''); }; function parsejs(item) { if (item.editor) item.js = new Function('$', item.editor.trim()); } ``` -------------------------------- ### Initialization Middleware and Routing Source: https://github.com/totaljs/cms/blob/master/views/admin.html Defines middleware for initialization, ensuring readiness of common data and user information before proceeding. It also sets up initial routing for the root path and the common root. ```javascript MIDDLEWARE('init', function(next) { WAIT(() => common.ready && W.user && common.breadcrumb && W.BREADCRUMB, next, null, 60000); }); ROUTE('/', function() { REDIRECT(common.root); }, 'init'); ROUTE(common.root, function() { var dashboard = common.plugins.findItem('id', 'dashboard'); if (dashboard && !dashboard.loaded) { REDIRECT(dashboard.url); } else { BREADCRUMB.add(); SET('common.page', 'welcome'); } }, 'init'); ``` -------------------------------- ### Get Historical Stats by Year and Names Source: https://github.com/totaljs/cms/blob/master/plugins/dashboard/public/index.html Retrieves historical statistics for a given year and a list of names. It processes data from `historystats` and formats it into an array of objects, each containing a name and its corresponding values for each month. ```javascript exports.getStats = function(year, names) { var stats = []; for (var a = 0; a < names.length; a++) { var arr = []; for (var b = 0; b < 12; b++) { var key = (b + 1) + '-' + year; var obj = historystats[key]; var item = {}; item.x = MONTHS[b].substring(0, 3); item.y = obj ? obj[names[a]] : 0; arr.push(item); } stats.push({ name: names[a], values: arr }); } return stats; }; ``` -------------------------------- ### Client-Side Initialization for Links and Navigation Source: https://github.com/totaljs/cms/blob/master/views/admin.html Initializes client-side functionalities for handling links and navigation editors. It fetches data using TAPI and processes it for sitemaps and navigation structures. ```javascript CLINIT('links', function(next) { TAPI('pages_links', response => next(FUNC.sitemap(response))); }, true); CLINIT('nav', function(next) { TAPI('nav_editor', next); }, true); ``` -------------------------------- ### Navigation and Platform Linking Source: https://github.com/totaljs/cms/blob/master/views/admin.html Handles navigation based on user authentication and platform status. It displays links to the open platform or the main website. ```javascript @{if user.openplatform} [](@{user.openplatform} "@(Browse modules)")@{CONF.name} @{else} [](/ "@(Website)")@{CONF.name} @{fi} ``` -------------------------------- ### Initialize CMS Plugin Source: https://github.com/totaljs/cms/blob/master/public/forms/code.html Initializes the CMS plugin with provided options, setting the content body and type. It also stores callback functions for later use. ```javascript exports.init = function(opt, callback) { exports.set({ content: { body: opt.html || opt.code || opt.body || '', type: opt.type || 'clientside' }}); meta = opt; if (callback) meta.callback = callback; }; ``` -------------------------------- ### CMS Layout and Meta Configuration Source: https://github.com/totaljs/cms/blob/master/views/admin.html Sets up the basic layout, title, user-specific styles, and imports necessary scripts and stylesheets for the CMS. It also includes a drag-and-drop area for files. ```javascript @{layout('')} @{title(config.name)} @{if user.color}:root{--color:@{user.color};} @{fi} @{import('meta', 'head', 'default.js + func.js', 'default.css', 'favicon.ico')} @(Drag & Drop files here) ``` -------------------------------- ### CMS Environment and Common Variables Initialization Source: https://github.com/totaljs/cms/blob/master/views/admin.html Initializes the CMS environment, sets up common variables like client ID, API endpoints, and redirects. It also injects an openplatform token into API requests. ```javascript ENVIRONMENT('cms'); var user = null; var common = {}; common.breadcrumb = []; common.clientid = GUID(5) + Date.now().toString(36); common.name = document.title; common.openplatform = NAV.query.openplatform || ''; common.plugins = PARSE('#pluginsdata'); common.api = common.root = '@{CONF.$api}'; common.redirect = REDIRECT; ENV('indentation', 201); ENV('margin', 60); DEF.fallback = '@{#}/cdn/j-{0}.html'; DEF.versionhtml = '@{CONF.version}'; DEF.languagehtml = '@{user.language}'; // Injects Token to every API request (function() { var openplatform = NAV.query.openplatform || ''; if (openplatform) { var hostname = openplatform.substring(0, openplatform.indexOf('/', 10)); openplatform = '?openplatform=' + encodeURIComponent(openplatform); } common.ready = true; DEF.api = common.api + openplatform; common.openplatform = openplatform; $('body').rclass('invisible', 200); })(); NAV.clientside('.jR'); if (W.top !== W && common.openplatform) NAV.custom(); REDIRECT = function(url) { if (url.charAt(0) !== '.' && url.substring(0, common.root.length) !== common.root) url = common.root + url.substring(1); common.redirect(url); }; ``` -------------------------------- ### Total.js CMS Widget Styling Source: https://github.com/totaljs/cms/blob/master/public/widget.txt Applies basic styling to a Total.js CMS widget. The CSS class `.CLASS` is automatically assigned by the framework, allowing for custom styling of the widget's container. This example adds a border and bottom margin. ```css /* The class is assigned automatically */ .CLASS { border: 1px solid #E0E0E0; margin-bottom: 32px; } ``` -------------------------------- ### Common Plugin Initialization and Exports Source: https://github.com/totaljs/cms/blob/master/views/admin.html Initializes common plugin functionalities, including sorting, routing, and handling file drops. It exports functions for refreshing data, redirecting, and logging out. ```javascript PLUGIN('common', function(exports) { var model = exports.model; (function() { model.plugins.quicksort('position'); model.plugins.forEach(function(plugin) { plugin.url = model.root + plugin.id + '/'; if (!plugin.hidden) { ROUTE(plugin.url, function() { plugin.loaded = true; exports.set('page', 'plugin' + plugin.id); }, 'init'); plugin.routes && plugin.routes.forEach(item => ROUTE('@{#}' + item.url, () => exports.set('page', 'plugin' + plugin.id + item.html), 'init')); } plugin.import && $(document.body).append(''.format('@{#}/\_' + plugin.id + '/' + plugin.import, plugin.id)); }); })(); exports.refresh = function() { TAPI('account', 'user'); }; exports.redirect = function(el) { REDIRECT(el.attrd('url')); }; exports.navigation = function(el) { REDIRECT('/'); }; exports.dropfiles = function(e) { var plugin = model.form3 || model.form2 || model.form || model.page; var tmp = PLUGINS[plugin]; if (tmp && tmp.dropfiles) tmp.dropfiles(e); }; exports.dropcheck = function(e) { if (model.form3 === 'formfiles' || model.page === 'pluginfiles') return true; var plugin = model.form3 || model.form2 || model.form || model.page; var tmp; if (plugin) { tmp = PLUGINS[plugin]; if (tmp && tmp.dropcheck) return tmp.dropcheck(e); } return false; }; exports.logout = function() { exports.ajax('GET @{#}{0}logout/ ERROR'.format(model.root), () => location.href = model.root); }; ON('service', function(counter) { if (counter % 5 === 0) exports.refresh(); }); ON('ready', exports.refresh); }); ``` -------------------------------- ### Widget Management Plugin (JavaScript) Source: https://github.com/totaljs/cms/blob/master/public/cmseditor/widgets.html This JavaScript plugin provides core functionality for widget management in Total.js CMS. It includes methods for reloading the widget list, installing a selected widget, importing new widgets, and implementing a search feature with a spotlight interface. ```javascript PLUGIN(function(exports) { exports.reload = function(com) { exports.set('search', ''); }; exports.install = function(el) { var id = ATTRD(el); var model = exports.data; var item = model.items.findItem('id', id); if (item) model.next(item); NUL('cmseditor.form'); }; exports.import = function() { SET('common.form2', 'formwidgets'); }; exports.search = function() { var model = exports.model; var opt = {}; opt.id = 'cmswidgetimport'; opt.search = function(q, next) { q = q.toSearch(); var arr = []; for (var m of model.items) { if (!m.search) m.search = m.name.toSearch(); if (m.search.indexOf(q) !== -1) arr.push({ id: m.id, name: m.name, html: '{1}'.format(m.preview, m.name.encode()) }); } next(arr.take(30)); }; opt.callback = function(item) { exports.install(item); }; SETTER('spotlight/show', opt); }; }); ``` -------------------------------- ### HTML Structure with UI Components Source: https://github.com/totaljs/cms/blob/master/plugins/layouts/public/template.txt This HTML snippet outlines the basic structure of the Total.js CMS page. It includes placeholders for UI components like 'exec' and 'imageviewer', a header with a logo and navigation, a content area with breadcrumbs, and a footer. ```HTML
``` -------------------------------- ### Refresh Widget List in Total.js CMS Source: https://github.com/totaljs/cms/blob/master/plugins/widgets/public/form.html This JavaScript function demonstrates how to refresh the list of available widgets in Total.js CMS. It fetches widget data from a CDN, processes it, and then updates the UI. The function also handles checking the installation status of each widget by comparing it with the response from a separate API endpoint. ```javascript exports.refresh = function() { exports.ajax('GET https://cdn.totaljs.com/cms/db.json', function(response) { var items = PARSE(response); exports.tapi('widgets\_list?list=1', function(response) { for (var item of items) { item.html = '{1}'.format(item.preview, item.name.encode()); item.search = item.name.toSearch(); item.imported = !!response.findItem('id', item.id); } items.quicksort('name'); exports.set('items', items); }); }); }; ``` -------------------------------- ### UI Component Rendering for Pages and Routes Source: https://github.com/totaljs/cms/blob/master/views/admin.html Renders UI components for pages and their associated routes. It dynamically sets component configurations, URLs, and visibility based on plugin IDs and route definitions. ```html {{ foreach m in value }} {{ if !m.hidden }} {{ if m.routes }} {{ foreach route in m.routes }} {{ end }} {{ fi }} {{ fi }} {{ end }} ``` -------------------------------- ### Total.js CMS Plugin Initialization and Refresh Source: https://github.com/totaljs/cms/blob/master/plugins/pages/public/index.html Initializes the plugin and defines the refresh functionality. The refresh function fetches layout and page data, processes it to build a sitemap and hierarchical structure, and updates the UI with the processed data. It also handles visual feedback by adding a spinning icon during the refresh process. ```javascript PLUGIN(function(exports) { exports.reload = function() { BREADCRUMB.add('@(Pages)', NAV.url); exports.refresh(); }; exports.refresh = function(el) { el && el.find('i').aclass('ti-spin').rclass('ti-spin', 800); exports.tapi('layouts\_list ERROR', function(layouts) { exports.set('layouts', layouts); exports.tapi('pages\_list ERROR', function(response) { var arr = []; for (var item of response) { if (item.parentid === item.id) item.parentid = ''; item.breadcrumb = item.name.encode(); item.search = item.name; item.layout = layouts.findItem('id', item.layoutid); if (!item.pinned) item.pinned = false; if (!item.dtupdated) item.dtupdated = item.dtcreated; if (item.parentid) { var parent = response.findItem('id', item.parentid); if (parent) { if (parent.children) parent.children.push(item); else parent.children = [item]; } else item.parentid = ''; parent = item; while (true) { parent = response.findItem('id', parent.parentid); if (parent) { if (parent.parentid) { item.breadcrumb = '' + parent.name.encode() + ' / ' + item.breadcrumb; item.search = parent.name + ' / ' + item.search; } else break; } else break; } } } exports.set('sitemap', FUNC.sitemap(response)); for (var item of response) { if (!item.parentid) arr.push(item); } response.quicksort('pinned\_desc, dtcreated\_desc'); exports.set('items', response, 'noscroll'); exports.set('sitemap', FUNC.sitemap(response)); exports.set('items2', arr); }); }); }; exports.menu = function(el) { var model = exports.model; var opt = {}; opt.element = el; opt.align = 'right'; opt.items = []; opt.items.push({ id: 'remove', name: '@(Remove selected ({0}x))'.format(model.checked.length), icon: 'ti ti-trash red' }); opt.callback = function(item) { if (item.id === 'remove') { SETTER('approve/show', '@(Are you sure you want to remove selected ({0}x) pages?)'.format(model.checked.length), '"ti ti-trash" @(Clear)', function() { SETTER('loading/show'); model.checked.wait(function(item, next) { exports.tapi('pages\_remove', { id: item.id }, next); }, function() { SETTER('loading/hide'); exports.refresh(); }); }); return; } }; SETTER('menu/show', opt); }; exports.editor = function(el, e) { if (!el) return; if (e && e.target && e.target.tagName === 'A') return; var id = ATTRD(el); REDIRECT('/admin/pages/{0}/'.format(id)); }; exports.remove = function(el) { var items = exports.data.items; var id = ATTRD(el); var data = items.findItem('id', id); SETTER('approve/show', '@(Are you sure you want to remove the "name" page?)'.arg(data, 'escape'), '"ti ti-trash" @(Remove)', function() { exports.tapi('pages\_remove ERROR', { id: id }, () => exports.refresh()); }); }; exports.edit = function(el) { var id = ATTRD(el); exports.tapi('pages\_read @showloading ERROR', { id: id }, function(response) { SET('formpage @reset @hideloading', response); SET('\*form', 'formpage'); }); }; exports.code = function(el) { var id = ATTRD(el); exports.tapi('pages\_html ERROR', { id: id }, function(response) { var opt = {}; opt.body = response.html; opt.callback = function(value, hide) { var model = {}; model.id = id; model.html = value; exports.tapi('pages\_save\_html', model, hide); }; FUNC.code(opt); }); }; exports.options = function(name, row, el) { if (name === 'edit') { exports.edit(row); return; } if (name === 'remove') { exports.remove(row); return; } var model = exports.model; var items = model.items; }; }); ``` -------------------------------- ### Total.js CMS Widget Meta and Configuration Source: https://github.com/totaljs/cms/blob/master/public/widget.txt Defines the essential meta-information and configuration for a Total.js CMS widget. This includes the widget's ID, name, author, version, a preview image, and a configuration object, typically used for storing URLs or other settings. ```javascript // Meta exports.id = 'yourwidget'; exports.name = 'Widget'; exports.author = 'Total.js'; exports.version = '1'; exports.preview = 'data:image/gif;base64,R0lGODdhLAHIANUAAP////39/eHh4czMzLa2tvr6+vb29rW1tejo6Lu7u7e3t97e3t3d3crKyr+/v/X19fz8/MbGxrq6uvDw8Nra2s7Ozufn59fX1/f399XV1b6+vsfHx8XFxePj49DQ0MDAwPv7+/j4+NnZ2fn5+e/v78jIyO7u7sHBwcnJydvb2/T09Nzc3MPDw/Pz8729vbi4uMvLy+Xl5by8vAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAALAHIAAAG/0CAcEgsGo/IpHLJbDqf0Kh0Sq1ar9isdsvter/gsHhMLpvP6LR6zW673/C4fE6v2+/4vH7P7/v/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn61Q8WFB4bPiR4QYDAiwQfNnigYOHBvk0GBAxIcKCixYsYLSYYIMDAw0kFBETISLIkxggCCnxsNKGCApMwYyqoMGElIhMNYurc2cCEzf9BKnLuHKqzgYqffgKIeEm0KUwFIgIg1UPCgdOrMR2QmHpnAQGsYE0SWMB1DogBYdOaHACi7JsQLNTKJckihFs2D6zO3XvRgcO7aFpQ5Eu4YoIWgM0YcFG48QEXHhOLGXHCseMTIySDCcDBsmUOUjV3yeDZcwbRXBCULo0AdRYDElZ7lhDZdRUYskvDsF1FdW7WvKVA0PC7tAYIwaGkKL46RXInEGIzn438+RIG01czsK4kgIzspWWE5m4kBvjVMcgfQXG+NAr1RTB8bW+ZAAb4Q7DT97wdP4CR+1kWgX8FzBdgYwSoBJ9vBzrWGnwXNGjZBfiVIKFjJeA32IWEJQD/XwEcOqYgdxOE2FhN5DFo4l4PctfBioR1oN4CMPJFFnkr1LjXCupRoONcFKiX449q8UgejUSmdaOLSaYlY4pNhtWidSVGiRWK3IFo5VUjcrfhljt5CJ+FYA6VIYRlDkXhgmnuNGWWBrZJUoL+ASgnSQP6p9+dGfWHn3x8YmSff0KwF6hF7xEKgHmHVpSeot41Kp6iQuzJp5+KRheoBNVRCsByfDrnqRDD3XncqEOoWOabo+KW5m6oEgFbmbTFWoSqTbJqK2lWnmarEZxFCdqvR1CWJGbEIrHYj5Alm4RgNR7mrBJ5rejXtEvAFWJd2DJx1oVsdeuEVwGOJS4UVdGnkNW5USjFFHNQjccuFEExZ9S8VuAkW0/4ZtHSu3zNhGW/WYRkp1oodUkwFxFNdNVGHS1sRj//BDRQQQcltFBDEnfs8ccghyzyyCSXbPLJKKes8sost+zyyzDHLPPMNNds880456zzzjz37PPPQAct9NBEF2300UgnrfTSTDft9NNQRy311FRXbfXVWGettSpBAAA7'; exports.config = { url: '' }; ``` -------------------------------- ### Total.js CMS Context Menu for File Insertion Source: https://github.com/totaljs/cms/blob/master/plugins/posts/public/form.html Defines a context menu for the Total.js CMS plugin to allow users to insert files. It specifies menu item properties and handles the selection of the 'Insert file' option, triggering a file form initialization and inserting the file URL. ```javascript exports.menu = function(e) { var opt = {}; opt.x = e.x; opt.y = e.y; opt.items = []; opt.items.push({ id: 'upload', name: '@(Insert file)', icon: 'far fa-cloud-upload' }); opt.callback = function(selected) { switch (selected.id) { case 'upload': SET('*form2', 'filesform'); EXEC(true, 'filesform/init', {}, function(item, hide) { SETTER('#cloudeditorpost/insert', item.url); hide(); }); break; } }; SETTER('menu/show', opt); }; ``` -------------------------------- ### Total.js CMS File Plugin Initialization and Refresh Source: https://github.com/totaljs/cms/blob/master/plugins/files/public/list.html Initializes the Total.js CMS file plugin and handles refreshing the file list. It fetches files, formats dimensions, filters by type (e.g., images), sorts by date, and updates the UI. Dependencies include Total.js API functions like `tapi` and `set`. ```javascript PLUGIN(function(exports) { var meta; var noscroll = false; exports.refresh = function() { exports.tapi('files_list', function(response) { for (var item of response) { item.dimension = (item.width && item.height ? (item.width + 'x' + item.height) : ''); } switch (meta.type) { case 'images': var tmp = { jpg: 1, png: 1, jpeg: 1, webp: 1, gif: 1, svg: 1 }; response = response.remove(n => !tmp[n.ext]); break; } response.quicksort('date_desc'); exports.set('search', ''); exports.set('items', response, noscroll ? 'noscroll' : undefined); noscroll = false; }); }; exports.init = function(opt, callback) { meta = opt; if (callback) meta.callback = callback; exports.refresh(); }; exports.submit = function(row, grid, row_el) { row.url = '/download/' + row.id + '.' + row.ext; meta.callback(row, () => NULL('common.form3')); }; exports.button = function(name, row) { if (name === 'rename') { var opt = {}; opt.value = row.name; opt.name = '@(Rename file)'; opt.callback = function(val) { noscroll = true; exports.tapi('files_rename ERROR', { id: row.id, name: val }, () => exports.refresh()); }; SETTER('prompt/show', opt); } }; exports.upload = function(e) { var opt = {}; if (e && !(e instanceof jQuery)) opt.files = e; opt.url = ENV('upload'); opt.multiple = true; opt.width = meta.width; opt.height = meta.height; opt.onlylarger = true; switch (meta.type) { case 'images': opt.accept = 'image/*'; break; } opt.callback = function(response, err) { exports.scope(); exports.refresh(); }; SETTER('fileuploader/upload', opt); }; exports.dropfiles = function(e) { exports.upload(e); }; }); ``` -------------------------------- ### Total.js CMS HTML Structure and Styling Source: https://github.com/totaljs/cms/blob/master/plugins/admin/login.html This snippet details the HTML structure and CSS styling for the Total.js CMS login page. It includes elements for layout, input fields, buttons, and error messages, along with associated styles for visual presentation. ```HTML @{layout('')} @{title(CONF.name)} @{import('meta', 'head', 'favicon.ico')} ``` ```CSS body { background-color: #F2F5FE; } .login { max-width: 300px; text-align: left; margin: 0 auto; width: 100%; } .login > div { background-color: #FFF; padding: 30px; border-radius: var(--radius); box-shadow: 0 0 20px rgba(0,0,0,0.1); } footer { font-size: 11px; color: #999; text-align: center; padding: 0 0 10px; } footer a { color: #777; } h1 { font-size: 20px; margin: 0 0 15px 0; padding: 0; } h1 i { margin-right: 8px; font-size: 30px; vertical-align: middle; } h2 { font-size: 16px; margin: 0 0 15px 0; padding: 0; font-weight: normal; color: #777; } button { width: 100%; border: 0; padding: 8px 10px; font-size: 14px; background-color: var(--color); color: #FFF; border-radius: var(--radius); font-weight: bold; outline: 0; } button:hover { opacity: 0.8; } button:disabled { background-color: #E0E0E0 !important; color: #999 !important; opacity: 1 !important; } .error { padding: 5px 0; color: red; } .alert { background-color: #fffad7; border: 1px solid #EDE8C8; padding: 15px; border-radius: 2px; color: #988e56; font-size: 12px; line-height: 14px; } .alert i { margin-right: 5px; } .kv { line-height: 17px; font-size: 12px; color: black; } .kv .value { margin-left: 85px; text-align: right; } .kv .key { float: left; width: 100px; } .kv > \* { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; } ```