Custom JSON renderer in AEM/Sling - json

I've been playing around with this for a while now, and I think, I've - almost - cracked it, but I am still not fully satisfied with my solution.
So, what I want to do, is having a piece of content, a list of items, which would have two views: The standard HTML one, so people can view and edit it; and then a JSON endpoint for other services to consume.
First I thought it's a simple matter of creating two JSP scripts to render the content:
/apps/my-stuff/components/list-page/html.jsp
/apps/my-stuff/components/list-page/json.jsp
However the Apache Sling DefaultServlet seems to be rather ignorant of the json.jsp script.
As a second attempt, I created another script, in /apps/foundation/components/primary/cq/Page/json.jsp which will be actually called, and renders the page, as I expected. However there are a couple of worries/questions regarding this:
First of all, why is this being honoured by the system, and not the one in the more specific place?
The documentation states, that to find the appropriate renderer, first sling:resourceType will be inspected, then sling:resourceSuperType and then, only as a fallback will jcr:PrimaryType checked. However I think this is rather: jcr:PrimaryType, then the DefaultServlet, and then all the other things.
Most worryingly however, I have to admit, this is rather generic, so it'll break all the contnet with jcr:PrmaryType = Page, so that could have some side-effects.
A solution could be creating a new type: ListPage extends Page; and then create a renderer for that in /apps/foundation.... However I have this bad feeling, that might introduce other problems.
So my question is two fold: What is the proper way of doing this, and/or what am I missing from the way the URL -> script resolution is working in AEM/Sling. (Because it seems to be slightly different that described here and here.)
(Obviously I am trying to keep the default JSON renderer for other pages, as that might be needed for other things in the page. I am not even sure, changing this one page won't break the UI for this particular page...)

However the Apache Sling DefaultServlet seems to be rather ignorant of the json.jsp script.
Have you tried renaming your JSP like so: "list-page.json.jsp"?
If you're using AEM 6.3, you should look at Sling model Exporters. They allow you to automatically register a servlet against your Sling Model (that you can create to model your list content). That servlet can generate a JSON representation of the model for you using Jackson.
If you're not using AEM 6.3, I would suggest you create a servlet registered against your resource type and use an additional selector.
#SlingServlet(
selectors = "json",
resourceType = "my-stuff/components/list-page",
methods = "GET")
More information on Sling Servlets can be found here.

Related

Accessing regmap RegFields

I am trying to find a clean way to access the regmap that is used with *RegisterNode for creating documentation and testing files. The TLRegisterNode has methods for generating the json through some Annotations. These are done in the regmap method by adding them to the ElaborationArtefacts object. Other protocols don't seem to have these annotations.
Is there anyway to iterate over the "regmap" Register Fields post elaboration or during?
I cannot just access the regmap as it's not really a val/var since it's a method. I can't quite figure out where this information is being stored. I don't really believe it's actually "storing" any information as much as it is simply creating the hardware to attach the specified logic to the RegisterNode based logic.
The JSON output is actually fine for me as I could just write a post processing script to convert JSON to my required formats, but I'm wondering if I can access this information OR if I could add a custom function call at the end. I cannot extend the case class *RegisterNode, but I'm not sure if it's possible to add custom functions to run at the end of the regmap method.
Here is something I threw together quickly:
//in *RegisterRouter.scala
def customregmap(customFunc: (RegField.Map*) => Unit, mapping: RegField.Map*) = {
regmap(mapping:_*)
customFunc(mapping:_*)
}
def regmap(mapping: RegField.Map*) = {
//normal stuff
}
A user could then create a custom function to run and pass it to the regmap or to the RegisterRouter
def myFunc(mapping: RegField.Map*): Unit = {
println("I'm doing my custom function for regmap!")
}
// ...
node.customregmap(myFunc,
0x0 -> coreControlRegFields,
0x4 -> fdControlRegFields,
0x8 -> fdControl2RegFields,
)
This is just a quick example I have. I believe what would be better, if something like this was possible, would be to have a Seq of functions that could be added to the RegisterNode that are ran at the end of the regmap method, similar to how TLRegisterNode currently works. So a user could add an arbitrary number and you still use the regmap call.
Background (not directly part of question):
I have a unified register script that I have built over the years in which I describe the registers for a particular IP. It works very similar to the RegField/node.regmap, except it obviously doesn't know about diplomacy and the like. It will generate the Verilog, but also a variety of files for DV (basic `defines for simple verilog simulations and more complex uvm_reg_block defines also with the ability to describe multiple of the IPs for a subsystem all the way up to an SoC level). It will also print out C Header files for SW and Sphinx reStructuredText for documentation.
Diplomacy actually solves one of the main issues I've been dealing with so I'm obviously trying to push most of my newer designs to Chisel/Diplo.
I ended up solving this by creating my own RegisterNode which is the same as the rocketchip RegisterNodes except that I use a different Elaboration Artifact to grab the info and store it for later.

How to Simulate a Keyboard Event in Dart HTML

1. Problem and Context
I'm trying to create a browser extension with Dart, more specifically, one that deals with adding keyboard shortcuts to certain websites.
To guarantee better TDD, I'm trying to simulate keyboard events during the tests. However, it seems like many things have changed when it comes to Dart's HTML APIs and I haven't been able to figure out how to make them work.
2. What I'm Trying
I would like to register a specific keystroke — so the generic KeyboardEvent won't cut it apparently, only the KeyEvent class can handle that. So far, I'm trying something like this:
document.body.dispatchEvent(KeyEvent('keypress', keyCode: 65, charCode: 97));
From which I receive an error close to this:
Error: Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.
I've also tried the code above with document, document.window and window, none worked. Something similar can be found in the KeyEvent documentation. However, they mention adding to a Stream, which I don't think is possible. It would have to be a Sink instead.
If I'm not able to solve this via dispatching events, I think I'll have to simply inject mocks into the tests.
3. More Resources
2 outdated answers which have helped me so far were:
dart how to create, listen, and emits custom event?
How do I listen for custom events in Dart?

The best solution for background application logic?

I have 2 different types components. They both only use and contain an HTML5-canvas element, but need to show different types of data on a chart:
Component A (Only ever 1 of these)
Component B (0 to 4 of these)
Both components need the dateTime of the first data-entry from the two data-sets, but the dateTime of the last entry comes from their own respective data-sets.
Component A needs its first entry date from Component B.
Currently I do it like this:
Component B has the method that finds the date-limits from its own dataset. Using an Observer-pattern & Subjects, I broadcasts the returned dates through a service and into Component A.
The problem with this though, is that coupling suddenly becomes pretty tight. I can't initialize component A first, because it needs B to do its calculation first. Both components ideally should initialize and show/share their data simultaneously, and continue to do so. (E.g. If a user scrolls in one chart it should scroll all other components too, and so on.)
This is why I wanted an extra layer added on top of these components. A controller if you will.
I can't figure out what's best though:
A shared service that can take external data as input?
A container component? (Transclusion)
Another component, Component C, that A & B are children of?
As I'm still new to Angular 2, it's hard to tell which approach is best for future maintenance/development?
I'm being drawn towards creating another normal component as a parent, and have this component send and receive data to/from its children (A & B) as necessary.
I'm also uncertain as to what's "best practice" and if you can just use a component like an empty 'logic shell'. I've tried reading here and there, and I've found a lot, but I can't seem to get an exact answer to my question. It'll take time before I can comprehend all this knowledge and answer it myself, so I'm hoping someone could give me a helping nudge, thanks.
PS: I should add that my angular application will be a child-component in larger application, and will get its data from some other parent comp.
Why don't you put your logic into services?
You can also set up service hierarchies by injecting sub-services into a parent service.
If your logic is not UI / interaction related, you should put it into reusable services. If your logic is UI related, you could set up a parent component acting as a mediator between A and B (acting on their respective input/output parameters)
Whatever you do, it is a good idea to keep concerns separate.
Both A and B should not need to care about other components needing their output. Angular has Input/Output parameters for that.
Don't put some generic datetime calculation stuff into components. Make it reusable through services.
Keep coupling loose by introducing interfaces and injections.
Update:
Services should only use injectable constructor parameters, so you should pass your input using methods (or setters, but that is less expressive).
To pass arbitrary JSON objects, you could utilize any parameters. However if your json follows a certain structure, you could define an interface.
public doStuff(input: any): any { }
or
interface IMyDataContract {
dateField: string;
}
public doStuff(input: IMyDataContract): any { }

om.next: how to have multiple components that use the reconciler

I'm new to om.next (and to clojurescript), and I have the following question. I can only get the root component to be invoked with the reconciler (i.e. have its query method invoked); every other component seems to need to be invoked with props and with om/factory. I think I'm missing something.
I am attempting to create a todo list app (100 points for originality!), with a filter to show completed/incomplete/all items. If my TodoList component is the root component, I can invoke it with query: [:todos] with no problem. I'd like to have a different root component, and also have a Filter component that goes through the reconciler.
Possible options I can see:
have multiple om/add-root! calls (this prevents us from having nested components that use the reconciler, and is not the pattern that I see in tutorials)
wrap everything in a global component and pass state down through props. But the examples make read a multimethod, which doesn't jive with this approach.
Is this possible? Thank you!
If you haven't already please take a look at Components, Identity & Normalization · omcljs/om Wiki · GitHub. This tutorial shows how to organize a multi-component application under a single root - and it should also make clear how read, mutate, Ident, IQuery, etc. are being used by each individual component to coordinate interaction with the one-and-only app state via the reconciler. The app-state is basically the application's database - using nested data structures inside a single Map.
React applications typically only have a single root component - if there are multiple roots they are typically organized by routes, i.e. one root per route (see also Top-level React Components — Medium).
Also: Om/Next: The Reconciler — Medium
The concept behind Om Next (and others such as reframe) is that there is one source of truth - your app state. With Om Next the UI of your application is made up of one (upside down) component tree. During rendering your app state is loaded into your Root component by Om Next interpreting its static query. This app state is received as 'props'. It is your job to pick these props apart and hand 'sub props' down the rest of the tree. You do this in the render method of each of your components.
So your second option is the way to go. reads are related to keywords that are in your static component queries. If you make sure that your state is in default db format, then in fact every read can be implemented the same way, making use of db->tree. Having a global component and making every read a multimethod are unrelated concepts, and thus not incompatible. In fact having both is quite idiomatic.
There are ToDo application examples already that you may wish to look at for reference: here and here.
One thing to note is that your Root component query will use joins to include the other components, so your query [:todos] does not look right to me. Something like [{:todos (om/get-query TodoList)}] would be better :-)

Angular - building a "public" function (newbie)

I'm After several days learning angularJS through converting my standart JS app to a ng one.
I was wondering about this simple scenario:
I have a global function called fb_connect(),
it can be used from any page (or any controller if you like) to make a facebook-based login.
This function makes a simple http call and receives a JSON object contain data to move on (display a pop up, login, etc...)
I read that I can define a Factory or a Service for my app and use it in any controller, which works fine.
So, I created a fb_connect factory function.
The problem is that now, in every page (every controller), I have to define that fb_connect in the constructor of every controller - for example :
function welcome($scope,fb_connect){});
What is the proper way to do this kind of actions using Angular without having to define these functions each and every time in every controller?
Thanks
Setting up factories and services is all part of the dependency injection system of Angular. Using that system is great when you need to create things that depend on other injected things. It's a big tree of dependencies. It's also nice for creating singletons, such that everywhere in your code end up using the same instance of some object.
It sounds to me like neither of these benefits apply in your case. I'd suggest just not using Angular's DI for it. You have some function defined globally, just call it directly and skip the DI. There's nothing wrong with that.
Of course you say it makes an Ajax call, so doesn't depend on the Angular $http service?
Your two options are:
Declare the function on the $rootScope
Inject it as a service
My advice is to go with making it a service. The whole purpose of services is explained in the Angular.js docs, just like this quote:
Angular services are singletons that carry out specific tasks common to web apps... To use an Angular service, you identify it as a dependency for the dependent (a controller, or another service) that depends on the service.
As you mentioned in your question, you'd prefer to not define the service in every controller you wish to use it in. With $rootScope you'll be injecting that also in every controller. So really it's a question of which you prefer, although to answer your question, the proper way of using a factory or service is to inject it into the controller you wish to use it in.
You can always put it in the $rootScope
myApp.run(function($rootScope, fb_connect){
$rootScope.welcome = function(){
};
});