Trigger an event while removing a block from a content area on a page (using "Remove" on the Content Area) and when a user click on "Move to Trash" i - episerver

I want to trigger an event whenever editor removes a block (using "Remove" on the Content Area) and when a user click on "Move to Trash" on a block in the asset pane.
I find DataFactory.Instance.MovedContent event which is firing on every click on "Move to Trash"
But while clicking on Remove on the Content Area its not firing.
Update:-
I am doing these steps to achieve clicking on remove
Register event handlers for saving event and saved event for the page.
In saving event, get the page that is being saved, get the block ids from the content area by ContentArea.Items. Use the contentlink.ID property.
Store those ids in a List, store it in memory somewhere, preferably in httpcontext.items collection since you only need it for the request but a short lived cache also works. Now you know the ids of all blocks before the change by editor.
In saved event, get a new list of ids like above. Now you know the ids after editor change. Some block ids will be missing. Handle those by whatever you want to do...
void Instance_SavingContent(object sender, ContentEventArgs e)
{
if (e.Content is ListPdfDocumentBlock)
{
var properties = e.Content.GetType().GetProperties().Where(i => i.PropertyType == typeof(ContentArea));
if (properties != null)
{
List<int> ids = new List<int>();
foreach (var property in properties)
{
ContentArea contentArea = property.GetValue(e.Content) as ContentArea;
if (contentArea != null)
{
foreach (ContentAreaItem contentAreaItem in contentArea.Items)
{
IContent itemContent = contentAreaItem.GetContent();
ids.Add(itemContent.ContentLink.ID);
}
}
}
HttpContext.Current.Items.Add("pdfId", ids);
}
}
}
But the problem with this code is,its always returning updated ids. then how i will compare from old to new to identify which block is removed.

When you remove something from a content area, the item reference is simply removed from that content area. The actual content (for example block/media) removed from the content area isn't actually moved/deleted (it will still exist where it was created, commonly in some asset folder).
So, the only thing happening when something is removed from a content area is that the content containing the content area is changed. The removed item is unchanged.
You could hook up the PublishingContent event and compare the content being published to the currently published version (if any) and compare the items in its content area to see if anything was added or removed.

Related

Verify the visibility of a specific list element - Katalon

I have the following method that takes an integer input and clicks on the item from a list.
def static selectItem(int itemIndex) {
WebUI.waitForElementVisible(findTestObject('dashboard/ItemList'), 7, FailureHandling.STOP_ON_FAILURE);
final List<TestObject> items =
CommonUtils.findVisibleElementsFromTestObject(findTestObject('dashboard/ItemList'));
WebUI.click(items.get(itemIndex));
}
In my test class, I am loading the dashboard page and before clicking a particular item, I want to make sure that it is visible on the screen.
For example,
Dashboard.selectItem(17) should click the 16th item on the list. I know one way is to verify the visibility of the complete list but I am looking for a way to verify visibility of a specific item (16th in my case) from a list.
WebUI.waitForElementVisible() method returns
true: the element is present and visible within the timeout
and
false: the element is NOT present and visible within the timeout
So, you could create a new method that would look something like this
def static isItemVisible(int itemIndex, int timeout) {
final List<TestObject> items =
CommonUtils.findVisibleElementsFromTestObject(findTestObject('dashboard/ItemList'));
WebUI.waitForElementVisible(findTestObject('dashboard/ItemList'), timeout, FailureHandling.OPTIONAL);
}
Failure handling has been changed to "OPTIONAL" so the test won't fail in case the element is not found.

in angularjs 2, Issue with updating DOM content

in angularjs 2 i want to implement Print functionality.
Steps for implementing this are:-
1. on button click i want to fetch data from server.
2. on success, store that data in an array property inside Component class (By this DOM updated automatically) and call my custom print function which fetch DOM Content and place it in another window and calls print to open print dialog box.
Problem:
when i update property, then DOM is not updated automatically right when i assign the new value. it will update automatically after some time. in that time if my print function got executed then i got the old DOM content.
Code: on button click, i fetched data from server and passed that data to setContent method.
//set properties of component
setContent(data: any, columns: any): void {
this.customCollection = data;
this.columnsToPrint = columns;
//by setting above 2 properties i was assuming that DOM content is updated by this. Now i call function to print the content
this.printContent();
}
printContent(): void {
var printContents = document.getElementById("divPrintContent").innerHTML;
var popupWin = window.open('', '_blank', 'width=1200,height=800');
popupWin.document.open();
popupWin.document.write('<html><head><link rel="stylesheet" media="print" type="text/css" href="/app/shared/PRINT/print.css" /></head><body onload="window.print()">' + printContents + '</body></html>');
popupWin.document.close();
return;
}
Now when new window open (for print) it does not show the updated data but on inspecting DOM of parent window (by F12) i found the content is updated.

Backbone.Collection.reset() => child view is out of sync with parent

I have a list of items. They are stored in backbone pageable collection.
They are displayed like this
|---item1---------------------------|
|---item2---------------------------|
|---item3---------------------------|
|---item4---------------------------|
|---item5---------------------------|
|---item6---------------------------|
|---item7---------------------------|
<< 1,2,3...end >>
User can click on individual item to open detail view in a separate page. Detail view has listeners initialized
when it's created. Those listeners are bound to the item model.
Since the detail view is huge, I cache it in the DOM by toggling the visibility.
The subsequent click on the item will toggle the cached view.
------ here is the problem -----
When item list is switched to another page, the collection is reset (by paginator). And all the models previously stored in the collection is dereferenced and
a new set of models is created. So after the page is switched back and forth, the previously opened item has a different copy of itself stored
in the collection. So when I change the name of the item in the detail view (in the view cache), the name in the item list is not changed.
The views are out of sync! because they are referencing to different models.
Not sure if anyone else encounter this before. If you do, please share with me how you solve it.
Thanks very much.
The most straight-forward way to maintain a fresh reference between your list view items and the corresponding detail view, on page change, is to re-render the detail view. But I'm assuming this options is not acceptable within the scope of your project.
What I often do, when I have the task of forming relationships within logically separate views is use listeners. As long as the views share a unique identifier (for example, they both share a model, or at least identical model ids), I can always send a message that will reach the view I'm interested in.
For this you'll need a centralized event hub, which with Backbone is trivially easy to generate. In some appropiately global variable (like, for example, MyApp) we simply do:
MyApp.EventBus = _.extend({}, Backbone.Events);
Set up the detail view
On the detail view initialize function I would drop this listener,
initialize: function () {
// Listen to a toggle visibility on this view
this.listenTo(MyApp.EventBus, 'detail-view:toggle-view', toggleView);
},
toggleView: function (id) {
if (this.model.id == id) {
// Show this view if I have the passed id
this.$el.show()
// Notify the parent list item view that its detail view exists
MyApp.EventBus.trigger('detail:view:exists', true);
} else {
// Hide all other views
this.$el.hide();
}
},
changeName: function () {
// logic that parses DOM user input to
// local variable name
// We now trigger an event 'detail-view:change:name', and we send as
// parameters our model's id and the new name
MyApp.EventBus.trigger('detail-view:change:name', this.model.id, name);
}
Setting up the list item view
The list item view will want to listen to a name change (or any other model property in the detail view that you want the list item to be aware of). So we'll set up a handler for the 'detail-view:change:name' event.
We'll also want to wire our click handler to toggle the visibility of the list item's detail view. The tricky part is to handle the event that a view has not been rendered yet (I'm assuming you're lazy loading the detail view). So we set up a second listener for the detail:view:exists event the detail view triggers when it catches a detail-view:toggle-view event. If we don't hear the detail:view:exists event from the targeted detail view in a timely manner (I'm using 100 ms, but you can play around with that to suit your needs), then we render the view.
initialize: function () {
// Listen to when the detail associated with this list item changes
// the the list item name
this.listenTo(MyApp.EventBus, 'detail-view:change:name', onNameChange);
// Set a property in this view if its detail view exists
this.listenTo(MyApp.EventBus, 'detail:view:exists',
_.bind(function () { this.detailViewExists = true; }, this));
// Create a debounced function that tests whether this view's
// detail view exists
_.debounce(_.bind(this.handleViewState, this), 100);
},
events {
click: 'toggleDetailView'
},
toggleDetailView: function (id) {
MyApp.EventBus.trigger('detail-view:toggle-view', this.model.id);
this.handleViewState();
},
// Debounced function that will wait 100ms asynchronously for the
// detail view to respond. If the detailViewExists bit is not set to true
// then we assume the view does not exist and we render it
handleViewState: function () {
if (!this.detailViewExists)
// The view does not exist, render and attach the view
// Set the bit to false to allow testing in the event that the detail view
// is destroyed in the future
this.detailViewExists = false;
},
changeName: function (id, newname) {
if (this.model.id == id) {
// Change the name of this list item view
this.$('.item-name').text(newname);
}
The take-away
Now, the reference between these two disparate views is the shared unique identifier. Since, by design, these two identifiers are unique in their scope, and should not change, and assuming the detail view has been rendered and attached to the DOM, then regardless of the rendering its state the list item view will always be able to communicate with its detail view.

Registering events works only first time

I have a window, and inside it a panel. The panel contains text (basic html). After the window is ready I call the following function, which finds elements with specific class, and registers click events on them. This works at first.
After closing the window, and recreating 1:1 similar window the events will not fire. The same happens if I .update() the panel and re-run my function - the events fail to fire. Why is this?
I can still see elements being found, and apparently some events must be registered, but my clicks can't be captured by the debug code, or the receiving function anymore.
addEvents: function(win) {
// The Window
var ow = win;
// Using this debug trick I can see that on the second time the events wont fire
// -- nothing gets printed to console
Ext.util.Observable.capture(ow, function(){
console.log(arguments);
});
// Will search for elements, finds elements that have class myclass
// In my case the elements are just ordinary html tags in the visible content
// area of the panel.
var elems = ow.down('panel').getEl().select(".myclass").elements;
Ext.Array.forEach(elems, function (item, index, allItems) {
// We need Ext DOM element to be able to attach stuff to it
var elem = new Ext.dom.Element(item);
elem.on ('click', function (evt, el, o) {
ow.fireEvent('myevent', ow, elem);
});
});
}
I suspected at first that I have to actually unregister the previous events and destroy the window, so I tried adding this to the close of the window:
window.down('panel').destroy();
window.destroy();
However it seems I have some other problem I really am unable to understand.
This is a very JQuery-ish way to add events. You are dealing with components and should add event listeners on components. If you need to delegate events down to html elements then you need to set a single event listener on the Component encapsulating the elements and add delegate config to the actual html elements.
Here are some resources:
Explain ExtJS 4 event handling
Event delegation explained:
http://www.sencha.com/blog/event-delegation-in-sencha-touch (applies to extjs just as well)
More on Listeners with extjs: https://stackoverflow.com/a/8733338/834424

ExtJS form creating help

I'm using extJS 4.
I have a form pop up every time you click edit profile.
The problem is that every time you click edit Profile another form pops up so you can just keep clicking.
Is there a way to make the form only pop up if there isn't one already up.
Thanks for the help!!!
The problem sounds like you are creating a new window on every click of the "edit profile" button/link.
What you need to do is put a check in at the beginning of your form code to check to see if it exists first. If it doesn't, create the window and .show() it... Otherwise, you will just need to .show() it. Be sure to also reset the form if need be. You will also want to try and hide the window instead of destroying it. Otherwise, you will be creating new objects every time.
You can make your form modal, so to block entire interface until you close it, or you can use something like this to your controller to create form:
editProfile: function(button) {
var me = this;
if (!me.win) {
me.win = Ext.widget('editProfile');
// delete the me.win reference if the window gets destroyed
me.win.on('destroy', function() {
delete me.win;
return;
});
}
me.win.show();
}

Resources