Slate.js prevent block deletion - slate.js

Which way I can prevent user to remove specific block from slate.js editor (or inform user that block will be deleted) my goal is protect information from accidental removal. Thanks in advance.

I was looking for something similar.
One way that I found was - by preventing default deleteForward and deleteBackward invocation when inside that node.
For example I have a front-matter node that contains meta-information about the document and I'd like the user to edit it but never remove from the tree.
text node is editable and this is the schema
{
type: 'front-matter',
children: [{ text: 'Welcome to the document' }],
}
And this is the plugin
export const withFrontmatter = (editor: Editor) => {
const { deleteForward } = editor;
editor.deleteForward = (unit: TextUnit) => {
const [frontmatter] = Editor.nodes(editor, {
match: (node) =>
!Editor.isEditor(node) && Element.isElement(node) &&
node.type === 'front-matter'
});
if (
!!frontmatter &&
Element.isElement(frontmatter[0]) &&
Editor.isEmpty(editor, frontmatter[0])
) {
return;
}
deleteForward(unit);
};
return editor;
};
Identical logic for deleteBackward and you have an un-deletable node.
Editor.isEmpty(editor, frontmatter[0]) checks if the inner text fragment is empty.

Related

Drupal 8: How to customize the block content on specific page

I'm able to change the block content by using the hook as below. But, I would like to change the block content (for eg: system_main_block) only if it appears on specific page. But, I'm not sure how to get the page id or title in the hooks below. Appreciate help.
function yourmodule_block_view_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block)
{
if ($block->getBaseId() === 'system_powered_by_block') {
$build['#pre_render'][] = '_yourmodule_block_poweredby_prerender';
}
}
function _yourmodule_block_poweredby_prerender(array $build) {
$build['content']['#markup'] = Markup::create('Your text');
return $build;
}
You can check the route name like this:
function yourmodule_block_view_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
if ($block->getBaseId() === 'system_powered_by_block' && \Drupal::routeMatch()->getRouteName() === '<your_route_name>') {
$build['#pre_render'][] = '_yourmodule_block_poweredby_prerender';
}
}

In ember, how to change values of checkboxes based on another

I have four checkbox and I want to check automatically checkbox with id = 2 if checkbox with id = 4 is checked.
I did the following but did not get the output. Could someone help me with this.
{#each category in checkboxList}}
{{input id = category.CHECKBOX_ID type="checkbox" checked=category.IS_CHECKED}}
{{#if category.CHECKBOX_ID == 4 && category.IS_CHECKED == true}}
{{action 'CheckSize'}}
{{/if}}
The checkboxList is
[
{"IS_CHECKED":false,"CHECKBOX_ID":1},
{"IS_CHECKED":false,"CHECKBOX_ID":2},
{"IS_CHECKED":true,"CHECKBOX_ID":3},
{"IS_CHECKED":false,"CHECKBOX_ID":4}
]
You'll want to manage the state of the checkboxes separately.
Here is an example I did for another SO question that had a similar problem to solve:
https://ember-twiddle.com/468a737efbbf447966dd83ac734f62ad
The gist of it is
we use a single action in response to a click of any checkbox:
#action
toggleChecked(id) {
const newTree = check(this.options, id);
this.set('options', newTree);
}
In this example (taken from the ember-twiddle), all of the logic is extracted to a pure-function named check.
Check itself is pretty involved, but because the application logic is different between that example and the problem you've run in to, I'll just show the entry point function:
export function check(tree, id, transform = toggle) {
if (tree === undefined) return undefined;
if (Array.isArray(tree)) {
return tree.map(t => check(t, id, transform));
}
if (tree.id === id || id === 'all') {
return checkNode(tree, id, transform);
}
if (tree.children) {
return checkChildren(tree, id, transform);
}
return tree;
}
This is just an example of how you can immutably modify the representation of all checkboxes by using a pure function. Your logic may vary.
Hope this helps :)

lookback API where filter with multiple conditions

When using loopback API, is 'AND' operator redundant in 'where' filter with multiple conditions?
For example, I tested the following two queries and they return the same result:
<model>.find({ where: { <condition1>, <condition2> } });
<model>.find({ where: { and: [<condition1>, <condtion2>] } });
To be more specific, suppose this is the table content:
name value
---- -----
a 1
b 2
When I execute 'find()' using two different 'where' filters, I get the first record in both cases:
{ where: { name: 'a', value: 1 } }
{ where: { and: [ { name: 'a'}, { value: 1 } ] } }
I've read through the API documents, but didn't find what logical operator is used when there are multiple conditions.
If 'AND' is redundant as shown in my test, I prefer not using it. But I just want to make sure if this is true in general, or if it just happens to work with postgreSQL which I'm using.
This is a valid query which could only be accomplished with an and statement.
{
"where": {
"or": [
{"and": [{"classification": "adn"}, {"series": "2"}]},
{"series": "3"}
]
}
}
EDIT: https://github.com/strongloop/loopback-filters/blob/master/index.js
function matchesFilter(obj, filter) {
var where = filter.where;
var pass = true;
var keys = Object.keys(where);
keys.forEach(function(key) {
if (key === 'and' || key === 'or') {
if (Array.isArray(where[key])) {
if (key === 'and') {
pass = where[key].every(function(cond) {
return applyFilter({where: cond})(obj);
});
return pass;
}
if (key === 'or') {
pass = where[key].some(function(cond) {
return applyFilter({where: cond})(obj);
});
return pass;
}
}
}
if (!test(where[key], getValue(obj, key))) {
pass = false;
}
});
return pass;
}
It iterates through the keys of the where object where looking for failure, so it acts like an implicit and statement in your case.
EDIT 2: https://github.com/strongloop/loopback-datasource-juggler/blob/cc60ef8202092ae4ed564fc7bd5aac0dd4119e57/test/relations.test.js
The loopback datasource juggler contains tests which use the implicit and format
{PictureLink.findOne({where: {pictureId: anotherPicture.id, imageableType: 'Article'}},
{pictureId: anotherPicture.id, imageableId: article.id, imageableType: 'Article',}
But I just want to make sure if this is true in general, or if it just happens to work with postgreSQL which I'm using.
Is it true in general? No.
It appears that this is handled for PostgreSQL and MySQL (and probably other SQL databases) in SQLConnector. So, it is possible connectors not using SQLConnector (e.g MongoDB) don't support this. However, given the many examples I've seen online, I would say it's safe to assume other connectors have implemented it this way, too.

Edting collection of items is slow in Sitecore

I've implemented an on item:saved handler per this question I posted here: Run code when Publishing Restriction is saved in Sitecore
When an author changes the publishing restrictions on a page, I iterate through each of the related components for that page, updating the publishing restrictions on each to match the page item. This works, but some pages have 150 or so components and the process of editing each is taking for ever. The result is that the UI hangs for up to 5 minutes while it runs. Not good.
I'm doing this:
compItem.Editing.BeginEdit();
compItem.Publishing.ValidFrom = pageItem.Publishing.ValidFrom;
compItem.Publishing.ValidTo = pageItem.Publishing.ValidTo;
compItem.Editing.EndEdit(true, true);
I've played around with the updateStatistics and silent arguments. If do it "silent" the UI responds, but of course it still takes forever for the update to run in the background which could cause issues, since there will be a window of time where the pub restrictions between the page and components would be out of sync.
Any thoughts on why updating 150 items is so slow? Any ways to speed it up?
Here's the full code:
public void OnItemSaved(object sender, EventArgs args)
{
Item item = Event.ExtractParameter(args, 0) as Item;
if (item == null)
return;
//if it's a page, then update the page component templates with the same publish restrictions.
if(this.HasBaseTemplate(item, GlobalId.PageBaseTemplate))
{
ItemChanges itemChanges = Event.ExtractParameter(args, 1) as ItemChanges;
if (itemChanges != null &&
(itemChanges.FieldChanges.Contains(__Validfrom) || itemChanges.FieldChanges.Contains(__Validto)))
{
foreach (Item i in this.GetPageComponents(item))
{
try
{
i.Editing.BeginEdit();
i.Publishing.ValidFrom = item.Publishing.ValidFrom;
i.Publishing.ValidTo = item.Publishing.ValidTo;
i.Editing.EndEdit(true, false);
}
catch(Exception ex)
{
i.Editing.CancelEdit();
}
}
}
}
}
protected IEnumerable<Item> GetPageComponents(Item page)
{
var links = page.Links.GetAllLinks(false, true);
var foundIds = new HashSet<ID>();
var foundComponentIds = new HashSet<ID>();
var componentIds = new List<ID> { page.ID };
using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
while (componentIds.Any())
{
var query = context.GetQueryable<LinkSearchResultItem>();
var predicate = PredicateBuilder.False<LinkSearchResultItem>();
foreach (var id in componentIds)
{
predicate = predicate.Or(sri => sri.ItemId == id);
}
query = query.Where(predicate);
var results = query.GetResults().Hits.Select(h => h.Document);
foundIds.Add(componentIds);
componentIds.Clear();
componentIds.AddRange(results
.Where(sri => (sri.Path.StartsWith("/sitecore/content/BECU/Global/Page Components/", StringComparison.InvariantCultureIgnoreCase) || sri.ItemId == page.ID) && sri.Links != null)
.SelectMany(sri => sri.Links)
.Except(foundIds));
foundComponentIds.Add(results
.Where(sri => (sri.Path.StartsWith("/sitecore/content/BECU/Global/Page Components/", StringComparison.InvariantCultureIgnoreCase)))
.Select(sri => sri.ItemId));
}
}
var database = page.Database;
return foundComponentIds.Select(id => database.GetItem(id)).Where(i => i != null);
}
I would recommend that you try wrapping your edit code with a Sitecore.Data.BulkUpdateContext as follows
...
using(new Sitecore.Data.BulkUpdateContext())
{
foreach (Item i in this.GetPageComponents(item))
{
try
{
i.Editing.BeginEdit();
i.Publishing.ValidFrom = item.Publishing.ValidFrom;
i.Publishing.ValidTo = item.Publishing.ValidTo;
i.Editing.EndEdit(true, false);
}
catch(Exception ex)
{
i.Editing.CancelEdit();
}
}
}
...
When an item is updated in Sitecore, several other background processes and events as a result of updating the item. Such an example is indexing which will slow down the update of a large number of items at once.
The BulkUpdateContext will disable most of these events and processes until the update is complete thereby hopefully speeding up the update of your items.
Note: I have yet to use this BulkUpdateContext myself but I found several posts including this Stackoverflow question where it claims that the BulkUpdateContext only improves item creation speed, not updates. However that may only apply to the particular version of Sitecore that was being used at the time. It may may no longer be the case with new versions of Sitecore (7.X and 8), so I think it is still worth a try.

In (Scala) Lift, how to render the original HTML from the template when using Helpers.bind

I'm a Scala/Lift beginner and I'm having trouble with rendering a list with optional "tags" on each item.
My HTML template says
<lift:Items.list>
<e:name>Rock</e:name><br />
<e:warning><span style="color:#ff0000;">DANGER!</span></e:warning>
</lift:Items.list>
And on the Items.scala I have
def list(node : NodeSeq) : NodeSeq = {
getItems flatMap( it => {
Helpers.bind("e", node,
"name" -> { Text(it.name) },
"warning" -> {
if (it.isDangerous) { <<INSERT HTML FROM TEMPLATE>> }
else { Text("") }
}
)
})
}
I'd like to, in certain cases, have the contents of the "e:warning" tag rendered verbatim. I'm sure there's an easy way to extract them from "node", but I guess I have some major gaps in my Lift knowledge because I can't figure out how.
If anyone could point out the proper procedure to me I'd be very thankful.
ANSWERED:
Thanks for the advice. I ended up structuring my code like this:
"warning" -> { (n : NodeSeq) => {
if (it.isDangerous) { n } else { Text("") }
}}
You can simply bind a function to the node’s name which takes a NodeSeq and returns a NodeSeq.
E.g.:
def warning(in: NodeSeq): NodeSeq = doSomethingWith(in)
// ...
Helpers.bind("e", node, "warning" -> warning _)
The contents of the <e:warning> node will then be transformed and inserted.
I'm not sure on the purpose of what you are trying to do. If you want to display one thing or the other, use chooseTemplate and a Box.