Git Product home page Git Product logo

mast's People

Contributors

ghernandez345 avatar mikermcneil avatar mscdex avatar particlebanana avatar sgress454 avatar tkh44 avatar zolmeister avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mast's Issues

TODO application

Let's see how far you can get by Friday-- I'd like to see a working TODO app we can go over w/ together. Then this weekend, let's add some server-side functionality (and I can show you the single-biggest weakness in Sails right now, lack of wildcard websocket support.)

After implementing the server integration, I'd like to host the todo app and make a new git repo for the source code so we can provide it as a working example.

API: get list of current active visitors

also need to expose this information on the serverside.

The grouping here is important-- this is asking for the list of curent active visitors for this route. Which could mean a separate page or not, who cares, it's the logical unit we're interested in, since we're probably using the client-side router.

Mast.UI and Mast.registerUI()

UI extends component, but uses autorender=false and automatically instantiates the component during Mast.raise(). It adds the .activate() method, which empties the outlet and rerenders the template for the now active UI component.

Improve Socket event definition api

Right now, you have to pretty much hack the Mast source code to add new socket events from the server. There needs to be a file much like controller.js (AppRouter) for mapping socket events to functionality.

-OR- the socket events should propagate to the AppRouter (which would be fine as long as we remain explicit about which component is being rendered into from the AppRouter)

Rendering vs. Bindings

Problem

The DirectoryComponent should render its branches in a fancier way to match everything else. This involves taking a fresh look, at the framework-level, at bindings vs. custom render functions, and whether we even need both.

Custom render functions

Custom render functions can work for everything, but they must be triggerable from Component.set() -AND- Mast.Model.set(). This is because comet calls can only update a model. However this ties view functionality in at the model layer, which is a negative.

-Custom render functions work best for cases where templates+css just don't do the trick (i.e. animations unsupported by unsupported CSS3, applying styles using an algorithm, animations w/ complex timing, etc.)-

someComponent.set('someProperty','someNewValue',{
   render: function($existingElement, $newElement) {
       // do stuff here like fade out the old element and fade in the new
   });

someComponentsModel.set('someProperty','someNewValue',{
   render: function($existingElement, $newElement) {
       // do stuff here like fade out the old element and fade in the new
   });

Bindings

Bindings are confusing, and leave open questions about how they should behave when some of the attributes are changed, and not others. Not to mention for Trees and Tables.

-Bindings work best for cases when you dont' want to force a rerender of an entire component just to change one of its model's attributes. The most efficient components have bindings for every attribute that changes in their models. This side of things could be eventually converted into a Spine-style templating scheme.-

-Finally, note that bindings were created because originally, Mast rerendered all children of a component whenever one of the parent's attributes changed. This is wildly annoying, and no longer occurs.-

bindings: {

        numActive: function (newVal) {
            this.$el.closest_descendant('.num-users').text(newVal);
        },

        numComments: function (newVal) {
            this.$el.closest_descendant('.num-comments').text(newVal);
        },

        // This gets called whenever the depth of this component's model changes
        depth: function(newDepth) {
            this.setPadding(newDepth);
        },

        state: function (newVal) {
            var arrow = this.$el.closest_descendant('div.expand-close-arrow');

            // Handle basic rendering use case
            this.$el.removeClass('loading expanded');

            // Do animation for arrow rotation
            if (newVal != "") {
                this.$el.addClass(newVal);
                if (newVal=="expanded" || newVal=="loading") {
                    arrow.addClass("expanded");
                }
            }
            else {
                arrow.removeClass('expanded');
            }
        }
    }

Conclusions

  • In general, if a Component's collection is changed, it should only rerender its branches/rows.
  • That is, if a Component's model attribute(s) are changed, it should preserve the branch/row outlet in memory, rerender itself, and then swap out the empty branch/row outlet with the one from before.
  • Bindings are useful in gaining efficiency and/or smoothness out of the render process. If the above tactic is employed, they are not strictly required to handle serverside events from comet.
  • Custom render functions are good for complicated state-changes that involve more than a simple $el.find/replace animation, or when multiple attributes change at once. Custom render functions actually do the templating for you and present an API with the $old and $new element, and let you switch them out.
  • Some hooks into the core state change events should probably be added, probably in bindings, but maybe not (maybe they should be like afterRender...):
    • hide (override default behavior when Component.hide() is called)
    • show (override default behavior when Component.show() is called)
    • change (override default behavior when an attribute is set)
    • add (override default behavior when a row/branch is added)
    • remove (override default behavior when row/branch is removed)
    • reset (override default behavior when rows/branches are wiped and replaced)
  • The reset event should be smart-- it doesn't need to wipe all of the branches each time. It should be able to look at the current collection vs. the new collection and remove/add only the branches necessary.
  • There should be bindings to control what the animation for removing and adding branches looks like. These animation bindings should be called by the reset binding if it exists.

Current state of Mast

So far, from the above list, the following sensible default behaviors don't exist in Mast:

`````` Component.hide()```

Simply display:none the Component's $el

Component.show()

Dumbly show the Component's $el

And here's what we do have:

Component.change()

If there are any bindings for the attributes that were changed, execute them. If any or all of the attributes changed WERE NOT in bindings, remove the Component's $el from the DOM, recompile the templates, and reinject it into its outlet.

Component.reset()

Wipe from DOM, retemplate, and then rerender the Components rows/branches.

Component.add()

Add a row/branch at the model's position in the collection

Component.remove()

Remove a row/branch by model.

clean up branching-- make Mast-only version

Right now, the repo contains Sails+Mast, which is fine, and what we'll typically be using, but I want to support the case where someone wants JUST Mast out of the box (to use w/ PHP, rails, whatevs) The goal being that I can incorporate Mast in the new Demo Center product for Unwired, assuming that flies w/ our "legal dept.". I can't wait to see the productivity gains there.

route middleware

There is logic that should be performed before every route, on on the very first route.

These should probably have a filesystem convention, whether that's to put them in a file in the /mast/routes directory or in the top level /mast dir.

Tentative spec:

Mast.beforeEachRoute(fullRoute,arguments*) {

}
Mast.beforeFirstRoute(fullRoute,arguments*) {

}

Where arguments* are standard Backbone route arguments, e.g.: #/:arg1/:arg2
and fullRoute is the complete route string.

client side routes (controllers)

change the compilation script to piece together any files in public/routes into the AppController instead of just absorbing public/js/controller.js.

So:

public/routes/index.js
public/routes/tableExample.js
public/routes/whateverElse.js

->

production/ _controller.js

Ideally, development mode keeps these as separate files to make it easy to see in a browser's dev console.

Complete API for Mast.Table

Needs public methods to add, insert and remove rows.

Needs to listen for changes to individual rows' Mast.Patterns (already done I think...)

Needs to listen for changes to the Mast.Collection itself (awareness of when models are added or removed)

Simple binding shortcut notation

Allow bindings to be specified like subcomponents:

an object definition of the form: attributeName : relativeOutletSelector
where relativeOutletSelector refers to the DOM selector for an element inside of this.$el. (similar to this.$()

For example:

bindings: {
  someAttribute : '.some-attribute-outlet'
}

The new value of the bound attributes replaces the contents of the appropriate relative outlet.

Modify require.js to manage dependencies

In every case, .ejs templates for the various components should be either:

  1. stripped of white-space and concatenated, then made available as a view partial which will be absorbed during component instantiation by the runtime Mast library
  2. or stripped of white-space and concatenated, then made available immediately as TemplateLibrary in the client javascript code

As for the JS and CSS:

we'll still need some magic to manage .css and .ejs template files, but dependencies and js loading should be done by require.js because it's a much more mature framework than anything I can write in a few hours.

In development mode, Mast.Require.js on the client-side asynchronously loads the javascript components and routes, managing dependencies all the while. CSS s are loaded asynchronously by default in browsers, and so we include them in order, from a view partial.

In production mode, require.js on the node.js side synchronously compiles the javascript components and routes into one file, app.js, on initial launch. It leverages this dependency information to compile CSS into one file as well, available from the same (smart) view partial.

NOTE: production mode should be used with care when developing client code, since any changes will result in a restart and recompilation.

Mast.Tree

Create a data structure to represent an n-branched tree (dependency list)

More awesome dependency inclusion in production mode

Compile and include jQuery, jQuery UI, Backbone, and Underscore, as well as moving the generated socket.io client into the lib/client directory and minifying and compiling into _app.js in production mode.

Better yet, wrap it in a function that checks if it's already on the page before initializing. But meh that's a lot of work and easy to break still. Better to make the user manage their dependencies themselves so they're aware of what's happening.

Determine some structural choices based on Gabe's feedback

What do you think of the models directory? Are you OK with models and collections sharing one common folder?

What about templates? Is it ok that ejs and css files share the same parent folder?

If you were going to include Mast in a simple PHP site (let's say you wanted to make a single-page application for mobile web, or something), what would the ideal structure look like? Obviously you're going to lose the advantages of the Sails integration, like auto compilation/minification, and it loading all of the necessary pieces on demand (you'll need to manually include each script file, each template CSS file, and each HTML template inside the markup)

More conventional and efficient template compilation

First and foremost, decide on whether there should be a filename convention -> template label mapping for .css and .ejs files in the "templates" directory.

Next, figure out whether js Mast.Component definitions should be included here as separate files or kept separate (probably should be here).

Instead of rendering each template files as a view partial on the serverside each time a view is rendered, string all of the templates together

Also consider automatically creating a separate compilation for the css (and js?!?) files and minifying it (them?!).

subscribe to socket messages using Backbone events

Server might send any manner of message back (controllers can broadcast whatever they like). However, by convention, we use URL notation:

account/create
account/2/update
account/3/delete
..etc. 

So a subscription hash (in a UserTable Component) might look like:

(trailing and leading slashes are automatically stripped)

{
  'account/:id/update': 'handleUpdatedAccountEvent'
}

In the example above, the id property of the Component's model will be checked against the id passed in the message's label (:id).

To override this behavior (if you're using a non-standard REST API between your client or server, for instance) you can either check against a different model property:

{
  'account/:id/update': {
    id: function () { return this.get('account').id; },
    action: 'handleUpdatedAccountEvent'
  }
}

or just broadcast to all instances of this component:

{
  'account/create': 'handleNewAccountCreatedEvent'
}

Better development-mode asset compilation

In dev mode, a non-compressed copy of Mast should be made available, with all of the dependencies, but no regular CSS or JS(controller) files should be included. CSS and JS of components should still be marshalled into one big file each.

-AND/OR-

evaluate the value of adding view variables (i.e. <%- cssfiles %> ) for this purpose.

Garbage collector

This probably will never be an issue-- but because models are now saved in Mast.modelCache by cid, they aren't getting gc'ed() by the javascript interpreter. On desktop, this only really starts slowing things down (and then we're talking 10s of ms, never over 100) when there are more than 10,000 models. Mobile is my concern.

The best solution is probably to associate components with routes by tying components to the route they're created in at the application layer. Then, at the framework layer, free the components that were used in a route when switching routes (which removes their models from the modelCache)

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.