Modifying the Wagtail publish dropdown (per app) - django

I'd like to reconfigure the default "Publish" menu. The default configuration is this:
I'd like to make Publish the default action, and move it to the top. I'd also like to remove Submit for Moderation, as our site has no current need for that feature.
Ideally, I'd love to be able to override the menu config on a per-app basis - we will likely have other sections of our site in the future where we want a different config.
Is this possible?

This isn't currently possible I'm afraid - the menu items are fixed in wagtailadmin/pages/create.html and edit.html.
This is possible as of Wagtail 2.4 using the register_page_action_menu_item hook, as per Yannic Hamann's answer. Additionally, Wagtail 2.7 (not released at time of writing) provides a construct_page_listing_buttons hook for modifying existing options.

You can add a new item to the action menu by registering a custom menu item with the help of wagtail hooks.
To do so create a file named wagtail_hooks.py within any of your existing Django apps.
from wagtail.core import hooks
from wagtail.admin.action_menu import ActionMenuItem
class GuacamoleMenuItem(ActionMenuItem):
label = "Guacamole"
def get_url(self, request, context):
return "https://www.youtube.com/watch?v=dNJdJIwCF_Y"
#hooks.register('register_page_action_menu_item')
def register_guacamole_menu_item():
return GuacamoleMenuItem(order=10)
Source
If you want to remove an existing menu item:
#hooks.register('construct_page_action_menu')
def remove_submit_to_moderator_option(menu_items, request, context):
menu_items[:] = [item for item in menu_items if item.name != 'action-submit']
The default button SAVE DRAFT is still hardcoded and therefore cannot be configured so easily. See here.

It seems it can't be done on server side without some monkey-patching.
However if you want it for yourself (or have access to computers of those who will publish) you can modify your browser instead.
Install Tampermonkey browser addon
Create new script with a content below
Change http://127.0.0.1:8000/admin/* to your wagtail admin panel url pattern
Save script and check admin panel
Result should look:
// ==UserScript==
// #name Wagtail: replace "Save draft" with "Publish"
// #match *://127.0.0.1:8000/admin/*
// #require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// ==/UserScript==
let $ = window.jQuery;
function modify() {
let draft = $("button.button-longrunning:contains('Save draft')");
let publish = $("button.button-longrunning:contains('Publish')");
if (draft.length && publish.length) {
swap(publish, draft);
}
};
function swap(a, b) {
a = $(a); b = $(b);
var tmp = $('<span>').hide();
a.before(tmp);
b.before(a);
tmp.replaceWith(b);
};
$(document).ready(function() {
setTimeout(function() {
try {
modify();
}
catch (e) {
console.error(e, e.stack);
}
}, 100);
});

Modifying the code above, these selectors works for every admin language:
let draft = $("button.button-longrunning.action-save");
let publish = $("button.button-longrunning[name='action-publish']");

Related

How to remember past searches for anonymous users

My application doesn't have user accounts, the users anonymously interact with it.
I want to be able to remember what a user has searched for previously without attaching it to their account (as they don't have one). How would I go about doing this?
Is cookies the answer I am looking for? If so, can you point me in the right direction.
Clarification: when the users clicks the search bar to search for something, I want to be able to display what that specific user has searched for in the past in a drop-down box.
you can use localStorage in this situation
There are code snippets which will help you (preliminarily add jQuery in you project for example in head of html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
). Just add it in your templates
//selector by id - #selector, by class - .selector, by tag - selector
function getItemsFromLS(){
return JSON.parse(localStorage.getItem('search'))
}
function addNewItemToLS(item){
localStorage.setItem('search',JSON.stringify([...getItemsFromLS(), item]))
}
$(document).ready(function(){
//if there are no storage create it
if(!localStorage.getItem('search')){
localStorage.setItem('search', JSON.stringify([]))
}
//click on the search button
$('search-button-selector').click(function(){
//get item form input
let newItem = $('input-type-selector').val()
addNewItemToLS(newItem)
})
//show items on focus of search bar
$('input-type-selector').focus(function(){
let searchItems = []
$(this).change(function(){
searchItems = getItemsFromLS().filter((item)=>item.includes($(this).val()))
$('list-of-search').empty()
searchItems.forEach((item)=>{
$('list-of-search').append(`<span>${item}</span>`)
})
})
})
})

Attachments moved away from Item after validation and before submit process in Apex

I have multiple File Browser Item fields on one page of Application in Oracle Apex.
What happens: When I miss any Item for which validation error fires, I want to hold that file to the browser but I usually loose it if I get that validation error. Is there a solution for the same like other Items fields hold previous value except File Browser Item field. Please see below ss:
Anshul,
APEX 4.2 is very old and no longer supported. A later (or preferably latest) version of APEX will behave differently as Dan explained above.
Can you import your application into apex.oracle.com (which is running APEX 20.1) and you will probably see better results. Based on this you can hopefully use it as justification to upgrade your environment.
Regards,
David
Go to your page-level attributes and a function like the following in the Function and Global Variable Declaration:
function validateItems(request) {
var $file1 = $('#P68_FILE_1');
var $file2 = $('#P68_FILE_2');
var errorsFound = false;
if ($file1.val() === '') {
errorsFound = true;
// Show item in error state
}
if ($file2.val() === '') {
errorsFound = true;
// Show item in error state
}
if (!errorsFound) {
// I think doSubmit was the name of the function back then. If not, try apex.submit
doSubmit(request);
} else {
// Show error message at top of page, I'll use a generic alert for now
alert('You must select a file for each file selector.');
}
}
Then, right-click the Create button and select Create a Dynamic Action. Set the name of the Dynamic Action to Create button clicked.
For the Action, set Type to Execute JavaScript Code. Enter the following JS in code:
validateItems('CREATE');
Finally, ensure that Fire on Initialization is disabled.
Repeat the process for the Save button, but change the request value passed to validateItems to SAVE.

django summernote create custom buttons

I'd like to add a custom button similar to this one:
$('#makeSnote').click(function(event) {
var highlight = window.getSelection(),
spn = document.createElement('span'),
range = highlight.getRangeAt(0)
spn.innerHTML = highlight;
spn.className = 'snote';
spn.style.color = 'blue';
range.deleteContents();
range.insertNode(spn);
});
JS Fiddle
http://jsfiddle.net/ypweuw1L/
I'm not sure how would I go about adding this into my Django app? I don't see anything in the django-summernote docs.
I don't know about django-summernote well. But you can create custom button and use it on toolbar with options.
for more details...
http://summernote.org/deep-dive/#custom-button

Overriding Admin shapes in custom Orchard CMS theme

I'm doing a custom theme for Orchard CMS.
As part of client project one of the requirements is to have some extra functionality in blog admin page.
This is pretty easy doing some simple changes in Parts.Blogs.BlogPost.ListAdmin.cshtml
I do not want to change the Blog source code, I would like to override that wiew in theme just like I'm doing with all the others on front end.
Following some guidelines found on orchard forum I have tried the following paths:
~/Themes/MyTheme/Views/Parts.Blogs.BlogPost.ListAdmin.cshtml
~/Themes/MyTheme/Views/Orchard.Blogs/Parts.Blogs.BlogPost.ListAdmin.cshtml
~/Themes/MyTheme/Views/Dashboard/Admin/Parts.Blogs.BlogPost.ListAdmin.cshtml
but the view is not picked up.
So, How may I override a view in my theme that will be picked up by admin dashboard instead of the default one?
Thanks
You need to create a theme with a project file, then add a .cs file with something like this in it:
public class AdminOverride : IThemeSelector
{
public ThemeSelectorResult GetTheme(RequestContext context)
{
if (AdminFilter.IsApplied(context))
{
return new ThemeSelectorResult { Priority = 111, ThemeName = "NewAdminTheme" };
}
return null;
}
}
Don't set this theme as current though, just enable it from the backend. You will also need to set your TheAdmin as the base theme in the Theme.txt like this:
BaseTheme: TheAdmin

How do I utilize the save event in a Sitecore custom Item Editor?

I am creating a custom item editor, and am using the following blog post as a reference for responding to the "save" event in the Content Editor, so that I do not need to create a second, confusing Save button for my users.
http://www.markvanaalst.com/sitecore/creating-a-item-editor/
I am able to save my values to the item, but the values in the normal Content tab are also being saved, overriding my values. I have confirmed this via Firebug. Is there a way to prevent this, or to ensure my save is always after the default save?
I have this in as a support ticket and on SDN as well, but wondering what the SO community can come up with.
Thanks!
Took a shot at an iframe-based solution, which uses an IFrame field to read and save the values being entered in my item editor. It needs to be cleaned up a bit, and feels like an interface hack, but it seems to be working at the moment.
In my item editor:
jQuery(function () {
var parentScForm = window.parent.scForm;
parentScForm.myItemEditor = window;
});
function myGetValue(field) {
var values = [];
jQuery('#myForm input[#name="' + field + '"]:checked').each(function () {
values.push(jQuery(this).val());
});
var value = values.join('|');
return value;
}
In my Iframe field:
function scGetFrameValue() {
var parentScForm = window.parent.scForm;
if (typeof (parentScForm.myItemEditor) != "undefined") {
if (typeof (parentScForm.myItemEditor.myGetValue) != "undefined") {
return parentScForm.myItemEditor.myGetValue("myLists");
}
}
return null;
}
In theory, I could have multiple fields on the item which are "delegated" to the item editor in this way -- working with the content editor save rather than trying to fight against it. I'm a little uneasy about "hitchhiking" onto the scForm to communicate between my pages -- might consult with our resident Javascript hacker on a better method.
Any comments on the solution?
EDIT: Blogged more about this solution