pragmar / wiki-plugin-fivestar

Rating plugin for Smallest Federated Wiki
MIT License
2 stars 2 forks source link

Attach keys to ratings, feed key-value pairs into the lineup. #3

Open WardCunningham opened 7 years ago

WardCunningham commented 7 years ago

Note to self: your thoughts about how this plugin can develop will be directed upstream to the pragmar repo, not the federated-wiki repo where you commit. Be comfortable in public.

This plugin could be assembled in number and offered as a template for multi-dimensional ranking of pretty much anything. Say you wanted to rate suppliers on price, inventory and service. You create three FiveStars and add them to the Supplier Template.

Price image Inventory image Service image

Wiki offers Scatter charts and Radar diagrams that are useful for comparing multi-dimensional data. Consider how all of the FiveStars on a given page could be assembled into data compatible with these other plugins. Also consider how a community of consumers could offer independent ratings and have those ratings rolled up and then further analyzed as tuples over supplier page titles and consumer domain names.

The Scatter and Radar plugins expect key/value pairs. Add markup to specify the dimension being rated so that multiple ratings can be aligned. Add journal analysis to recognize when a choice has been made or only inherited through a fork or template. Render the key as part of the star display so that any rearrangement on the page will be recognized as such.

image

WardCunningham commented 7 years ago

Hovers over stars could offer tool-tips suggesting the meaning of each star. For example, a lower price would be more stars, right?

WardCunningham commented 7 years ago

Shouldn't there be a way to rate something zero stars? Or is that not how stars work? In github you get a binary star, off or on, very digital.

WardCunningham commented 7 years ago

I just noticed some similar thinking in a roadmap included in the source comments: https://github.com/pragmar/wiki-plugin-fivestar/blob/master/client/fivestar.js#L5

pragmar commented 7 years ago

Thanks for the feedback, Ward, I'll try and address these comments as best I can. I've not updated the plugin in some time so some of the thinking behind the initial implementation is on the hazy side.

Wiki offers Scatter charts and Radar diagrams that are useful for comparing multi-dimensional data. Consider how all of the FiveStars on a given page could be assembled into data compatible with these other plugins.

If I recall correctly, I used a bare integer for purposes of data simplicity/purity. The thinking was that (a) it would degrade more gracefully in the case it was forked outside of fivestar support, and (b) at the time of initial development, the core plugins I looked to for ideas seemed to be constructed from primitive data types. In a sense, I was rolling with what I thought was customary. I'm certainly not opposed to an extended/stacked data format if that is a common in fedwiki. If you're interested in extending the format, definitely let me know.

Hovers over stars could offer tool-tips suggesting the meaning of each star. For example, a lower price would be more stars, right?

There are conceivable situations where the presentation isn't intuitive, and could benefit from configurable tool tips. I glossed over this since, in the context of film ratings, it's highly intuitive.

Shouldn't there be a way to rate something zero stars? Or is that not how stars work? In github you get a binary star, off or on, very digital.

I may be misunderstanding, but in my mind it's an argument of an embellished checkbox versus and embellished radio button series. Either one is useful, and there are arguments for both. What I find scary would be a multi-paradigm approach that tries to be both. I think the benefits would be cancelled out through an overloaded user interface that could be confusing to the end user. Or are you implying it could be set up one way or the other (not both at the same time)? That could potentially work, though it might require a change the name of the plugin. The current fivestar doesn't have a true "0 stars" context, but an uninitiated state of undefined. Anyways, I'm going long on this response. If you think this is something worth looking into, I'm onboard with merging it.

I just noticed some similar thinking in a roadmap included in the source comments:

This was an intriguing thought, and I remember noting it so as not to forget. My familiarity with the API was not mature enough to dig into it, and it wasn't necessary for the film review site, so it was left on the table.

WardCunningham commented 7 years ago

Here is a good next step for FiveStar markup.

Let us define what will be in the text field in an open-ended way. We focus on simplicity, compatibility, future extension and adhering to conventions established by other plugins.

Example

These words are a note to self that will be
ignored because they are not the last word line
2
Price
HOVER 1 Expensive
HOVER 5 Economical

Common practice is to write a parser that loops over text split into lines, regex matches on the line to detect cases and then returns a hash of recognized values. The parse might also return the line number of the last digit line so as to simplify update.

In our example line 3 contains the star count of 2 and line 4 contains the key of Price. The parser might return an object that makes further processing simple. The form of the parsed text can change at any time because it does not leave the plugin.

{stars:2, line:3, key:"price", hovers:["Expensive", nil, nil, nil, "Economical"}

I would be happy to write such a parser if this would be helpful.

WardCunningham commented 7 years ago

I like the argument for no-stars meaning no choice has been made. The analogy with radio buttons makes the case clear. Let's encase that decision in some numerical reporting logic and thus make it true throughout the federation.

I have previously suggested that the item.text should be interpreted by the plugin and contain more than just the chosen number of stars. This complicates mining wiki's flat files for data because the mining script would need to understand how to parse the number out of the text. Let's have the plugin record what it has made of a choice when the choice happens.

When the plugin updates the item it could revise the text field (upward compatibility) and write new fields with the choice reported various ways. The item stored might then look like this.

{
  "type": "fivestar",
  "text": "blah blah\n2\nblah",
  "key": "price",
  "value": 25.0
}

By quoting the value as a percentage between min and max choices we make it clear that the min of one star represents a percentage of 0.0. ("key" would be omitted if none were provided.)

This built in interpretation would make for a good match with other plugins which I will explore.

pragmar commented 7 years ago

Let me take this into the shop and see what I can do. It may be a few weeks before I can dig in. I'm a bit unsure as to how the configuration would be stored--do you know of a configurable plugin I could look to as a example for storing the configurations (i.e. star count, hovers, etc.), be it at a template, global, or some other scope?

WardCunningham commented 7 years ago

The map plugin stores marker coordinates in the item.text along with various other configuration parameters. Shift-double-clicking on a map adds to this an additional marker with the lat-lon of the point clicked. Here is the code that handles that double-click:

https://github.com/fedwiki/wiki-plugin-map/blob/master/client/map.coffee#L113-L127

At line 125 it modifies the item before saving it with the wiki.pageHandler.put in the update function. This handler is nested within the scope of the emit handler and has access to its variables including those found and returned by the parse function on line 78.

Aside: Map shares markers in several interesting ways. See Hip Portland

Your code looks a lot like this so if you add some more fields to the item, other than text, they will be preserved. The fields item.key and item.value will be write-only to you and not visible except to anyone who reads the flat files on the server.

Aside: If we knew that the user of FiveStar wanted a csv file with the FiveStar settings on all the pages that have them, then we could write a server-side component to FiveStar that read all of the pages, found all of the FiveStar plugins, build an in-memory summary and then returned it as a text file. More on that when asked.

pragmar commented 7 years ago

Ward, I've made progress, but I've run into a problem. When I stuff the value into into a field other than text, it breaks the history feature. That is to say, history visually tracks the configuration that is stored in the text field, but not the value that got dumped into its own space (specifically, a value field). Does that make sense? Should I ditch the idea of alternative value storage, or should history be able to accommodate non-text data?

pragmar commented 7 years ago

FWIW, the text store could be refactored to store star count and selected value as a vulgar fraction. It's a bit more brittle, but on the plus side, it is intuitive. For example, 2/5 would mean a selection of 2-star rating out of 5. An undefined fivestar would just be the number of stars, i.e. 5 (or /5).

WardCunningham commented 7 years ago

Yikes. I hadn't seen any activity here so I took a quick run at separating ratings. What is the chance that we both started the same day? I was prompted by questions in the matrix chat.

https://riot.im/app/#/room/#fedwiki:matrix.org

I plan to work on downstream data handling this weekend. I will want to understand the problem you notice with history? I'm not sure I have it since I both read and write the stars item property.

pragmar commented 7 years ago

Ward, all of my progress thus far is in the fivestar.js. It looks as though that was only lightly modified in the pull request. That's the only file I anticipate working in in the near term, save some possible light edits in fivestar.css. I'll take a closer look at the pull over the weekend and try to figure out what is going wrong in the history--if it continues to be mysterious I'll try and document it in step action.

WardCunningham commented 7 years ago

My implementation in #4 does recall and render the correct stars when clicking through the history in the Journal. But I did find that all is not right with the Journal and the evidence points to some unintended aliasing of Actions.

I'm not completely sure why the FiveStar plugin as originally written worked and both of our revisions don't. I'd like to find this out. Let me note some possible causes.

A particular revision is reconstructed by replaying each Action in the Journal up to and including the selected revision. We show the reconstruction as a "ghost" page because it is no one that is stored in the server.

We can inspect the Journal's json several ways. The file on the server, the JSON link at page bottom, and the Action behind the ghost's timestamp. Double-click to see this last one. In my test these were not in agreement. Yikes.

We keep multiple copies of objects read from json which we sometime think of as json, but not THE json, which is on the server. We have Item json in the dom, copies of Items in each Journal Action, and complete copies of displayed pages in a recently introduced model called the Lineup.

(By recently I mean maybe three years ago. That is when we made an incomplete effort then to stop splattering our model all over the dom, a recognized anti-pattern in many jQuery applications.)

I notice that you do depend on the dom copy of Item json. You still have the arguments of the emit function, container and item, in scope for your click handler. If you confine your manipulations to the inside of these objects then core javascript should work to your advantage.

There are some issues that arise if you bind handlers to dom objects that you later discard. I don't recall that you do. But here are my notes on the subject anyway.

http://plugins.fed.wiki.org/tips-for-binding-events.html

Let me know what you discover or if you'd like for me to take over at any point. For today I will work on the server-side of FourStar and other downstream analysis.

WardCunningham commented 7 years ago

I forgot to mention what I specifically observed when I made a series of edits, 5, 4, 3, 2, 1 stars, leaving me five Actions at the tail end of the Journal.

On disk looks good:

    {
      "type": "edit",
      "id": "947cb8e17d957b87",
      "item": {
        "type": "fivestar",
        "id": "947cb8e17d957b87",
        "text": "top",
        "stars": "3"
      },
      "date": 1494683153082
    },
    {
      "type": "edit",
      "id": "947cb8e17d957b87",
      "item": {
        "type": "fivestar",
        "id": "947cb8e17d957b87",
        "text": "top",
        "stars": "2"
      },
      "date": 1494683155091
    },
    {
      "type": "edit",
      "id": "947cb8e17d957b87",
      "item": {
        "type": "fivestar",
        "id": "947cb8e17d957b87",
        "text": "top",
        "stars": "1"
      },
      "date": 1494683157517
    }
  ]
}

Reported by the page, from the dom (I believe), looks wrong:

    {
      "type": "edit",
      "id": "947cb8e17d957b87",
      "item": {
        "type": "fivestar",
        "id": "947cb8e17d957b87",
        "text": "top",
        "stars": "1"
      },
      "date": 1494683153082
    },
    {
      "type": "edit",
      "id": "947cb8e17d957b87",
      "item": {
        "type": "fivestar",
        "id": "947cb8e17d957b87",
        "text": "top",
        "stars": "1"
      },
      "date": 1494683155091
    },
    {
      "type": "edit",
      "id": "947cb8e17d957b87",
      "item": {
        "type": "fivestar",
        "id": "947cb8e17d957b87",
        "text": "top",
        "stars": "1"
      },
      "date": 1494683157517
    }
  ]
}

From the timestamp, penultimate revision, looks right:

image

WardCunningham commented 7 years ago

Through some chrome inspector heroics I've managed to get at the pageObject in the Lineup model and find it contains similarly corrupted star counts in Actions.

image

pragmar commented 7 years ago

Thanks for digging into this. I'm glad you were able to capture the behavior, I was worried it was something specific to my development environment. The important takeaway on my end is that storing to an alternative field (i.e. stars) is an acceptable strategy within the framework. I think I'm going to back off on history/journal side and instead focus on integrating the pull request with my local dev.