diff --git a/src/packages/plg_content_mokoog/media/css/preview.css b/src/packages/plg_content_mokoog/media/css/preview.css new file mode 100644 index 0000000..b5d74a9 --- /dev/null +++ b/src/packages/plg_content_mokoog/media/css/preview.css @@ -0,0 +1,104 @@ +/** + * @package MokoOpenGraph + * @subpackage plg_content_mokoog + * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved. + * @license GPL-3.0-or-later + */ + +.mokoog-preview-wrapper { + margin: 15px 0; + padding: 15px; + background: #f8f9fa; + border-radius: 8px; + border: 1px solid #dee2e6; +} + +.mokoog-preview-heading { + margin: 0 0 12px; + font-size: 14px; + color: #666; +} + +.mokoog-platform-label { + display: block; + color: #999; + text-transform: uppercase; + font-size: 11px; + font-weight: 600; + margin-top: 16px; + margin-bottom: 4px; +} + +.mokoog-platform-label:first-of-type { + margin-top: 0; +} + +.mokoog-card { + overflow: hidden; + max-width: 500px; + background: #fff; +} + +.mokoog-card-fb { + border: 1px solid #ddd; + border-radius: 3px; +} + +.mokoog-card-tw { + border: 1px solid #cfd9de; + border-radius: 16px; +} + +.mokoog-card-img { + height: 260px; + background: #e4e6eb center / cover no-repeat; +} + +.mokoog-card-body { + padding: 10px 12px; + border-top: 1px solid #ddd; +} + +.mokoog-card-tw .mokoog-card-body { + border-top-color: #cfd9de; +} + +.mokoog-card-domain { + font-size: 11px; + color: #65676b; + text-transform: uppercase; +} + +.mokoog-card-tw .mokoog-card-domain { + font-size: 13px; + text-transform: none; + margin-top: 4px; +} + +.mokoog-card-title { + font-size: 16px; + font-weight: 600; + color: #1d2129; + margin: 3px 0 2px; + line-height: 1.3; +} + +.mokoog-card-tw .mokoog-card-title { + font-size: 15px; + font-weight: 700; + color: #0f1419; +} + +.mokoog-card-desc { + font-size: 14px; + color: #65676b; + line-height: 1.4; + max-height: 2.8em; + overflow: hidden; +} + +.mokoog-card-tw .mokoog-card-desc { + font-size: 15px; + color: #536471; + margin-top: 2px; +} diff --git a/src/packages/plg_content_mokoog/media/joomla.asset.json b/src/packages/plg_content_mokoog/media/joomla.asset.json new file mode 100644 index 0000000..340aa7a --- /dev/null +++ b/src/packages/plg_content_mokoog/media/joomla.asset.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json", + "name": "plg_content_mokoog", + "version": "01.00.00", + "description": "MokoOpenGraph Content Plugin Assets", + "license": "GPL-3.0-or-later", + "assets": [ + { + "name": "plg_content_mokoog.preview", + "type": "style", + "uri": "plg_content_mokoog/css/preview.css" + }, + { + "name": "plg_content_mokoog.preview", + "type": "script", + "uri": "plg_content_mokoog/js/preview.js", + "dependencies": ["core"] + } + ] +} diff --git a/src/packages/plg_content_mokoog/media/js/preview.js b/src/packages/plg_content_mokoog/media/js/preview.js new file mode 100644 index 0000000..62e8925 --- /dev/null +++ b/src/packages/plg_content_mokoog/media/js/preview.js @@ -0,0 +1,170 @@ +/** + * @package MokoOpenGraph + * @subpackage plg_content_mokoog + * @author Moko Consulting + * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved. + * @license GPL-3.0-or-later + * + * Live social sharing preview for article/menu item editor. + */ +document.addEventListener('DOMContentLoaded', function () { + 'use strict'; + + var fields = { + ogTitle: document.getElementById('jform_mokoog_og_title'), + ogDesc: document.getElementById('jform_mokoog_og_description'), + ogImage: document.getElementById('jform_mokoog_og_image'), + articleTitle: document.getElementById('jform_title'), + metaDesc: document.getElementById('jform_metadesc') + }; + + // Find the mokoog fieldset and insert preview after it + var fieldset = document.querySelector('[data-showon-id="mokoog"]') || + document.getElementById('attrib-mokoog') || + document.querySelector('fieldset.mokoog') || + document.querySelector('[id*="mokoog"]'); + + if (!fieldset) { + return; + } + + // Build preview DOM safely (no innerHTML with user data) + var preview = document.createElement('div'); + preview.id = 'mokoog-preview'; + + var wrapper = document.createElement('div'); + wrapper.className = 'mokoog-preview-wrapper'; + + var heading = document.createElement('h4'); + heading.className = 'mokoog-preview-heading'; + heading.textContent = 'Social Sharing Preview'; + wrapper.appendChild(heading); + + // Facebook preview card + var fbLabel = document.createElement('small'); + fbLabel.className = 'mokoog-platform-label'; + fbLabel.textContent = 'Facebook'; + wrapper.appendChild(fbLabel); + + var fbCard = document.createElement('div'); + fbCard.className = 'mokoog-card mokoog-card-fb'; + + var fbImg = document.createElement('div'); + fbImg.id = 'mokoog-fb-img'; + fbImg.className = 'mokoog-card-img'; + fbCard.appendChild(fbImg); + + var fbBody = document.createElement('div'); + fbBody.className = 'mokoog-card-body'; + + var fbDomain = document.createElement('div'); + fbDomain.id = 'mokoog-fb-domain'; + fbDomain.className = 'mokoog-card-domain'; + fbBody.appendChild(fbDomain); + + var fbTitle = document.createElement('div'); + fbTitle.id = 'mokoog-fb-title'; + fbTitle.className = 'mokoog-card-title'; + fbBody.appendChild(fbTitle); + + var fbDesc = document.createElement('div'); + fbDesc.id = 'mokoog-fb-desc'; + fbDesc.className = 'mokoog-card-desc'; + fbBody.appendChild(fbDesc); + + fbCard.appendChild(fbBody); + wrapper.appendChild(fbCard); + + // Twitter preview card + var twLabel = document.createElement('small'); + twLabel.className = 'mokoog-platform-label'; + twLabel.textContent = 'Twitter / X'; + wrapper.appendChild(twLabel); + + var twCard = document.createElement('div'); + twCard.className = 'mokoog-card mokoog-card-tw'; + + var twImg = document.createElement('div'); + twImg.id = 'mokoog-tw-img'; + twImg.className = 'mokoog-card-img'; + twCard.appendChild(twImg); + + var twBody = document.createElement('div'); + twBody.className = 'mokoog-card-body'; + + var twTitle = document.createElement('div'); + twTitle.id = 'mokoog-tw-title'; + twTitle.className = 'mokoog-card-title'; + twBody.appendChild(twTitle); + + var twDesc = document.createElement('div'); + twDesc.id = 'mokoog-tw-desc'; + twDesc.className = 'mokoog-card-desc'; + twBody.appendChild(twDesc); + + var twDomain = document.createElement('div'); + twDomain.id = 'mokoog-tw-domain'; + twDomain.className = 'mokoog-card-domain'; + twBody.appendChild(twDomain); + + twCard.appendChild(twBody); + wrapper.appendChild(twCard); + + preview.appendChild(wrapper); + fieldset.parentNode.insertBefore(preview, fieldset.nextSibling); + + var domain = window.location.hostname; + + function updatePreview() { + var title = (fields.ogTitle && fields.ogTitle.value) || + (fields.articleTitle && fields.articleTitle.value) || 'Page Title'; + var desc = (fields.ogDesc && fields.ogDesc.value) || + (fields.metaDesc && fields.metaDesc.value) || 'Page description will appear here...'; + var img = ''; + + if (fields.ogImage) { + img = fields.ogImage.value; + } + + if (title.length > 65) title = title.substring(0, 62) + '...'; + if (desc.length > 160) desc = desc.substring(0, 157) + '...'; + + // Facebook + document.getElementById('mokoog-fb-title').textContent = title; + document.getElementById('mokoog-fb-desc').textContent = desc; + document.getElementById('mokoog-fb-domain').textContent = domain; + var fbImgEl = document.getElementById('mokoog-fb-img'); + if (img) { + fbImgEl.style.backgroundImage = 'url(' + encodeURI(img) + ')'; + fbImgEl.style.display = ''; + } else { + fbImgEl.style.display = 'none'; + } + + // Twitter + document.getElementById('mokoog-tw-title').textContent = title; + document.getElementById('mokoog-tw-desc').textContent = desc; + document.getElementById('mokoog-tw-domain').textContent = domain; + var twImgEl = document.getElementById('mokoog-tw-img'); + if (img) { + twImgEl.style.backgroundImage = 'url(' + encodeURI(img) + ')'; + twImgEl.style.display = ''; + } else { + twImgEl.style.display = 'none'; + } + } + + Object.values(fields).forEach(function (el) { + if (el) { + el.addEventListener('input', updatePreview); + el.addEventListener('change', updatePreview); + } + }); + + if (fields.ogImage) { + var observer = new MutationObserver(updatePreview); + observer.observe(fields.ogImage, { attributes: true, attributeFilter: ['value'] }); + } + + updatePreview(); +}); diff --git a/src/packages/plg_content_mokoog/mokoog.xml b/src/packages/plg_content_mokoog/mokoog.xml index 651e9ba..bb64e27 100644 --- a/src/packages/plg_content_mokoog/mokoog.xml +++ b/src/packages/plg_content_mokoog/mokoog.xml @@ -27,6 +27,12 @@ language + + joomla.asset.json + js + css + + language/en-GB/plg_content_mokoog.ini language/en-GB/plg_content_mokoog.sys.ini diff --git a/src/packages/plg_content_mokoog/src/Extension/MokoOGContent.php b/src/packages/plg_content_mokoog/src/Extension/MokoOGContent.php index 3d70565..1752055 100644 --- a/src/packages/plg_content_mokoog/src/Extension/MokoOGContent.php +++ b/src/packages/plg_content_mokoog/src/Extension/MokoOGContent.php @@ -71,6 +71,12 @@ final class MokoOGContent extends CMSPlugin implements SubscriberInterface Form::addFormPath($formPath); $form->loadFile('mokoog', false); + // Load live preview assets + $wa = $this->getApplication()->getDocument()->getWebAssetManager(); + $wa->getRegistry()->addRegistryFile('media/plg_content_mokoog/joomla.asset.json'); + $wa->useStyle('plg_content_mokoog.preview'); + $wa->useScript('plg_content_mokoog.preview'); + // If editing an existing item, load saved OG data $id = 0;