Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve support for snippets throughout Winter CMS #36

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,35 @@ public function boot()
Classes\Page::class,
];
});

BaseBackendController::extend(function ($controller) {
$user = BackendAuth::getUser();
if (!$user || !$user->hasAccess('winter.pages.access_snippets')) {
return;
}

// Add the AJAX handlers required for snippet inspector properties
// to function on all backend controllers
$controller->addDynamicMethod('onGetInspectorConfiguration', function() {
return (new StaticPage)->onGetInspectorConfiguration();
});
$controller->addDynamicMethod('onGetSnippetNames', function() {
return (new StaticPage)->onGetSnippetNames();
});
$controller->addDynamicMethod('onInspectableGetOptions', function() {
return (new StaticPage)->onInspectableGetOptions();
});

FroalaFormWidget::extend(function ($widget) {
// Adds default base CSS/JS for snippets
$widget->addCss('/plugins/winter/pages/assets/css/pages.css', 'Winter.Pages');
$widget->addJs('/plugins/winter/pages/assets/js/pages-page.js', 'Winter.Pages');
$widget->addJs('/plugins/winter/pages/assets/js/pages-snippets.js', 'Winter.Pages');

// Adds custom assets for the Froala snippet button
$widget->addJs('/plugins/winter/pages/assets/js/froala-snippets.js', 'Winter.Pages');
});
});
}

/**
Expand All @@ -236,7 +265,8 @@ public function registerMarkupTags(): array
{
return [
'filters' => [
'staticPage' => ['Winter\Pages\Classes\Page', 'url']
'staticPage' => ['Winter\Pages\Classes\Page', 'url'],
'parseSnippets' => ['Winter\Pages\Classes\Snippet', 'parse'],
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need documentation for this filter

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LukeTowers I think we should use a modified version of the original readme.md file
ref. https://github.com/inetis-ch/oc-richeditorsnippets-plugin

Do you have a suggestion on where to integrate this content ?

]
];
}
Expand Down
132 changes: 132 additions & 0 deletions assets/js/froala-snippets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
(function ($) {
// Adds snippets to the default Froala buttons
// Places it after the quote button to keep dropdowns together
$.wn.richEditorButtons.splice(3, 0, 'snippets');

// Define a dropdown button.
$.FroalaEditor.RegisterCommand('snippets', {
// Button title.
title: 'Snippets',

// Mark the button as a dropdown.
type: 'dropdown',

// Specify the icon for the button.
// If this option is not specified, the button name will be used.
icon: '<i class="icon-newspaper-o"></i>',

// The dropdown HTML
html: function() {
if (!$.wn.snippets) {
return '<div style="padding:10px;">No snippets are currently defined.</div>';
}

var html = '<ul class="fr-dropdown-list">';

$.each($.wn.snippets, function(i, snippet) {
html += '<li><a class="fr-command" data-cmd="snippets" data-param1="' + snippet.snippet + '" title="' + snippet.name + '">' + snippet.name + '</a></li>';
});

return html + '</ul>';
},

// Save the dropdown action into undo stack.
undo: true,

// Focus inside the editor before callback.
focus: true,

// Refresh the button state after the callback.
refreshAfterCallback: true,

// Callback.
callback: function (cmd, val, params) {
var options = $.wn.snippets[val];

if (options) {
// Get editor element. OC2's richeditor has 2 nested data-control=richeditor, we want the outer one
var $editor = this.$el.parents('[data-control="richeditor"]:not([data-richeditor-vue])');
mjauvin marked this conversation as resolved.
Show resolved Hide resolved

var $snippetNode = $('<figure contenteditable="false" data-inspector-css-class="hero">&nbsp;</figure>');

if (options.component) {
$snippetNode.attr({
'data-component': options.component,
'data-inspector-class': options.component
})

// If a component-based snippet was added, make sure that
// its code is unique, as it will be used as a component
// alias.

/*
// Init a new snippet manager

// Below code reattaches the inspector event, causing duplicate inspector options
// Until I can figure a solution, I have copied the code to this file...

var snippetManager = new $.wn.pages.snippetManager;
options.snippet = snippetManager.generateUniqueComponentSnippetCode(options.component, options.snippet, $editor.parent())
*/

options.snippet = generateUniqueComponentSnippetCode(options.component, options.snippet, $editor.parent());
}

$snippetNode.attr({
'data-snippet': options.snippet,
'data-name': options.name,
'tabindex': '0',
'draggable': 'true',
'data-ui-block': 'true'
})

$snippetNode.addClass('fr-draggable');

// Insert the content
this.figures.insert($snippetNode);
}

LukeTowers marked this conversation as resolved.
Show resolved Hide resolved
}
});

generateUniqueComponentSnippetCode = function(componentClass, originalCode, $pageForm) {
var updatedCode = originalCode,
counter = 1,
snippetFound = false

do {
snippetFound = false

$('[data-control="richeditor"] textarea', $pageForm).each(function() {
var $textarea = $(this),
$codeDom = $('<div>' + $textarea.val() + '</div>')

if ($codeDom.find('[data-snippet="'+updatedCode+'"][data-component]').length > 0) {
snippetFound = true
updatedCode = originalCode + counter
counter++

return false
}
})
LukeTowers marked this conversation as resolved.
Show resolved Hide resolved

LukeTowers marked this conversation as resolved.
Show resolved Hide resolved
} while (snippetFound)

return updatedCode
};


/**
* Because the pages-snippets.js is injected after the richeditor script, it will register its
* initialization hooks too late. Here we need to force initialization in order to work with forms
* that are displayed on page load (i.e. Winter.Blog).
*/
$(document).ready(function() {
var $editor = $('[data-control="richeditor"]:not([data-richeditor-vue])');

if ($.wn.pagesPage && !window.location.pathname.includes('winter/pages')) {
$.wn.pagesPage.snippetManager.initSnippets($editor);
}
});

LukeTowers marked this conversation as resolved.
Show resolved Hide resolved
})(jQuery);
LukeTowers marked this conversation as resolved.
Show resolved Hide resolved
Loading