Wanikani Open Framework [developer thread]

I have started experimenting with an html type filter. Here is what I have found.

The plan is to implement a better user interface for the Item List filter. I think we should go for a button type because of the limited screen real estate of a filter interface, but let’s do html first.

I want to insert this html. The classes are not there yet. I just check if the html inserts properly.

    let htmlString = '<div>' +
                      '<p>Radicals</p>'+
                      '<input type="text"></input>'+
                      '<p>Kanjis</p>'+
                      '<input type="text"></input>'+
                      '<p>Vocabulary</p>'+
                      '<input type="text"></input>'+
                     '</div>';

I have modified to filter loading code to handle html like this:

                    case 'html':
                        flt_content[src_name+'_flt_'+flt_name] = {
                            type:flt.type,
                            label:flt.label,
                            html:flt.html,
                            default:flt.default,
		                 	hover_tip:flt.hover_tip,
                        }
                        break;

According to the doc default and hover_tip are not going to be used, but I included them anyway. The result is this.

html

Upon inspecting the elements I have found that:

  • The row is not wrapped into a <div class="row">
  • There is no checkbox and no div to include one.
  • The html is not wrapped into a <div class="right">

These elements are present in all the good looking rows, so I guess they must be included for html as well.

Then there is this: ( from the wkof doc)

The html component does not store a value. However, you can attach event handlers to the html via the global pre_open callback.

In the context of a filter I am not setting up the dialog. I don’t have access to the pre_open callback. I don’t see how I can attach event handlers.

And now this:

I have looked at the code. This is not going to work because there is no path associated with the individual elements. setting_changed() stores them all at the same path which is associated to the whole html type.

Some suggestions

I think we can avoid the complexity of associating paths to an unknown html structure by storing an object in the lone path provided by the framework. The html callback and event handlers will have the responsibility to map this object to the individual elements.

I suggest that an html configuration should be like:

html_id: {
    type: 'html',
    label:          // (optional) A string label that appears to the left of (or above) the inline html.
    html:           // An html string to be inserted inline.
    path:           // The path where the object value will be stored
    default:        // A default object value
    pre_open:       // A callback that will be called prior to the opening of the dialog
    hover_tip:      // A hover tip that will be applied to the label but not to the html.
}

The signature of pre_open should be:

pre_open(root_elem, object, on_change)

root_elem : The DOM element where the html is located.
object: The object stored at the path when pre_open is called.
on_change: A callback that will inform the framework of a new object value

The signature of on_change should be:

on_change(object)

object is the new value to be stored in the settings.

I think this solution will work for a button as well except that instead of ‘pre_open’ it will be ‘on_click’ and the root_elem.parameter is not required for a button.

You have more experience than me with this sort of things. Do you see flaws or ways to improve on this?

Edit: I made another test for html.

I asked for this string.

    let htmlString2 = '<div class="row">' +
                          '<div class="enable">' +
                              '<input type="checkbox">' +
                          '</div>' +
                          '<div class="left">' +
                              '<label for="for="Item_Inspector_wk_items_flt_listed_items"">' +
                                   'Listed Items' +
                              '</label>' +
                          '</div>' +
                          '<div class="right">' +
                              '<p>Radicals</p>'+
                              '<input type="text"></input>'+
                              '<p>Kanjis</p>'+
                              '<input type="text"></input>'+
                              '<p>Vocabulary</p>'+
                              '<input type="text"></input>'+
                          '</div>'
                      '</div>';

In other words I tried to do manually what is expected from the framework, and I removed the label from the registry function.

	function registerItemListFilter() {
		wkof.ItemData.registry.sources.wk_items.filters[itemListFilterName] = {
			type: 'html',
            html: htmlString2,
			//label: 'Listed Items',
			default: false,
			filter_func: itemListFilter,
			set_options: function(options) { return; },
			hover_tip: itemListdHover_tip,
		};
	}

The result is this.

html

This is an improvement. The checkbox and the <div class=""row> container were added on top of those I provided. And I get the html properly styled. So it seems that requesting a label while registering is buggy. We can workaround the bug by providing the label manually.

To test that I tried this html. I don’t request a label and I supply one manually. My expectation is that if I don’t provide a checkbox and a class="row" container the framework will provide one and there will be no duplication.

    let htmlString2 = '<div class="left">' +
                          '<label for="for="Item_Inspector_wk_items_flt_listed_items"">' +
                               'Listed Items' +
                          '</label>' +
                      '</div>' +
                      '<div class="right">' +
                          '<p>Radicals</p>'+
                          '<input type="text"></input>'+
                          '<p>Kanjis</p>'+
                          '<input type="text"></input>'+
                          '<p>Vocabulary</p>'+
                          '<input type="text"></input>'+
                      '</div>';

The result is this.

html

Now there is no checkbox and no <div class="row"> container. The bug is no so simple as I thought.

It would be good to have the label on top of the html and have the html use the full width of the filter panel. This would be a much better use of the screen estate. This filter would need it. Is there any provision in the framework for this? Or do I have to cook up some css?

I did more tests hoping to find a html that works. I failed. But I have to report that this one gives me a crash.

    let htmlString2 = '<div class="row">'+
                           '<div class="left">' +
                              '<label for="for="Item_Inspector_wk_items_flt_listed_items">' +
                                   'Listed Items' +
                              '</label>' +
                          '</div>' +
                          '<div class="right">' +
                              '<p>Radicals</p>'+
                              '<input type="text"></input>'+
                              '<p>Kanjis</p>'+
                              '<input type="text"></input>'+
                              '<p>Vocabulary</p>'+
                              '<input type="text"></input>'+
                           '</div>' +
                      '</div>';

html