I am dealing with a strange issue after the update to Typo3 11.5.
My extension adds several content elements to the new content element wizard in its own tab.
What does not work:
Users do not see the custom tab in the new content element wizard
What works:
Admins can see the tab in the content element wizard
Users can edit the elements once they are created
Users can change the type of an element to any of the custom elements using the "Type" dropdown
So, users seem to have all the access rights they need (confirmed in backend group settings).
The wizard seems to be configured correctly (confirmed accessing as admin).
But only admins see the tab.
If you have any hint what I could look into, I would be very grateful.
Below is the .tsconfig file I use for the wizard:
mod.wizards {
newContentElement.wizardItems {
abc.header = ABC
abc.elements {
abc_slider {
iconIdentifier = abc
title = ABC Slider
description = ABC Slider
tt_content_defValues {
CType = abc_slider
list_type = abc_slider
}
}
}
}
newContentElement.wizardItems {
abc.header = ABC
abc.elements {
abc_text {
iconIdentifier = abc
title = ABC Text
description = ABC Text
tt_content_defValues {
CType = abc_text
list_type = abc_text
}
}
}
}
}
mod.wizards.newContentElement.wizardItems.abc.show = *
I have tried adding more permissions to the backend user, but they already had rights to all elements and there was no permission setting for the tab.
I have tried adding settings to the tsconfig of the backend user and backend user group, but that did not have any effect.
As the documentation says show = * is for the plugins-tab. I had success using the documented way. So your code should look like this:
mod.wizards {
newContentElement.wizardItems {
abc.header = ABC
abc.elements {
abc_slider {
iconIdentifier = abc
title = ABC Slider
description = ABC Slider
tt_content_defValues {
CType = abc_slider
list_type = abc_slider
}
}
}
abc.show := addToList(abc_slider)
}
newContentElement.wizardItems {
abc.elements {
abc_text {
iconIdentifier = abc
title = ABC Text
description = ABC Text
tt_content_defValues {
CType = abc_text
list_type = abc_text
}
}
}
abc.show := addToList(abc_text)
}
}
Related
I want to hide the Dev Tools menu item in Kibana, but according to their roadmap, that's not possible with their permission system nor will it be anytime soon. (see https://discuss.elastic.co/t/disable-hide-management-plugin-kibana-5/72763)
Kibana is inside an iFrame hosting a site on the container's domain.
I ended up using MutationObservers in JavaScript to watch for changes to the DOM inside the iFrame in order to hide the menus I didn't want non-admins to see. Solution written in AngularJS 1.2 and is known to work with Kibana 6.2 and 6.3. This will hide several "left side" menus as well as a bunch of Management sub-menus. You can use or modify the code to hide/show additional UI elements. Unfortunately, I had to rely on classes a lot since very few elements contained IDs I could reference.
I hope this at least helps you think of your own solution to managing Kibana display elements outside of their permission structure.
HTML:
<iframe id="AnalysisFrame" ng-src="{{kibanaUrl}}" ng-init="setupFrame()"></iframe>
JavaScript:
$scope.setupFrame = function() {
//iframes are excluded from mutation observation, so we will
// need to create an observer _inside_ the iframe content.
var theFrame = document.querySelector('#AnalysisFrame');
//once the frame is loaded, that is when we can now attach our
// observer to the frame's content.
theFrame.onload = function() {
//console.log('[TRACE] iframe is completely loaded');
var bIsKibanaAdmin = $scope.bIsKibanaAdmin;
//the above is TRUE|FALSE set by some outside logic
// which does not pertain to this exercise.
//create an observer instance for Management sub-menus
var observerMan = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
//console.log('[TRACE] ', mutation);
//sub-menus of the Management console area
var manArea = theFrame.contentDocument.body.querySelector('kbn-management-landing');
if ( manArea ) {
//Management area is divided up by panels of related subjects
var manPanels = manArea.querySelectorAll('div[class*="page-row"]');
if ( manPanels ) manPanels.forEach(function(aPanel) {
//console.log('[TRACE] panel=', aPanel);
//6.2.4 had <div> titles, 6.3.x has <h3> titles, select based on their class only
var panelTitle = aPanel.querySelector('.kuiPanelHeader__title');
//if a panel has a title (version panel does not have one), see if hide or not.
if ( panelTitle ) switch ( panelTitle.innerText ) {
case 'Kibana':
//only hide the Advanced Settings item off this panel
var panelItem = aPanel.querySelector('li > a[href*="#/management/kibana/settings"]');
if ( panelItem ) panelItem.parentElement.hidden = !bIsKibanaAdmin;
break;
default:
//most management panels are hidden from non-admins
aPanel.hidden = !bIsKibanaAdmin;
}//switch
});
}
});
});
//configuration of the left menu becomes active observer
var configMan = {
attributes: true, //for when Management becomes the Active menu
attributeFilter: ['class'],
//attributeOldValue: true,
childList: false,
characterData: false,
//characterDataOldValue: false,
//subtree: true,
};
//the Management menu item does not exist yet, cannot start observing until later.
//create an observer instance for left menu
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
//console.log('[TRACE] ', mutation);
var leftMenus = mutation.target.querySelectorAll('.global-nav-link');
//since the menus do not have IDs, we are searching for their outer
// DIV class unique to all left menu items. Their first element child
// will be the <a href> link we can use to filter out ones we
// wish to show or not.
if ( leftMenus ) leftMenus.forEach(function(aMenu) {
if ( aMenu.firstElementChild ) {
switch ( aMenu.firstElementChild.hash ) {
case "#/dev_tools":
aMenu.hidden = !bIsKibanaAdmin;
break;
case "#/account":
aMenu.hidden = true;
break;
case "":
if ( aMenu.innerText=='Logout' ) {
aMenu.hidden = true;
}
//else console.log('[TRACE] menu=', aMenu);
break;
case "#/management":
//we only want to hide certain sub-menus
// our menu item exists, attach observer for when
// user clicks it to make it "active"
observerMan.observe(aMenu, configMan);
break;
default:
//console.log('[TRACE] menu=', aMenu);
}//switch
}
});
});
});
//configuration of the left menu creation observer
var configLM = {
attributes: false,
//attributeFilter: ['src'],
//attributeOldValue: true,
childList: true,
characterData: false,
//characterDataOldValue: false,
//subtree: true,
};
//start observing the contents of the iframe changes
observer.observe(theFrame.contentDocument.body, configLM);
};
};
In my Apple Watch app, I update the title text via self.setTitle("some title"). The problem is, that if that code gets triggered on Controller A while Controller B is present, A, the one in the "background", (e.g. in a hierarchical/Master-Detail design) changes the title although B is showing.
What's the best way to get around this? I tried looking for a way to do something like
if (self.navigationController.topViewController == self) {
self.setTitle("Chats (live)")
}
but this isn't available on Watchos.
How else can I achieve this?
I put this together, haven't tested this much yet but on the first look it appears to work:
var masterTitle = ""
var masterActive = false
...
setControllerTitle("Test") //set the title
override func didAppear() {
masterActive = true //enables title updates
setControllerTitle(masterTitle) //sets title if view re-appeared
}
override func willDisappear() {
masterActive = false //disables title updates
}
func setControllerTitle(_ s : String){
masterTitle=s //saves title for future use
if(masterActive){
self.setTitle(s) //sets title when view is current
}
}
I have a fixed navigation bar with an a-tag that links to a hash-URL. When the a-tag is clicked the URL changes from url.com to url.com/#all and the page scrolls down to a div with the belonging id, while the navigation bar still appears as it is fixed.
What I want is to style the a-tag when the #all appears in the URL. All without refreshing the page. I guess it can be done quite simple with jQuery, but I'm not sure how.
To simplify what I want it is this:
Without #all in the URL:
<div style="position:fixed;height:50px;width:100%;">
All
</div>
With #all in the URL:
<div style="position:fixed;height:50px;width:100%;">
All
</div>
This also implies that when the #all is removed again from the URL the style should be removed as well - again, all without refreshing the page.
So basically you want to change the style of the link once it has been clicked. That can be done easily with css:
a:visited {
font-weight: 700;
}
I would advise giving a class or an id to your link though, so that the style doesn't apply to all of them!
If you reeeeally want to us jQuery, you can do something like this:
$('a').click(function() {
$('a').css("font-weight", "700");
})
If you actually want to use the url, try :
if (window.location.href == 'http://url.com/#all')
$('a').css("font-weight", "700");
My only concern is with the http/https, but that should be easily handled with an OR condition or some regex on the url variable to get a better substring.
If you are using bootstrap then use built-in bootstrap scrollspy. Otherwise use this fiddle code to create your own. Modify the code as per need
// Cache selectors
var lastId,
topMenu = $("#top-menu"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind click handler to menu items
// so we can get a fancy scroll animation
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
menuItems
.parent().removeClass("active")
.end().filter("[href='#"+id+"']").parent().addClass("active");
}
});
You can get the # value from the url using just JavaScript
var id = window.location.hash.substr(1);
Now you have the value after the #, you can then use it as a selector.
So, for example;
/**
* Lets say the URL looks like this:
* https://example.com#all
* var id contains now the value `all`
*/
var id = window.location.hash.substr(1);
/**
* Update id to valid css id selector
* id is now `#all`
*/
id = "#" + id;
/**
* Get the element using the id we created above
*/
var elem = document.querySelectorAll('a[href="'+ id +'"]')[0];
/**
* You can also change the font weight using JavaScript
*/
elem.style.fontWeight = "700";
See demo below;
/**
* Lets say the URL looks like this:
* https://example.com#all
* var id contains now the value `all`
*/
var id = "all" //(Lets asume the value is `all`)window.location.hash.substr(1);
/**
* Update id to valid css id selector
* id is now `#all`
*/
id = "#" + id;
/**
* Get the element using the id we created above
*/
var elem = document.querySelectorAll('a[href="'+ id +'"]')[0];
/**
* You can also change the font weight using JavaScript
*/
elem.style.fontWeight = "700";
TEST
On the add page of a new Plone Page i want to suggest a title to the user derived from the Folder title by adding it into the title form field.
What is the best practice on implementing that behavior in my Plone instance?
An alternative solution can be to use Javascript, respectively jQuery:
(function($) { $(document).ready(function() {
// A Dexterity-based document is added:
if( window.location.href.endsWith('/++add++Document') ) {
// Grab the parent's title of the current title-tag's content:
var title = $('title')[0].innerHTML.split(' — ')[0]
// Prefill the new document's title-field with the parent's title:
$('#form-widgets-IDublinCore-title').val(title)
}
// An Archetypes-based document is added:
if( window.location.href.indexOf('/portal_factory/Document/') > -1 ) {
var parentUrl= document.referrer
var parentTitleEleId = 'parent-fieldname-title'
// Provide ele to load parent's title into:
var loadEle = document.createElement('span')
// Load parent's title into ele:
$(loadEle).load(parentUrl + ' #' + parentTitleEleId, function() {
// After loading finished, fetch parent-title of ele, remove
// trailing spaces and set it into the new doc's title-field:
$('#title').val(loadEle.childNodes[0].innerHTML.trim())
// Thy had served y'er purpose, vanish:
loadEle.remove()
});
}
});})(jQuery);
More to MonkeyPatching can you find in the Docs. Another solution is, you can register your own AddForm and set the Value of the Textline-Widget. To create a Custom AddForm look at the Docs
You can monkeypatch or subclass the Basic metadata behavior to modify the behavior of _get_title: https://github.com/plone/plone.app.dexterity/blob/master/plone/app/dexterity/behaviors/metadata.py#L350-L351
I have the following code which returns one of the 3 options ("Please check availability","Low Stock" or "Available") in a controller.
How can I change the view (2nd part in order to display a link "here" that will open a new window to an external url like "www.google.com" ?
First part is the controller , second part the view.
Thank you
if (model.ShowInventoryAvailability)
{
// Check to see if the system allows for webbackorder. If it does then we will say that we have 'available' inventory.
if (ApplicationSetting.GetByNameBoolean("Web_AllowBackOrder", true, "") && orderLine.Product.TrackInventory)
{
var inv = (Int32)(orderLine.Product.QtyOnHand - totalOrdered);
if (inv <= 0)
line.Availability = "Please check availability" ;
else if (inv < model.InventoryLowStockQuantity)
line.Availability = "Low Stock";
else
line.Availability = "Available";
}
else
{ }
}
#if (Model.ShowInventoryAvailability)
{
<td class="os-availability">
#cartLine.Availability
</td>
}
Assuming you want to add the url link when there is no stock you can check your text status or you could also add another property to the Model like the actual quantity and control the conditional statement via that property.
#if (Model.ShowInventoryAvailability)
{
<td class="os-availability">
if (cartLine.Availability == "Please check availability")
{
#Html.Link("http://www.google.com", "Here");
}
else
{
#cartLine.Availability
}
</td>
}