CalendarKit - EventView has no member data - calendarkit

I've tried to replicate the "Usage" section of CalendarKit's documentation and I simply can't get the EventView.data when the user selects an EventView.
My controller conforms to DayViewController and the EventViews display normally on the DayView on my screen.
override func dayViewDidSelectEventView(_ eventview: EventView) {
print("Event has been selected: \(eventview.data)")
}
This is the method being executed when the user presses the EventView and the only problem is that "eventview has no member data". I've checked the definition of the library class and it really has no data member or no methods that would extract the event or anything.
Basically the question is - How do I get the event data here?
I understand that this is simple and I thank you for sparing some time in order to help.

thank you for your question. The documentation is not up-to-date, I'll make sure to update it.
Please, use the following approach to get the EventDescriptor which would help you identify the event in your application model layer. For example, you could use userInfo dictionary to store an event identifier.
override func dayViewDidSelectEventView(_ eventView: EventView) {
guard let descriptor = eventView.descriptor as? Event else {
return
}
print("Event has been selected: \(descriptor) \(String(describing: descriptor.userInfo))")
// You can use the userInfo dictionary to identify which event has been selected
}

Related

Kotlin-Firebase-cannot utilize the string read from database further down in the code

I have managed to read data from my firebase database but cant seem to re-use the String which has been read.
My successful read is as per below. When i check the logcat for the Log.d("Brand") it actually shows the String as expected.
brandchosenRef=FirebaseDatabase.getInstance().reference
val brandsRef = brandchosenRef.child("CarList2").orderByChild("Car").equalTo(searchable_spinner_brand.selectedItem.toString())
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for(ds in dataSnapshot.children){
Log.d("spinner brand",searchable_spinner_brand.selectedItem.toString())
val Brand = ds.child("Brand").getValue(String::class.java)
val brandselected= Brand.toString()
Log.d("Brand","$brandselected")
selectedbrand== brandselected
Log.d("selected brand",selectedbrand)
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("Branderror","error on brand")
}
}
brandsRef.addListenerForSingleValueEvent(valueEventListener)
What i am trying to do is write "selectedbrand" into a separate node using the following:
val carselected = searchable_spinner_brand.selectedItem.toString()
val dealref = FirebaseDatabase.getInstance().getReference("Deal_Summary2")
val dealsummayId = dealref.push().key
val summaryArray = DealSummaryArray(dealsummayId.toString(),"manual input for testing","brand","Deal_ID",carselected,extrastext.text.toString(),otherinfo.text.toString(),Gauteng,WC,KZN,"Open")
dealref.child(dealsummayId.toString()).setValue(summaryArray).addOnCompleteListener{
}
Note, in the above i was inputting "manual input for testing" to check that my write to Firebase was working and it works as expected. if i replace that with selectedbrand, then i get the below error.
kotlin.UninitializedPropertyAccessException: lateinit property selectedbrand has not been initialized
the summary array indicated above is defined in a separate class as follows. and as seen "manual input for testing is declared as String.
class DealSummaryArray(val id:String,val brand:String,val Buyer_ID:String,val Deal_ID:String,val Car:String,val extras:String,val other_info:String,val Gauteng:String,val Western_Cape:String,val KZN:String,val Status:String) {
constructor():this("","","","","","","","","","",""){
}
}
My question simply put, it why can i not re-use the value i read from the database? even if i was not trying to re-write it to a new node i cannot seem to utilize the value outside of the firebase query.
I seem to get this problem everywhere in my activities and have to find strange work around's like write to a textview and then reference the textview. please assist.
Data is loaded from Firebase asynchronously, as it may take some time before you get a response from the server. To prevent blocking the application (which would be a bad experience for your users), your main code continues to run while the data is being loaded. And then when the data is available, Firebase calls your onDataChange method.
What this means in practice is that any code that needs the data from the database, needs to be inside the onDataChange method or be called from there. So any code that requires selectedbrand needs to be inside onDataChange or called from there (typically through a callback interface).
Also see:
How to check a certain data already exists in firestore or not, which contains example code including of the callback interface, in Java.
getContactsFromFirebase() method return an empty list, which contains a similar example for the Firebase Realtime Database.
Setting Singleton property value in Firebase Listener, which shows a way to make the code behave more synchronous, and explains shows that this may not work on various Android versions.

Knockout components using OOP and inheritance

I was hoping I could get some input on how to use Knockout components in an object-oriented fashion using Object.create (or equivalent). I'm also using Postbox and Lodash, in case some of my code seems confusing. I've currently built a bunch of components and would like to refactor them to reduce code redundancy. My components, so far, are just UI elements. I have custom input boxes and such. My initial approach was as follows, with some discretion taken to simplify the code and not get me fired :)
// Component.js
function Component() {
var self = this
self.value = ko.observable()
self.initial = ko.observable()
...
self.value.subscribeTo('revert', function() {
console.log('value reverted')
self.value(self.initial())
}
}
module.exports = Component
// InputBox.js
var Component = require('./Component')
var _ = require('lodash')
function InputBox(params) {
var self = this
_.merge(self, params) // quick way to attach passed in params to 'self'
...
}
InputBox.prototype = Object.create(new Component)
ko.components.register('input-box', InputBox)
Now this kind of works, but the issue I'm having is that when I use the InputBox in my HTML, I pass in the current value as a parameter (and it's also an observable because the value is retrieved from the server and passed down through several parent components before getting to the InputBox component). Then Lodash merges the params object with self, which already has a value observable, so that gets overwritten, as expected. The interesting part for me is that when I use postbox to broadcast the 'revert' event, the console.log fires, so the event subscription is still there, but the value doesn't revert. When I do this in the revert callback, console.log(self.value(), self.initial()), I get undefined. So somehow, passing in the value observable as a parameter to the InputBox viewmodel causes something to go haywire. When the page initially loads, the input box has the value retrieved from the server, so the value observable isn't completely broken, but changing the input field and then hitting cancel to revert it doesn't revert it.
I don't know if this makes much sense, but if it does and someone can help, I'd really appreciate it! And if I can provide more information, please let me know. Thanks!
JavaScript does not do classical inheritance like C++ and such. Prototypes are not superclasses. In particular, properties of prototypes are more like static class properties than instance properties: they are shared by all instances. It is usual in JS to have prototypes that only contain methods.
There are some libraries that overlay a classical-inheritance structure onto JavaScript. They usually use "extends" to create subclasses. I don't use them, so I can't recommmend any in particular, but you might look at Coffeescript if you like the classical-inheritance pattern.
I often hear "favor composition over inheritance," but I generally see a lot of emphasis on inheritance. As an alternative, consider Douglas Crockford's "class-free object-oriented programming", which does away with inheritance entirely.
For what you're trying to do here, you probably want to have InputBox initialize itself with Component, something like:
function InputBox(params) {
var self = this
Component.bind(self)(); // super()
_.merge(self, params) // quick way to attach passed in params to 'self'
...
}
The new, merged, value will not have the subscription from Component, because the subscription is particular to Component's instance of the observable, which will have been overwritten.
To everyone who responded, thank you very much! I've found a solution that works better for me and will share it here in case anyone is interested.
// Component.js (only relevant parts shown)
function Component(params) {
var self = this
_.merge(self, params)
self.value.subscribeTo('some event', function() {
// do some processing
return <new value for self.value>
}
module.exports = Component
// InputBox.js
var Component = require('./component')
function InputBox(params) {
var self = this
Component.call(self, params)
}
By taking this approach, I avoid the headache of using prototypes and worrying about the prototype chain since everything Component does is done directly to the "inheriting" class. Hope this helps someone else!

Dispatch messages from a safari extension popover to the global page

I have a safari extension popover that needs to communicate with its global page. From a content-script I am using
safari.self.tab.dispatchMessage(name,data);
to accomplish that. From a popover I didn't find a way to do that. I know that I can access methods in the global page directly
safari.extension.globalPage.contentWindow
but my goal was to reuse code fragments that are already used in content-scripts. I do the same for the chrome version of the plugin.
Is there code for a little clever proxy that emulates
safari.self.tab.dispatchMessage(name,data);
from the popover?
To be honest it's probably just easier to have different code in your popover and injected scripts. If you really want, you could do something like this:
function dispatchMessage(name, message) {
if (safari.self.tab) {
safari.self.tab.dispatchMessage(name, message);
} else if (safari.extension.globalPage.contentWindow) {
safari.extension.globalPage.contentWindow.handleMessage({name: name, message: message});
}
}
Then just use dispatchMessage('foo', 'bar') in both your popover and injected scripts. It's a bit hacky though, because the message event object normally has more information on it than just the name and message, and you have to ensure that your handleMessage function is actually the same function that is assigned as the message event listener in the global page.
A simplistic way to accomplish reusing your message-based content script code in your popover is by wrapping the safari.self.tab.dispatchMessage calls in an abstraction function that I'll describe below...
But first, you need to make sure to have a single named handler function in your global page that handles all messages, like this:
function handleMessage(evt) {
switch (evt.name) {
case 'Message1':
// do something with evt.message
break;
case 'Message2':
// do something else with evt.message
break;
}
}
safari.application.addEventListener('message', handleMessage, false);
If you have separate handlers for each different message, or if you're using an anonymous function, this approach will not work.
Now, the wrapper function that goes in your popover and content scripts is very simple:
function tellGlobalPage(msgName, msgData) {
if (safari.self instanceof SafariExtensionPopover) {
// this script is running in a popover
var fakeMsgEvt = { name: msgName, message: msgData };
safari.extension.globalPage.contentWindow.handleMessage(fakeMsgEvt);
} else {
// this script is a content script
safari.self.tab.dispatchMessage(msgName, msgData);
}
}
And then instead of safari.self.tab.dispatchMessage(name, data), you use tellGlobalPage(name, data).
Please note that this simplistic approach doesn't deal with roundtrip messaging, where the popover or content script sends a message to the global page, and the global page replies with another message. There are other approaches that can handle that.

How to make a propertysheetpage be a selection provider?

I've got a contributed command and a handler for it. The handler's execute event has to get the value for the property actually selected in the properties view and act on it, or to be disabled if no property selected.
I've tried:
1) Set the selection provider to something which provides selection from the property view. Something in this case is just PropertySheetViewer for my PropertySheetPage, but i can't set it as the selection provider because the PropertySheetPage's viewer is private and has no getter.
2) Overriding PropertySheetPage's createControl method: This method creates a Tree control for the PropertySheetViewer. A selection listener can be installed for that tree control, so maybe i can make my command handler implement SelectionListener... The solution would be somethin like:
In my editor:
public Object getAdapter(#SuppressWarnings("rawtypes") Class type) {
if (type == IPropertySheetPage.class) {
PropertySheetPage page = new PropertySheetPage() {
#Override
public void createControl(Composite parent) {
super.createControl(parent);
IHandler handler = someWayToGetMyCmdHandler();
((org.eclipse.swt.widgets.Tree) getControl())
.addSelectionListener(handler);
}
};
IPropertySheetEntry entry = new UndoablePropertySheetEntry(
getCommandStack());
page.setRootEntry(entry);
return page;
}
return super.getAdapter(type);
}
And my command handler implementing SelectionListener as i said... The problem with this approach is that i can't find a way to get a reference to my contributed command handler (someWayToGetMyCmdHandler() above).
Has anybody got any clue on this, or any other possible approach to the problem??
There's handleEntrySelection(ISelection selection) method in PropertySheetPage that you could override to be notified about selection changes in the viewer (although PropertySheetPage is #noextend).
The second part (updating the handler) is a bit more tricky than it would normally be. Commands/handlers get updated automatically when workbench selection changes (you just need to implement setEnabled(Object evaluationContext) AbstractHandler). But since PropertySheetPage is designed to change its input on global selection change, then you have to find some custom way to notify/update your handler.
As I understand, it is currently not possible to extend the platform command event handling mechanism with custom variables, so you just need to directly look up your handler using IHandlerService of the workbench.

Dojo: Is there an event after drag & drop finished

I've got two dojo.dnd.Sources with items. Whenever an item is dropped I need to persist the new order of the items in the Sources using an xhr.
Is there an dojo event or topic that is fired after an dnd operation has (successfully) finished? What would be the best way to use it?
Probably I don't understand the problem in all details but I don't see why you need to process events or topics. The best way to record changes is to intercept updating methods on relevant sources. Specifically you need to intercept insertNodes() for drops or any other additions.
Simple example (pseudo-code):
var source1, source2;
// ...
// initialize sources
// populate sources
// ...
function getAllItems(source){
var items = source.getAllNodes().map(function(node){
return source.getItem(node.id);
});
return items;
}
function dumpSource(source){
var items = getAllItems(source);
// XHR items here to your server
}
function recordChange(){
// now we know that some change has occured
// it could be a drop or some programmatic updates
// we don't really care
dumpSource(source1);
dumpSource(source2);
}
dojo.connect(source1, "insertNodes", recordChanges);
dojo.connect(source2, "insertNodes", recordChanges);
// now any drop or other change will trigger recordChanges()
// after the change has occurred.
You can try to be smart about that and send some diff information instead of a whole list, but it is up to you to generate it — you have everything you need for that.
You can use dojo.subscribe to do something when a drop is finished like so:
dojo.subscribe("/dnd/drop", function(source, nodes, copy, target) {
// do your magic here
});
There's examples of using subscribe on the dojotoolkit tests site. More info about dojo publish and subscribe too.
Alternately, you could connect to the onDndDrop method.
var source = new dojo.dnd.Source( ... );
dojo.connect( source, "onDndDrop", function( source, nodes, copy, target ) {
// make magic happen here
});
connect methods are called at the end so the items will be there at that point.
I'm keeping this note for dojo Tree folks just like me who would run in to this problem. Solutions given here was not quite worked well in my situation. I was using a dijit.tree.dndSource with Dojo tree and subscribing to "/dnd/drop" allows me to capture the event even though at that point my underlying data store hadn't been updated with latest changes. So I tried waiting as Wienczny explains, that doesn't solve the problem completely as I can't rely on a timeout to do the waiting job. Time taken for store update could be vary, i.e. shorter or very long depends on how complex your data structure is. I found the solution with overriding the onDndDrop method of the dndController. Simply you can specify the onDndDrop : on your tree initialization. One thing I found odd though you can not hitch this method, you will get weird behavior during dnd.
Tree
this._tree = new MapConfigTree({
checkAcceptance: this.dndAccept,
onDndDrop: this.onDndDrop,
betweenThreshold:5,
method
onDndDrop : function(source, nodes, copy, target){
if(source.dropPosition === 'Over' && (target.targetAnchor.item.type[0] == 'Test layer')) {
this.inherited(arguments);
// do your bit here
} else {
this.onDndCancel();
}
}