Determining if a delta was generated by an undo - quill

I'm implementing a simple "track changes" type of interface that replaces deleted content with the same content, but highlighted and with a strike-through line. This works fine for normal content the user deletes, but when undoing an insertion, the delta looks the same as a regular user deletion. Is there any way to determine if the delta was from the undo extension? Or is this fundamentally the wrong approach?

You might want to check the keyboard Module to detect here that an undo command is done and modify the to-be-applied Delta in order to remove its "deleted style".
This pice of code might help you bootstrap your needs:
'undo': {
key: 90,
shortKey: true,
handler: function (range, context) {
// return true to keep normal Quill behaviour
// or else return a new Delta that modify context
console.log(range, context)
return true
}
}
Best

Related

Is FLIP-140 still correct in how it describes sorting/spilling data?

FLIP-140 states:
We will introduce a sorting step (with potential spilling, reusing the UnilateralSortMerger implementation) before every keyed operator for sorting/grouping inputs by their keys. This will allow us to process records in per-key groups, which will enable us to use a simplified implementation of a StateBackend that is not organized in key groups and only ever keeps values for a single key.
The single key at a time execution will be used for the Batch style execution as decided by the algorithm described in FLIP-134: DataStream Semantics for Bounded Input .
Moreover it will be possible to disable it through a execution.sorted-shuffles.enabled configuration option.
However I see not documentation for execution.sorted-shuffles.enabled, and no references to it in the code. So is the above description of how things work still correct? Wondering how the "only keep one key's state around" would work without sorting.
This code makes me think that both the sorting and special state backend are being used with batch execution:
private void setBatchStateBackendAndTimerService(StreamGraph graph) {
boolean useStateBackend = configuration.get(ExecutionOptions.USE_BATCH_STATE_BACKEND);
boolean sortInputs = configuration.get(ExecutionOptions.SORT_INPUTS);
checkState(
!useStateBackend || sortInputs,
"Batch state backend requires the sorted inputs to be enabled!");
if (useStateBackend) {
LOG.debug("Using BATCH execution state backend and timer service.");
graph.setStateBackend(new BatchExecutionStateBackend());
graph.setChangelogStateBackendEnabled(TernaryBoolean.FALSE);
graph.setCheckpointStorage(new BatchExecutionCheckpointStorage());
graph.setTimerServiceProvider(
BatchExecutionInternalTimeServiceManager::create);
} else {
graph.setStateBackend(stateBackend);
graph.setChangelogStateBackendEnabled(changelogStateBackendEnabled);
}
}

Xceed DataGrid: Filtering Details

I've got a Master/Detail DataGrid and I want to filter the details.
Here's my DataGridCollectionViewSource:
<xcdg:DataGridCollectionViewSource x:Key="Features"
Filter="ExampleFilter"
Source="{Binding Path=ItemUnderEdit.Features}"
AutoCreateDetailDescriptions="False"
AutoCreateItemProperties="False">
<xcdg:DataGridCollectionViewSource.DetailDescriptions>
<xcdg:PropertyDetailDescription RelationName="Settings"
AutoCreateDetailDescriptions="False"
AutoCreateItemProperties="False">
</xcdg:PropertyDetailDescription>
</xcdg:DataGridCollectionViewSource.DetailDescriptions>
</xcdg:DataGridCollectionViewSource>
As you can see I'm filtering it with ExampleFilter, but this only filters the master. I put a breakpoint and it never sees any details.
I cant add a filter to the Detail Descriptions in the same way. Is there any way to filter the details? Any help would be much appreciated!
I went up against this problem today - I had a simple filter for both the master and detail sections that gets turned on / off via code. For the master section, it was a simple matter of code like:
((DataGridCollectionView)grid.ItemsSource).FilterCriteriaMode = FilterCriteriaMode.None; // Off
((DataGridCollectionView)grid.ItemsSource).FilterCriteriaMode = FilterCriteriaMode.And; // On
((DataGridCollectionView)grid.ItemsSource).Refresh(); // Re-run filter.
For the details section, it should have been as simple as the following code (it wasn't though):
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.None; // Off
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.And; // On
Turns out, doing that will enable the new filter for any new detail sections that get generated, but not existing ones. New detail sections are generated when the master row is expanded. To get around this it turned out I needed a simple foreach loop such as:
foreach (DataGridContext context in grid.GetChildContexts()) {
((DataGridCollectionViewBase)(context.Items)).FilterCriteriaMode = PetsDetailDescriptions.FilterCriteriaMode;
}
Here's my complete(ish) code for all that:
public bool ShowDeleted {
set {
if ((grid.ItemsSource != null) && (grid.ItemsSource.GetType() == DataGridCollectionView));
DataGridCollectionView v = ((DataGridCollectionView)(grid.ItemsSource));
if (value) {
v.FilterCriteriaMode = FilterCriteriaMode.None;
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.None;
}
else {
v.FilterCriteriaMode = FilterCriteriaMode.And;
MyDetailDescription.FilterCriteriaMode = FilterCriteriaMode.And;
}
foreach (DataGridContext context in grid.GetChildContexts()) {
((DataGridCollectionViewBase)(context.Items)).FilterCriteriaMode = PetsDetailDescriptions.FilterCriteriaMode;
}
v.Refresh();
}
}
}
I'm using that in-conjunction with a simple predefined filter criterion in the XAML. IE:
<g:DataGridItemProperty Name="IsDeleted"
DataType="{x:Type sys:Boolean}">
<g:DataGridItemProperty.FilterCriterion>
<g:EqualToFilterCriterion>
<sys:Boolean>False</sys:Boolean>
</g:EqualToFilterCriterion>
</g:DataGridItemProperty.FilterCriterion>
</g:DataGridItemProperty>
I recommend using the Xaml FilterCriterions, because if you absolutely need the Filter event, it's going to get a bit more messy. For that route, you need to do the following steps:
Tap into the event when a new child DataGridContext is added to the control.
Add a predicate reference to the context.Items.Filter property (in the code state, this is a property expecting predicate, not an event).
Write your filter code in the predicate function.
I'm not 100% sure how to achieve #1 above (as I didn't need to go that route). However, a good place to possible start is the DetailsExpanding and DetailsExpanded events of the DataGridControl. For the expanding, I'm not sure if the child DataGridContext exists yet (as there is an option to cancel the expanding). So you might have to wait until after the expanded event.
I hope this helps point you in the right direction.

Can you alter a Custom Attribute's enum list in Maya?

I'm adding a custom attribute that is an enum list to some of my nodes. I can easily do this with addAttr. But I don't see a way to later add a new enum value or change the enum list. Is that possible?
I have found a way to do this but it seems there should be an easier way. For my workaround, if the attribute exists I grab its value and delete the attribute. Then I add the revised attribute back into the node and set its value to the old value. By changing $enumValues I can edit the list of enums. (Note I only plan to add values not delete values) This script demonstrates my workaround:
string $attrName = "MaterialType";
string $enumValues = "Water:Sky:Terrain:Building:Road:";
string $selected[] = `ls -sl`;
if(`size $selected` == 1)
{
string $attrFullName = $selected[0]+"."+$attrName;
$existingValue = 0;
if(attributeExists($attrName, $selected[0]))
{
$existingValue = `getAttr $attrFullName`;
deleteAttr $attrFullName;
}
addAttr -ln $attrName -at "enum" -en $enumValues $selected;
setAttr $attrFullName $existingValue;
}
else
{
print "You must have 1 object and only 1 object selected\n";
};
Worth mentioning, if I run this script it does change the enum's values but these changes don't show up in Maya's interface until I close the file and reopen the file.
Any suggestions on how to do this more gracefully would be appreciated.
I might be a bit late, but you can use the "-edit" flag in addAttr.
addAttr -edit -enumNames "A:B:C" "node.enumAttrName"
However, you still need to refresh manually or with refreshEditorTemplates
Edit:
You might also want to consider optionMenuGrp. You can add menuItems via the -parent flag. You can remove a specific child with the deleteUI command or remove all children with the -deleteAllItems flag in edit mode on the optionsMenuGrp.
What you're doing - deleting the attribute and re-adding -- is unfortunately the only way to do this. Maya enums are pretty lame.
The attribute should be working correctly after the script is done - you may need to deselect and reselect it to properly refresh the attribute editor. You can check it with an listAttr -ud on your object after the script runs - you should see your attribute name in the results, even if the UI has not refreshed.

clear text field using DELETE or BACK SPACE key in webdriver

I am trying to clear a text field using this action:
emailField.sendKeys("gmail.com");
emailField.sendKeys(Keys.CONTROL,"a",Keys.DELETE);
In above code, the last line only selects the text, does not delete it, but if I separate the actions it works.
emailField.sendKeys(Keys.CONTROL,"a");
emailField.sendKeys(Keys.DELETE);
From the JavaDoc for WebElement.clear():
If this element is a text entry element, this will clear the value.
Has no effect on other elements. Text entry elements are INPUT and
TEXTAREA elements. Note that the events fired by this event may not be
as you'd expect. In particular, we don't fire any keyboard or mouse
events. If you want to ensure keyboard events are fired, consider
using something like sendKeys(CharSequence) with the backspace key. To
ensure you get a change event, consider following with a call to
sendKeys(CharSequence) with the tab key.
Most likely you simply need to call:
emailField.sendKeys("gmail.com");
emailField.clear();
But if you need the clearing to be done via the keyboard for some reason, use Keys.BACKSPACE.
keys.DELETE can not work to delete the input text,you should use keys.BACKSPACE.
emailField.sendKeys(Keys.BACKSPACE)
From the JavaDoc for Keys.chord
chord(java.lang.CharSequence... value)
Simulate pressing many keys at once in a "chord".
You should be able to use
emailField.sendKeys(Keys.chord(Keys.CONTROL,"a",Keys.DELETE));
Tested in chrome driver
WE.send_keys(' \b')
This will add space then delete it (backspace)
I use in javascript and it's working fine:
await textBox.sendKeys(value);
await textBox.sendKeys(Key.BACK_SPACE);
emailField.sendKeys(Keys.BACKSPACE)
doesn't worked for me .
I used 'Key' instead of 'Keys'
emailField.sendKeys(protractor.Key.BACKSPACE)
emailField.sendKeys(Keys.CONTROL + "a",Keys.DELETE);
In PHP:
if you use php-webdriver (https://github.com/php-webdriver/php-webdriver) you must:
use Facebook\WebDriver\WebDriverKeys AS Keys;
.
.
.
$this->driver->findElement(By::id('demo'))->sendKeys([Keys::BACKSPACE,'Any other text']);
Just adding another working C# example using the Google Chrome webdriver.
SendKeys only takes one parameter so created a string with the Crtl + A. This code sequence will select the current text in the field then delete the text.
Code example:
var crtlA = Keys.Control + "a";
driver.FindElement(By.XPath("//div[3]/div[1]/div[2]/div/div[2]/div[2]/div/div/div[1]/div/span/input")).SendKeys(crtlA); Wait(5000); // Select current text
driver.FindElement(By.XPath("//div[3]/div[1]/div[2]/div/div[2]/div[2]/div/div/div[1]/div/span/input")).SendKeys(Keys.Delete); Wait(5000); // Clear current text
driver.FindElement(By.XPath("//div[3]/div[1]/div[2]/div/div[2]/div[2]/div/div/div[1]/div/span/input")).SendKeys(newItemSku); Wait(5000); // Input SKU name
1. in WebdriverIO, i tried to edit the text by clear text (which contains special charactes like #, +, _) in text field by below following step. Eventhough it was not successful.
example: text=> abc+1234#gmail.com
step1:browser.clearElement(selector);
step2:browser.execute(function () {
document.querySelector(>>>Cssselector<<<).value="";
});
step3: browser.doubleClick(selector);
browser.keys("Delete");
step4: browser.click(selector);
browser.keys(['Meta',a]);
browser.keys('Meta');
browser.keys('Delete');
Note: below step is resolved this issue.
var count= browser.getAttribute(selector, value).length;
for (var i=0;i<count;i++)
{
if (browser.getAttribute(selector, value)=='')
break;
}
else
{
browser.doubleClick(selector);
browser.keys("Delete");
}
browser.pause(200);
// it will clear your text field easily.
Note:
You can add the new text now.

Retrieving Specific Active Directory Record Attributes using C#

I've been asked to set up a process which monitors the active directory, specifically certain accounts, to check that they are not locked so that should this happen, the support team can get an early warning.
I've found some code to get me started which basically sets up requests and adds them to a notification queue. This event is then assigned to a change event and has an ObjectChangedEventArgs object passed to it.
Currently, it iterates through the attributes and writes them to a text file, as so:
private static void NotifierObjectChanged(object sender,
ObjectChangedEventArgs e)
{
if (e.ResultEntry.Attributes.AttributeNames == null)
{
return;
}
// write the data for the user to a text file...
using (var file = new StreamWriter(#"C:\Temp\UserDataLog.txt", true))
{
file.WriteLine("{0} {1}", DateTime.UtcNow.ToShortDateString(), DateTime.UtcNow.ToShortTimeString());
foreach (string attrib in e.ResultEntry.Attributes.AttributeNames)
{
foreach (object item in e.ResultEntry.Attributes[attrib].GetValues(typeof(string)))
{
file.WriteLine("{0}: {1}", attrib, item);
}
}
}
}
What I'd like is to check the object and if a specific field, such as name, is a specific value, then check to see if the IsAccountLocked attribute is True, otherwise skip the record and wait until the next notification comes in. I'm struggling how to access specific attributes of the ResultEntry without having to iterate through them all.
I hope this makes sense - please ask if I can provide any additional information.
Thanks
Martin
This could get gnarly depending upon your exact business requirements. If you want to talk in more detail ping me offline and I'm happy to help over email/phone/IM.
So the first thing I'd note is that depending upon what the query looks like before this, this could be quite expensive or error prone (ie missing results). This worries me somewhat as most sample code out there gets this wrong. :) How are you getting things that have changed? While this sounds simple, this is actually a somewhat tricky question in directory land, given the semantics supported by AD and the fact that it is a multi-master system where writes happen all over the place (and replicate in after the fact).
Other variables would be things like how often you're going to run this, how large the data set could be in AD, and so on.
AD has some APIs built to help you here (the big one that comes to mind is called DirSync) but this can be somewhat complicated if you haven't used it before. This is where the "ping me offline" part comes in.
To your exact question, I'm assuming your result is actually a SearchResultEntry (if not I can revise, tell me what you have in hand). If that is the case then you'll find an Attributes field hanging off of that guy, and from there there is AttributeNames and Values. I think you'll see how it works from there if you have Values in hand, for example:
foreach (var attr in sre.Attributes.Values)
{
var da = (DirectoryAttribute)attr;
Console.WriteLine(da.Name);
foreach (var val in da.GetValues(typeof(byte[])))
{
// Handle a byte[] val ...
}
}
As I said, if you have something other than a SearchResultEntry in hand, let us know and I can revise the code sample.

Resources