Coder Social home page Coder Social logo

other.js's Introduction

other.js Build Status Coverage Status chat

A JavaScript library for building Chatternet features.

  • Rational Multiple layers of abstraction, each explained in terms of the layer beneath. Never magic. Inspired by rational web platform principles.
  • Robust Features are written in environment-agnostic ES6 code that is adapted to execute across Other Chat's client or server environments as appropriate.
  • Rapid Feature code is succinct and pickup-able. No assumptions about your technology stack, so bring your fancy build system or just start typing.

Get started

Start with the feature creation documentation.

Contribute

See contribution instructions to contribute to the other.js library or the embedding instructions to learn how to embed other.js into a client.

other.js's People

Contributors

tonygentilcore avatar aza avatar bs avatar ruudderooij avatar captdaylight avatar

Stargazers

Ali Torki avatar Denys Sedchenko avatar Piérre Reimertz avatar  avatar Benjamin Allen avatar Josh Deeden avatar  avatar

Watchers

Josh Deeden avatar  avatar  avatar Juan-Carlos Foust avatar James Cloos avatar  avatar  avatar

Forkers

reimertz

other.js's Issues

Proposal: always default to courier's format when passing data between other.js and host

Consider this proposal a straw man to provoke conversation

Increasingly an embedding client and other.js will pass data between each other. Considering all clients as well as other.js will communicate and parse responses from courier, courier's format for representing data should serve as the default medium for moving data between other.js and its host.

For example, if other.js were to return an identity object that object shuld be indistinguishable from a deserialized identity JSON response from GET /identity/{id}.

cc @tonygentilcore @adamrothman

Deep dream

I'm not sure exactly how the UX should work, but it should definitely be easy to apply deep dream style filters to images before posting them. Ideas?

Blocked on #10

/slash command spec

This is a strawman WIP investigation of /slash commands. Includes speculative stuff.

  • /foo [argument]

Slash commands format a message a particular way, and can take (optional) arguments as an unstructured string, a typed entity (e.g., channel or identity), staged objects, or a set of options exposed in chat complete.

For example:/album:

  • no arguments: creates an empty album container message
  • with images/gifs staged: creates an album container message with those images/gifs
  • /album #channel: creates an album from the images in the channel (the channel is the backing datastore)

Examples of general usage:

  • Put /playlist #channel in #channel's pocket for an auto-updating widget to play all songs in channel
  • Put /album #channel/bestpics in the #channel's pocket for a socially curated album
  • /map @juanxa/berlin for a map of all locations JC loves in Berlin
  • /calendar @greatcaeser/tour a calendar view of Great Caeser's tour
  • By default, we will probably include /related #channel in each channel's pocket, which users can remove. (Opens up the possibilities of /related @user and /related [gif entity] and /related [restaurant entity] (Thinking about every object as a hyperconversation entity: a read-only channel with the object as the only message, and a pocket; and in this light /related is unified across all of the above examples)
  • /points #jaunxa would create a leaderboard object of the points given to people in JC's channel (or perhaps of the members of JC's channel?)
  • /h1 Tree Frogs, /caption The Cutest, /blockquote (the last inserts an empty blockquote which can be edited via the normal interface—this lets you create content templates easily).
  • /article @za/blog/sometitle formats a channel as an article and/or summary (also: /summary http://example.com/article)
  • /playlist http://hypem.com/tags/lo-fi parses a webpage and creates a playlist from it (imagining that after typing 'hypem.com` you click "go" in chat complete, which opens a browser, navigating to the desired page, and tap a "select" button to indicate this page, and returns to chat complete with url now pasted in).

Note: it's possible to make the message styles full screen, which let's a channel be a video browser, playlist, or other app-like experience.

To think about: how do we indicate/show/let the user choose which containers are live updating and which are snapshots of a particular time. For example:

  • /members #channel could create a list of the people in the channel, but is that list live or a snapshot from when the command was run? Same question for /album #channel and all the others.

Maybe to fiddle with a container's options, a user long-holds and selects [container type] settings from the action list. E.g., album settings and from there can select whether it is live/snapshot, inline/fullscreen, who can edit, etc.

More speculative

  • /blog @za/blog (maybe includes code which let's it be published beautifully to a specific URL)

You could also imagine there to be options:

  • /album #sunsetmusic options: slideshow (perhaps the options could be prompted via chat completes)
  • /slideshow #sunsetmusic might be an alias to /album #sunsetmusic options: autoadvance 3s (interesting to think about how options are passed in, via what interface—perhaps commands can declare options which can be surfaced in chat complete)

/todo

What is?

  • /todo Check this off creates a todo-styled message, which has a checkbox on the left which toggles the message's style.
  • That's it.

How use?

  • To use, just post and check off. Reorder them. Put them in a shared channel for a social todo list.
    • In my whisper with Wendellen, we could just /todo our grocery list
  • Make three channels @user/todo/backlog, @user/todo/ready, @user/todo/done. Open them in the web client for a nice Trello-like experience. Save it as a channel set. Send it as a link.
  • @user/todo can use universal permission :)
  • A more feature-rich todo could be: /todo Check this off @moop cc @bop Tuesday which assigns it to @moop, notifies @bop and makes the item due Tuesday.

other.js

  • simple custom message rendering, ability to handle taps on messages

command composability

EXPLORATION AND IDEA FUZZING

This pseudo spec is an exploration of @tonygentilcore's insight that /album #foo can create an album container whose contents are back by channel #foo. It's a vein that goes deep. This is meant to be interpreted as a sketch/brainstorm .

Background: #20, #17

In particular, this explores what happens when (1) you can create a container that embeds (part) of another channel, and (2) you can compose commands.

/channel

  • /channel #channel:messageA-messageB creates a container which embeds part of one channel in another.
  • /channel #channel:messageA creates a container which embeds the specified message
    • maybe /message messageA is sugar for /channel #thischannel:messageA

Syntax is super strawman and is [|....]. Maybe we can borrow from CSS selectors? Not sure what an interface for selecting a message, or message range would look like.

It seems that being able to reference messages and (parts) of channels is a fundamental building block of many of our actions.

Rechat, for example, can be though of as a styled /channel #fromchannel:message followed by an appropriate /caption.

composability

A natural extension of commands is to let them be composable. Why not plug the output of one into the input of another?

  • /fullscreen /playlist #juanxa/music/danke to make a fullscreen music player (see below)
  • /pdf( /article #aza/book/chapter1, /article #aza/book/chapter2 ) to create a pdf of the article form of the subchannels of #aza/book (see #31)
  • /h1 /channel #channel:0 to have render out the last message in a channel as a title (say for putting in a pocket). Prepending by /fullscreen creates a TV mode

With composability, it makes it fast to define new containers/behaviors... without leaving the iOS client!

For example (very pseudo):

  • /rechat := /indent( /channel #channel:message ) /caption rechat from #fromchannel
  • /quote := /p $text /indent( /channel #channel:messageA-messageB )
  • /todo $text := /h3( /checkbox $text ) creates a todo item with a checkbox styled biggish
  • /expense-report := /h1( Expenses ) /h2 =sum( /channel #other/expenses )

Now imagine this:

  • Given input elements like /slider{min:0, max:100, id:'price'}, /slider{min:0, max:10: id:'order-size'}
  • You can now make interactive spreadsheet-like behavior:
    • /h2 Total: =( /message[id:"price"] * /message[id:"order-size"] )

Uses calculator (#29)

You can imagine how this can be extended to creating buttons/polls/voting:

  • /h2 Do you like #bb? /container( /button{label:"Yes"} /button{labe:="Extra Yes"} )
// SUPER PSEUDO
var msg = new Message('/h2 Do you like #bb?')
msg.add('/button{label="Yes"} /button{label="Extra Yes"}')
msg.find('.button').on('click', function( evt ){ ... })
client.channel.post( msg )

/fullscreen

  • Causes a message to be displayed as fullscreen
  • Needs some interface to see the backing channel (say via long-hold action sheet)
  • Can be used to turn a channel into a more app-like experience: /fullscreen /album #adam/knives posted to the pocket of #adam/knives.
  • Can also be used to create channel redirects. Say I have #foo and want to instead have it point to #bar. I would then post /fullscreen /channel #bar
    • If there was already content in #foo, maybe I'd make #foo read only and then put /h2 Please use #bar, /channel #bar:0-5 to have it show the last five messages of #bar.
  • Want to have your webpage as a subchannel? Post this in that subchannel /fullscreen /webreader http://topr.ytmnd.com/

maybe /app? what if there are multiple messages in the same channel with /fullscreen?

Github issues as channels

I really like the way we're using GH issues to track distinct threads of conversation that we want to be more self-contained and retrievable than a slack or chatternet channel (for example, the way we're using time-cone and production-issues).

However, it's sad that Other Chat doesn't enable us to have this same feel. I think as we progress on #10, #17, #19, https://github.com/other-xyz/other-chat-web/issues/97 and https://github.com/other-xyz/other-chat-web/issues/61 we should think about how a channel might look that is backed by a github issue (supporting bi-directional modification).

It'd be truly great to be able to rechat things in and out of such an entity that feels like the canonical discussion of a topic.

Support chat complete actions

@kharmabum enumerated these current actions as the burndown list:

  • Invite
  • Dismiss
  • UnblockIdentity
  • BlockIdentity
  • ChannelDeletion
  • SubchannelCreation

RFC

Currently, features can return text for chat completions, e.g.

return {chatCompletions: [
  {
    text: 'tony'
  }
]}

We could extend this to also allow a mapping of action callbacks.

return {chatCompletions: [
  {
    identity: 123,  // |identity| replaces |text| in this case. Client decides how to render that identity (e.g. name, avatar, active status)
    actions: {
      default() {  // 'default' is special, it's the default when completions is tapped.
        // Update staged message with mention: `<@123>`
      },
      block() {  // this is es6 shorthand for `'block': function() {...}`. For everything other than 'default', the client displays a button with the given text ('block') which invokes the callback.
        feature.chatternet.identity({id: 123}).block()
      },
      join() {
        feature.chatternet.channel({id: 234}).addMember(123)
      },
    ]
  }
]}

This entails the embedder emitting a new ON_ACTION UserAgent event that's fired when the user selects one.

Then it requires filling out the Chatternet class a bit more. Methods like block() and addMember() would emit new events back to the embedder like ADD_CHANNEL_MEMBER, BLOCK_IDENTITY.

Thoughts?

Stack to Silence

  • have Other Chat turn off all notifications and go DnD when it is very close to another phone (like stacking phones on the table when talking)
  • use nearby's btle signal to detect if another phone is super close/touching
  • if they are, go DnD
  • this installs a behavior on the human that helps create an environment less prone to distracted conversation
  • bonus: piles of phones will automatically shush themselves

Stream your Other Chat session

\stream screen puts a container that displays a live feed of your Other Chat session. Especially useful for helping people debug, trouble shooting, teaching, or even sharing a peek of channels/messages someone else doesn't belong to. Long-hold for options to pause/end.

We could also do \stream camera to start streaming your camera (Web RTC so we don't have to go through our servers?) to a container. Boom, we have Meerkat/Periscope, but in an extended-local world.

Similarly \stream audio or \stream microphone.

/pdf & /svg

svg

  • /svg <svg> would open up lots neat typography and drawing goodness.
  • For example, the calculator command (#29) could output \svg ... as generated by https://www.mathjax.org/ to output beautifully formated equations

pdf

  • http://pdfkit.org/ is a beautifully simple API for creating PDFs in JS
  • /pdf #channel could turn a channel into a PDF for reading later.
  • Imagine writing chapters of a book, each one in it's own subchannel:
  • In #aza/book I would post:
    • /article #/chapter1
    • /article #/chapter2
  • In #aza/book/pdf I'd post a single message /fullscreen( /pdf #aza/book )

Random thoughts:

  • Could also do /articles #/chapter1 #/chapter2 #/chapter3?
  • Is there a syntax for doing all subchannels? /articles #:subchannels:?

Enforce type safety during development

Currently the other.js library indicates all of its types in docstyle comments, but they're not enforced anywhere. This makes it easy to misuse things and lets the docs get out of date. We should fix that.

I'm not sure the best way: perhaps there's an existing tool (other than Closure Compiled) which does static checking based on docstyle comments or perhaps we should consider moving types into TypeScript.

Create a mechanism for embedders to discover required other.js version

@kharmabum points out that reading feature.dependencies.otherjs is too late to work for the embedder b/c that implies it has already injected some version of other.js. We should have a standard way to do this.

One possibility is replacing dependencies with something like require('other3.x'). Need to investigate the most idiomatic way to do this.

/wall

Framing Problem: You are inviting someone to a private channel that has chat history. It's a risky move: there may be private things in that history, relating to them or just not meant for them. Inviting someone to an existing private channel feels like a core action, and the mental friction of the above worry will likely have a chilling effect. It's already happened to me that I've invited someone to a private channel and then had that "oh no" feeling.

Solution

\wall erects a barrier whose strawman default behavior is to block recent and new channel members from scrolling past it.

As the creator, click the wall to mess with it: allow only certain people to scroll past, or block just a particular person, allow officers, or only people with a key in their pocket, set it's image to a gif of the GoT Wall.

Nice features of walls are:
(1) they are instantly grokable, i.e. are behaviorally skeuomorphic
(2) can be added after the fact (even if you have already invited a person to a channel you didn't mean to, you can throw down a wall, and even put a link to a new channel for current members just above the wall to redirect to a new space)
(3) can be reused for sectioning the pocket into public/private/deep
(4) continues our theme of turn permissions and settings into social objects.
(5) are rational

@user/gifs channel app & universal permission

@user/gifs channel app

#gifs is installed by default on @user

  • A collection of every gif you post (annotated with the search term that got them)
  • Makes it easy to find gifs you previously posted, even if you can't remember in which channel you posted
  • Fun trick: /slideshow @za/gifs
  • Builds a solid base upon which we can do an extended-local gif search when you type "gif" (gifs used by your scene may rank higher/get there own section). In some ways, this is turning database indices into desirable user features :)

Universal Permission

Is @user/gifs by default public or private? Public is nice—I'd like to be able to browse @kharmabum's gif collection. But then having it be public could have chilling effect on JC's gif usage.

  • Public/Private: Only put gif's posted in public channels in @user/gif.
  • Thoughts: This frustrates the original goal of making it easy to find a gif, regardless of where you posted it. We could have a @user/gif be all gifs, and @user/gif/public be the collection of gifs posted in public channels.
  • Universal Permission: A new kind of permission where symlink content can only be seen by an identity that has permission to see the original content. (rechatt'ed content is a kind of symlink: it's a pointer)
  • Thoughts: This is a very general kind of permission that might solve a number of privacy issues for us. E.g., a private channel might set this restriction on all content rechat from it... let's the content out of the channel, but not out of the community. The challenge is going to be communicating this permission.

other.js

  • Hook the client's messageDidPost, look for gif media attachments, and if it exists, post a symlink to @user/gifs (annotated with the user's typed text)

Autocorrect behavior

Some existing features on iOS (e.g. @identity_mention, #channel_mention, invite @identity_mention, etc) disable autocorrect as soon as the associated token is matched via the Intent system. The mechanism here (#55) should probably also return any requirements that the feature has when presenting results (e.g. disabling autocorrect, presentation style such as grid/vertical-list/horizontal-scroll, etc).

RFC: willShowMessage() / didShowMessage()

A willShowMessage()/didShowMessage() pair of hooks could allow us to elegantly implement a wide set of features without resorting to letting features actually render messages yet.

willShowMessage

Called by the user agent with the message that is about to be shown. The feature may modify or block the message before the user agent shows it.

Some examples:

  • In https://github.com/other-xyz/other-chat-web/issues/101 , we were trying to figure out how to format message timestamps consistently across clients. The builtin formatting feature could use the momentjs library to set a field on the message containing the text to be displayed. An identity or channel might instead use a feature with absolute timestamps. Or even a creative one that uses clock emoji for the timestamps (http://www.iemoji.com/emoji-cheat-sheet/time).
  • Mention entity resolution can be moved up to this layer (ie. a builtin feature is responsible for replacing <#123> with #foo in the message text).
  • When this runs server side, we could rationally implement identity blocking atop this.
  • A channel could install a feature that bleeps profanity.
  • Emoji support could be totally moved to the feature platform, because a feature could replace :tophat: with the emoji character.
  • Formatting could be implemented more cleanly, because rather than applying the format and trimming the command from the message eagerly at chat complete time (like we do today), it could be lazily applied at display time.
  • Since attachments are part of the message, a feature could be implemented that sets the "autoplay" attribute of media to false for "serenity mode" on a channel or identity.
  • A feature could arbitrarily filter media (e.g. deep dream).
    ...

didShowMessage

Not nearly as exciting, but here for symmetry. I could see this being used for analytics and as a more performant hook for features to establish context of visible messages which'd be useful for generating chat completes.

@aza @kharmabum WDYT?

Track test coverage

It's very popular for open source libraries to display a badge about their test coverage. I'd like to do the same and set a precedent of requiring test coverage for other.js. Coveralls is by far the most popular. We could set it up for other.js for $5/mo (and it becomes free when we open source).

@adamrothman since I don't have a credit card or root@ yet, would you mind signing us up for the "trial" plan here: https://coveralls.io/pricing

@user/dropbox channel app

@user/dropbox channel app

  • Oauth against Dropbox and you've got yourself a @user/dropbox channel
  • The file hierarchy is mapped to channel hierarchy, just navigate and browse as per normal: your dropbox files are now rendered in beautiful Other Chat styles

Use Cases

The integration is simple, but very powerful.

  • We haven't shared our wedding photos yet because Facebook isn't our jam, and they are socially dead on Dropbox. With this, I'd:
    • Navigate to @za/dropbox/path/to/wedding/photos
    • Nickname it to @za/wedding, keep it private, read-only, reactions-enabled
    • Invite everyone who attended wedding into the channel via their email, thereby on-boarding them (thanks to our soon-to-be slippery entry)

In one swell swoop, we give Other Chat desktop sync/files capabilites, and enviralized Dropbox content within the Chatternet.

  • Designer Fund retreat use case
    • A group of ~25 of us part of the Designer Fund Guild went on a retreat. There is no one place for us to talk, except on an email thread, so to share photos, DFG sent an email to a Dropbox folder. Photos were shared only one way (i.e., I couldn't contribute back my photos.
    • With Other Chat...
    • They'd make a channel #DFG
    • They'd install @designerfund/dropbox and then nickname @designerfund/dropbox/path/to/photos #DFG/Retreat2016Photos
    • Then invite everyone in :)

Develop features w/o a client checkout

Currently you need a client checkout in order to develop a feature. That's cumbersome.

@aza had some ideas:

  • Drag/drop a feature to a channel to have it run it once. This requires re-dragging to pick up changes.
  • In Chrome, we can use the File System API to drag & drop and make auto-reload work.
  • In other places, we can suggest python -m foo.other.js and some mechanism to point other.js at the local server
  • We can also research a codepen-like online editor to just view-source + save.

Enhance networking capabilities

  • A fetch polyfill to send requests from the embedder w/o CORS.
  • An opportunity to fetch dependencies prior to sending/receiving other events.
  • A permission to continue fetching after receiving any events.
  • A permission to fetch directly w/ CORS.

Bridge for slack bots

We could pretty easily write a Slack bot that posts all messages in a slack channel to an other channel. The idea is that we could do this for channels that have bots like #alerts and then we get access to a large number of existing slack bots for free (e.g. travis, sentry, jenkins, etc).

But I'm on the fence about whether this is actually a good idea. It'd help us move away from slack faster, for sure. But on the other hand, it'd limit our thinking about what kind of integrations w/ travis, sentry, etc we could implement atop other chat that aren't implementable as a slack bot.

Points: ++

Put the Points app in your pocket so that you can give to and take points from anyone.
Use like this: @name +1, or @name -10

A system message posts saying: "@BLAH gave @Bloop 5 points \n 30 points total", as the feature (so clicking on it message lets you see what feature is responsible, so you can install too)

Points are global for this feature per user. So if @mtkurlowski gives me 3 points and @ruudderooij gives me -2 points, then I end up with just 1 point.


Future options:

It would be nice to be able to /points leaderboard to put an (extended-local) leaderboard object into a channel (a text list of the highest and lowest pointed people in my extended local). I might put this into my pocket. Or I might put /points me into my pocket to showcase my points as part of my identity. Or /points #channel for a leaderboard of the people in this channel.

@user/camera channel app & dropbox business model

@user/camera is a channel app

#camera is by default installed on @user

  • everything captured by the camera (photo/video/gif) goes in here
  • option to sync your Cameraroll to #camera/phone (hey there Dropbox and your pay-for-storage business model)
  • you can add new features to the camera by putting them in the camera's pocket. (Implicitly giving the feature access to other.js camera stuff).
  • #camera is by default private

Some thoughts:

  • Makes it easy to find any photo you've taken/posted in anywhere in Other Chat.
  • Business model: If everything you create gets stored someplace in your identity, then above a certain identity storage size, we charge? It's saying we are essentially acting as your in-and-off-the-cloud file system.
  • Interesting to think about: who, conceptually, owns what content in Other Chat? If it's the identity that posts (barring copyright stuffs), and rechat's etc are all essentially pointers back to that content, then it's that identity which could pay for it's storage.

/album

  • /album with no images staged creates an empty album

untitled_2

  • /album with images staged creates an album with those images
  • Long hold to bring up chat complete actions, select "settings": brings you to a screen that lets you mess with the albums settings (e.g., maybe by default anyone can add to the album, but you can make it read-only, or maybe change the background color, or how the album is laid out)
  • Drag images/gifs in?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.