{"id":18656781,"url":"https://github.com/optimalbits/ground","last_synced_at":"2025-04-11T18:31:20.554Z","repository":{"id":2144565,"uuid":"3088990","full_name":"OptimalBits/ground","owner":"OptimalBits","description":"Ground - MV(C/VM) Javascript  Framework","archived":false,"fork":false,"pushed_at":"2018-03-12T11:39:17.000Z","size":3141,"stargazers_count":100,"open_issues_count":10,"forks_count":3,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-09T09:41:48.635Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OptimalBits.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-01-02T17:51:01.000Z","updated_at":"2022-08-24T20:42:15.000Z","dependencies_parsed_at":"2022-09-09T18:01:27.158Z","dependency_job_id":null,"html_url":"https://github.com/OptimalBits/ground","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OptimalBits%2Fground","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OptimalBits%2Fground/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OptimalBits%2Fground/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OptimalBits%2Fground/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OptimalBits","download_url":"https://codeload.github.com/OptimalBits/ground/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248458451,"owners_count":21107080,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T07:25:18.000Z","updated_at":"2025-04-11T18:31:19.766Z","avatar_url":"https://github.com/OptimalBits.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"#Introduction\n\nGround is a compact, modern web development framework that provides you a firm foundation to create rich, modular, scalable, realtime interactive web applications that are required to work seamlessly both online and offline.\n\nGround is light (22Kb + 5Kb of dependencies), and well suited for both desktop and mobile applications.\n\nIn ground, most of the application logic is moved from the server to the client, whereas the server acts mostly as an scalable, efficient distributed storage and synchronization controller.\n\nIt includes also some rather useful features such as a hierarchical routing system, an undo/redo manager, property and declarative bindings, reference counting and automatic synchronization between clients and servers. It is design to always deliver high performance and low memory consumption.\n\nGround is written in [TypeScript](http://www.typescriptlang.org/), for modularity and stability and is suitable for both javascript and TypeScript projects.\n\n\n##Highlights\n\n- Designed and optimized for Node.js servers.\n- Hierarchical routing system simplifies routing by matching the DOM hierarchical nature.\n- Define models and use them both client and server side.\n- Models, Collections and Sequences with property **bindings**, **persistence** and client-server **synchronization**.\n- **Offline** support.\n- *Declarative Bindings* for easily connecting views and models.\n- Sessions and rights managements support.\n\n\n##Philosophy\n\nThe philosophy of Ground is to focus on *performance* and *simplicity*. We wrote the complex code so that you don't. \n\nIt should be a complete Web framework that is fun to use, that uses efficiently the newest web browser technologies, and that relies on Node.js server technology to provide scalability and synchronization. It provides some innovations such as hierarchical routes and bi-directional client / server communication.\n\n\n##Dependencies\n\nGround depends on the following external libraries: Curl, Socket.io and Underscore or LoDash.\n\nGround is provided both as a set of TypeScript classes, and as a javascript AMD \nmodule. It can be included using script tags or using an\n [AMD loader](https://github.com/amdjs/amdjs-api/wiki/AMD). While it should work\n  with any AMD compatible loader, we recommend [Curl](https://github.com/cujojs/curl)\nsince it is already a required dependency.\n\nFor the server component both [Redis](http://redis.io) and \n[MongoDB](http://mongodb.org) are required at the moment.\n\n\n##Install\n\nInstall Ground by using npm:\n\n    npm install gnd -g\n    \n\n##Command line\n\nGround provides a command line tool that can be used to generate the skeleton of a ground application. This is a very convenient way to start playing with the framework with a minimum effort. For example:\n\n    gnd myapplication\n    \nWill generate a ground application in the directory myapplication. Enter in the directory and execute:\n\n    npm install\n    \nThis will install all the required dependencies, then just fire the server with the application:\n\n    npm start\n\nThe hello world application will be started automatically in your default browser.\n\n[Grunt](http://gruntjs.com) is used for building the application for deployment.\nIf you don't have grunt already installed:\n    \n    npm install -g grunt-cli\n\nThen just:\n\n    grunt\n\nThe resulting app will be placed in the *build* directory.\n\nFor testing we use [Mocha](http://visionmedia.github.io/). If you don't have \nmocha installed:\n\n    npm install -g mocha\n\nYou can run tests in developing mode\n\n    npm test\n    \nOr run the tests on the production built code:\n\n    npm test --production\n    \n\n#Demos\n\n  Take a look at some demos created with Ground that demonstrate some of its highlights:\n\n  * [Hierarchical Routing](http://gnd.io/demos/route)\n  * [Dynamic lists](http://gnd.io/demos/list)\n  * [Dynamic tables](http://gnd.io/demos/table)\n  * [Realtime multi user chat](http://gnd.io/demos/chat)\n\n\n#Routing\n\nIn modern web applications, it is desired to avoid page refreshes in order to provide a better user experience \nas well as to help keeping the application state and reduce latency. While it is possible to keep an internal state between the \napplication different components, it is often convenient to offer urls that links to different \"global\" states \nof the application. This is achieved using a client side url routing system.\n\nGround takes a less traditional approach to url routing. Instead of defining a list of independent routes, \nthe routes are assumed to be **hierarchical**, matching  the hierarchical nature of a web page and the \nunderlying DOM structure. The framework is smart enough to avoid re-rendering unnecessary DOM nodes, as well as \ndeleting the ones that are not part of the current route.\n\nWith this approach it is possible to reduce redundancy dramatically and also create transition effects between views very easily.\n\n##Basics\n\nThe routing module is started by specifying an optional root (defaults to '/') and a function callback where\nall the routes will be defined. Lets see the simplest possible example:\n\n\tGnd.router.listen(function(req: Request){\n\t  req.get(function(){\n\t    req.render('/templates/main.jade');\t\n\t  });\n\t});\n\nIn this case we will render the [jade](https://github.com/visionmedia/jade/) template *main.jade* into the *body* tag.\n\nNote that we used jade as an example template engine, any template engine can be used by ground, although it defaults\nto [underscore](http://underscorejs.org/#template) microtemplates.\n\nThe template engine to use is defined by the *use* method of Gnd global object, for example to use jade as template engine:\n\n    Gnd.use.template(templ: string){\n      return jade.compile(templ);\n    });\n\nSince the system is hierarchical, if we want to add some more sub routes we can do it like so:\n\n\tGnd.router.listen(function(req){\n\t  req.get(function(){\n\t    req.render('/templates/main.jade');\n\n\t\treq.get('products', '#content', function(){\n\t\t  req.render('/templates/products.jade');\n\n\t\t  req.get('foo', '#content', function(){\n\t\t\t  req.render('/templates/foo.jade');\n\t\t  });\n\n\t\t  req.get('bar', '#content', function(){\n\t\t\t  req.render('/templates/bar.jade');\n\t\t  });\n\t\t});\n\n\t\treq.get('about', '#content', function(){\n\t\t  req.render('/templates/about.jade');\n\t\t});\n\t  });\n\t});\n\nThis simple example will handle the following routes:\n\n\t/\n\t/products\n\t/products/foo\n\t/products/bar\n\t/about\n\nNote that the second parameter in the *get* function is a node selector. This parameter is optional\n(defaulting to 'body'), and it is used by the render function to place the content, as well as used by the framework internally to provide some smart features.\n\nAlso note that the framework is taking care of the asynchronicity between calls, for example, the render function will fetch a template from the server, but the user does not need to wait for it before calling the next *get* functions.\n\n\n##Entering the routes\n\nThe *get* method in the Request class defines a subroute in the route hierarchy. The callback parameter is used to determine what is going to happen when that subroute is matched by the url, for example we can call *get* again to define a new subroute or we can call several other methods that make useful things. These methods can be called in any order, but Ground will always call them in a specified order, and depending if we are entering or exiting the route different methods are called:\n\nWhen entering the route:\n\n    Request##before(done?: ()=\u003evoid)\n    Request##load(url: string, done?: ()=\u003evoid)\n    Request##render(urlTemplate: string, urlCss?: string, done?: ()=\u003evoid)\n    \n    Request##enter(el: HTMLElement, done?: ()=\u003evoid)\n    Request##after(done?: ()=\u003evoid)\n\nWhen exiting the route:\n    \n    Request##exit(el: HTMLElement, done?: ()=\u003evoid)\n    \n\n###Asynchronous and synchronous operations\n\nSometimes it is needed to do something after the function has finished, so render accepts a callback function for this means:\n\n\treq.render('/templates/products.jade', function(done){\n\t  // Do something asynchronous...\n\t  done();\n\t});\n\nThe callback takes an optional parameter done. This is a function used to tell the system that your function has finished doing what it was doing.\nYou need this parameter only when your function performs asynchronous operations. If your callback is just doing simple synchronous stuff, just\nskip the parameter and the system will understand that it is a synchronous callback:\n\n\treq.render('/templates/products.jade', function(){\n\t  // Do something synchronous\n\t});\n\nTemplates usually need data that may be fetched from the server as well. For that purpose, the function *load* can be used. Let's see an example:\n\n\tgnd.route.listen(function(req){\n\t  req.get(function(){\n\t    req.render('/templates/main.jade');\t\n\n\t\treq.get('news', '#content', function(){\n\t\t  req\n\t        .load('/data/news.json');\n\t        .render('/templates/news.jade');\n\t\t});\n\t  });\n\t});\n\n*load* will fetch the data from the server and place it in req.data, which will be used by *render* placing it in the *context* variable of the template system.\n\n###Transitions\n\nThe framework also provides a mechanism to make transitions between routes possible. They are enabled by using the pair of functions *Request##enter* and *Request##exit*.\n\n*enter* will be called when the top DOM node for the route has been rendered, but it is still hidden. If you do not call *enter*, Ground will just show the DOM node directly without animation, otherwise, you can specify an animation using any framework of your choosing.\n\nLets see a simple example conveing animations using jquery:\n\n\tGnd.router.listen(function(req){\n\t  req.get(function(){\n\t    req\n\t\t    .render('/templates/main.jade')\n\t      .enter(function(el, done){\n          $(el).fadeIn(done)\n        })\n\t      .exit(function(el, done){\n          $(el).fadeOut(done)\n        });\n\t  });\n\t});\n\nThe call to *exit* will perform a *fade out* operation on the content of the *body*, while the call to *exit* will *fade in* the rendered template. By using exit and enter its possible to combine many different animations for different parts of the web page or application. The order in which *enter* and *exit* are called is irrelevant, there can only be one call for every node in the route hierarchy and the system will call them when necessary. Also note that in the example we are using an asynchronous call, which means that the rendering of the route will wait until the animation has completed, in some cases we may not want to wait, and run all the animations in parallel for a different visual effect:\n\n    Gnd.router.listen(function(req){\n      req.get(function(){\n        req\n          .render('/templates/main.jade')\n          .enter(function(el){\n            $(el).fadeIn()\n          })\n          .exit(function(el){\n            $(el).fadeOut()\n          });\n        });\n      });\n\n###Before and After\n\nWe have also a pair of function to be used when custom code must be executed, they are called ***before*** and ***after***. The first function is called before rendering the node content, and the second function is called after the rendering. These functions will prove very useful, for example, *before* can be used to protect a route and make it only available to logged in users, while *after* can be used for doing operations on the DOM after the rendering. Usually is in the *after* function where all the logic for that specific route is placed.\n\nIn order to avoid large files with many route handlers that would keep the code large and clunky, we can use external route handlers. Simply provide a path to a handler in the get method instead of the function callback. Lets see a more complete example:\n\n    Gnd.router.listen(function(req){\n      req.use('template', template);\n\n      req.get(function(){\n        gnd.ajax.get('api/sessions', function(err, res){\n          req.user = res;\n          if(req.isLast()){\n            req.before(function(done){\n              if(req.user){\n         \t    req.redirect('/main');\n              }else{\n                req.redirect('/login')\n              }\n              done();\n            });\n          } \n        })\n\n      req.enter('show');\n      req.render('views/layout.jade', 'css/main.less');\n    \n      req.get('login', '#container', 'main/login');\n      req.get('admin','#container', 'main/admin');\n      req.get('register','#container', 'main/registration');\n        \n      req.notFound = function(){\n        req.render('views/notfound.jade');  \n      }\n    });\n    \n\n###Auto release pools\n\nGround uses a reference counting based mechanism to avoid memory and event leaks. This mechanism requires the user to manually call *release*. Usually, when entering a new route, several objects are created and it can be difficult to keep track when to release them. For this reason the route system provides autorelease pools where you can put all  the created objects and the pools will be released automatically when leaving the route.\n\nExample:\n\n    // TO BE ADDED\n\n\n#Classes\n\n\n##Base\n\n\n###Property bindings\n\n\n###Reference Counting\n\nIn Ground we provide a reference counting mechanism. Reference counting is a simple yet quite effective method \nto avoid memory and event leaks. \n\nThe Base class in Ground provides two methods: retain and release. The former is used to increase the reference \ncounter, its called retain because it expresses that the object that called it \"retains\" a reference to it. \nIt is equivalent to sharing the ownership of the retained object. It also means that the object that called\n*retain* is now responsible of calling *release* when it is not needed anymore.\n \nEvery time *release* is called, the reference counter is decremented, and when it reaches zero, the object is\ndestroyed by calling the method *destroy*, which is also part of the Base class, although it is quite often\noverrided to perform customized clean ups for your classes.\n\nIt may seem strange that we need a reference counting mechanism when javascript includes a garbage\ncollector. Garbage collection is a powerful facility that helps in releasing un-used objects, but \nthe garbage collector is only able to free objects that are not referenced by any other object. In complex \napplications, it is necessary some structured mechanism in order to un-reference the objects so that the \ngarbage collector can do its job. Also, besides memory, we want to avoid *event leaks*, which occour when\nsome event are still listening even if we do not care of them anymore. In Ground when an object is destroyed\n, by default, all the events associated to it are also removed.#\n\nJavascript does not provided Classes, although it provides a similar mechanism called prototypal inheritance, where objects just can inherit from other objects.\n\nGround provides a mechanism to simplify standard prototypal inheritance and it also provides a hierarchy of objects that will prove quite useful for developing advanced web applications.\n\nObjects inheriting from other objects are just declared using gnd.Declare:\n\n    var myObject = gnd.Declare(Super, [constructor, statics])\n  \nThe only mandatory parameter is Super, which is the super object that your object derives from.\nAt the top of the object hierarchy in ground lies the object gnd.Base, which provides some \nbasic functionality that the rest of the system expects from all the classes. So at a \nminimum you should derive from gnd.Base, although usually you will be deriving from more\nspecialized objects such as gnd.Model or gnd.View.\n\nThe other parameters are optional, but usually quite relevant. The *constructor* allows\nyou to define a customized constructor for your object. This constructor can have any\nnumber of input parameters, although if you are creating model objects it is \nrecommended that the first parameter is *args*, which would represent all the serialized \nproperties of your model. This will make more sense when we explain about the models later on.\n\nThe *statics* parameter is an object with all the static functions for this object, i.e. the \nfunctions that you can call without needing to instantiate the object.\n\nLets give some examples:\n\n    // Create a simple object without constructor.\n    var Animal = gnd.Derive(gnd.Base);\n  \n    // It is possible to add static functions and properties also after declaration\n    Animal.find = function(name){ ... }\n  \n    // Create a class with a custom constructor.\n    var House = gnd.Declare(gnd.Base, function(floors, colour){\n      // Don't forget to  call super class constructor!\n      this.super(House);\n      this.floors = floors;\n      this.colour = colour;\n    });\n\n    // Instantiate\n    var myHouse = new House(3, 'white');\n\nIf your objects are always inheriting from some object from the gnd.Base hierarchy, you \ncan use the simplified method *extend*:\n\n    // Create a simple object\n    var Animal = gnd.Base.extend();\n\nObjects derived from gnd.Base are not so much different from a normal javascript object, \nbut we get some useful features such as:\n\n  - Events\n  - Bindings\n  - Reference counting\n  \nLets give some examples for every feature:\n\n    // Instantiate a fox\n    var fox = new Animal();\n  \n    // Listen to changes to the property 'name'\n    fox.on('name', function(name){\n      console.log(name);\n    });\n  \n    // Set the name attribute\n    fox.set('name', 'mulder');\n\n    // stop listening to name property.\n    fox.off('name');\n\nIf we want we can bind two properties from two different objects, and they will be keep \nsynchronized at all times:\n\n    var cat = new Animal();\n  \n    // bind legs property from fox to cat\n    cat.bind('legs', fox);\n  \nWhen binding, if the properties are different at the moment of bind, the target object \n(cat in this case), will get the value of the 'legs' property from the fox.\n\nIt is also possible to bind properties with different names:\n\n    cat.bind('colour', fox, 'tail');\n    \n    cat.set('colour', 'brown');\n    \n    // Will output 'brown'\n    console.log(fox.colour);\n\n    // Just unbind when finished\n    cat.unbind('colour');\n  \n\nFinally, the Base class provides reference counting. When a class is instantiated, it \nwill get a reference count of 1. We can call retain to increase the count and release\nto decrease it. If the count reaches to zero, the class will call to its *destroy* \nfunction, which in the base class takes care of removing all the events associated to it. \nReference count proves to be an important mechanism in order to avoid memory leaks \nand dangling event listeners, which could otherwise lead to strange side effects and\nsuboptimal memory usage. So in order to keep the system clean, always call *release*\non the objects that are not going to be used any more.\n\n\n##Models\n\nModels in Ground are used to represent persistend data in a structured way. They provide mechanisms to keep data automatically synchronized between clients and servers as well as data validation.\n\nThe properties in a Model are defined using a Schema, which is heavily inspired by [MongooseJs](http://http://mongoosejs.com/) (a MongoDB ORM).\n\n\n###Defining the Schema\n\nThe first thing to do in order to use a Model is to define its Schema:\n\n    var AnimalSchema = new Gnd.Schema({\n      name: String,\n      legs: Number,\n      tail: Boolean,\n    });\n\n*AnimalSchema* is a simple schema that will be used to define an *Animal* model. Ths syntax for the schema is fully compatible with [Mongoose schemas](http://mongoosejs.com/docs/guide.html) with a few differences, for example when defining *Sequences* and *Collection* properties (see the Sequences and Collections section for details).\n\nAll models receive a base schema with the following properties that should never be overwriten by the user:\n\n    {_cid: String, \n     _id: Schema.ObjectId,\n     _persisted: Boolean}\n     \n\n###Creating a model\n\nA model is created by extending the Model base class:\n\n    var Animal = Gnd.Model.extend('animals', AnimalSchema);\n\nThe first parameter, 'animals', is used to define the bucket where this model is going to be stored in the storage. Buckets are top level containers for all our models and used to build *keypaths* (see the keypaths section).\n\n\n###Model instances\n\nA Model acts as a super class for creating model instances. All model instances have a client id (##cid) and optionally a server or persisted id (##_id). When a model instance has a persisted id, it means that the instance is safelly persisted in some server storage, and that it can be retrieved by any client that has the correct rights to do so.\n\nA model is instantiated using the *create* method:\n\n    // Model##create(args?: {}, keepSynced?: bool): Promise\u003cModel\u003e\n    var tiger = Animal.create({name: 'tiger'}, true);\n\nModel instances are singletons, meaning that you cannot have 2 instances in memory with the same cid or persistent id. If for example a *cid* or *_id* is given as arguments to the create method, it may return an already instantiated model:\n\n    var tiger2 = Animal.create({cid: tiger.cid});\n    console.log(tiger === tiger2) // outputs true\n\nA model instance includes all the properties defined in its schema. If the model is kept synced with the server, the properties will be automatically updated if any client changes them. But in order for the synchronization mechanism to work, properties must be set using the *set* method:\n\n    tiger.set('legs', 4);\n\nIt is also highly recommended to use the *get* method when retrieving some model property in order to enable *lazy* collection and sequence instantiation (more on this in the Collections and Sequences section).\n\n\n###Model Events\n\nModels generates events when they are updated or deleted. The update events are\ninherit from the Base class, (see property events in Base class), while the *deleted:* event is generated when a model has been deleted, which implies that it has been removed from all the storages (or it is about to be removed since they are eventual consistent).\n\n\n###Finding models\n\nModels are automatically stored in the best storage available. If a server storage is defined it will always store first locally to keep a cached version of the model instance, and after that, store it in the server. If the application is offline it will store it on the server as soon as it goes online again.\n\nStored models can be retrieved using the findById static method that all models inherit automatically:\n\n    // Model##findById(keyPathOrId, keepSynced?: bool, args?: {}): Model\n    var tiger3 = Animal.findById(tiger.id(), true);\n\n*findById* will return a model instance according to the given id or keypath. It is important to understand that a model instance is also a promise (Promise\u003cModel\u003e), i.e. a promise that resolves to itself. This is very useful in order to be able to work with models before they actually are delivered by some storage. If you really want to know when the model has got the best possible data in the current conditions you can just *then* it:\n\n    tiger3.then(function(tiger){\n      // tiger is the model instance with most fresh populated data.\n    });\n\nPlease read section regarding resync to understand why this works.\n\n\n###Understanding *resync*\n\nModels (as well as Collections and Sequences) can be kept automatically synchronized with a server. The synchronization implies that any change to a model instance is automatically persisted in the server, and the changes are propagated to any other clients that also may have the same model instantiated.\n\nEverytime a model is gets new data from the server via the automatic synchronization mechanism, a resync operation is performed, which changes the local instance of the model and emits *changed* events accordingly for any property that has been updated.\n\nThe resync operation can also performed when the instantiated model was persisted locally or remotely on a server:\n\n    var tiger = Animal.findById('1234');\n    \n    tiger.on('name', function(name){\n      console.log(name); // outputs \"Tiger\"\n    });\n\n\nThis initial resync operations are executed before the model promise is resolved, meaning that a resolved model has all the properties available locally or remotelly (it can be seen as if the model is resolved when the best available data for it has been populated):\n\n    var tiger = Animal.findById('1234');\n\n    tiger.then(function(){\n      console.log(tiger.name); // outputs \"Tiger\"\n    });\n\n\n###Model Hierarchies\n\n\n\n###Serialization\n\nSerialization of models is performed via the *toArgs* method. This method is usually not recommended to be overrided since its default implementation uses the model schema and it is designed to work seamlesly with the server component.\n\n\n##Containers\n\nGround provides 2 container classes to keep sets of models: Collections for unordered sets of models, and Sequences for ordered sets of models. Both containers support automatic synchronization with servers and other clients and are implemented as [CRDTs](http://hal.upmc.fr/docs/00/55/55/88/PDF/techreport.pdf) which we believe have very convenient features for a distributed architecture such as Ground.\n\n\n###Keypaths\n\nKeypaths are arrays of strings that define a location where a model or models are located in the storage hierarchy. \n\nA keypath is built by alternating buckets and model ids, with an unlimited length. This allows to describe complex hierarchies of models and containers in a simple and unified way.\n\nSome typical keypath looks like these:\n\n    ['cars'] // An orphan collection with all available cars\n    \n    ['cars', '534acf7e9da0867393000020'] // A Car instance (just one Model)\n    \n    ['zoos', '51c1d0e4f867c09141000010', 'animals'] // An animals collection for one Zoo instance.\n\n\n###Collections\n\nCollections are containers for keeping unordered sets of models. They are the most common type of container, and is suitable for large sets as well as small ones. Even if the models are kept unordered in the storage, it is still possible to sort and filter the elements locally, which is useful when visualizing collections in a UI.\n\nCollections are normally defined as a property in a parent model, although they can also be defined as orphan collections. All model instances are always part of some orphan collection, which is represented as a keypath with just some bucket name:\n\n    ['animals']\n\nCollections can as models be kept auto synchronized with the server, and in that case all instances of the given collection will be updated automatically as soon as some client perform any change on them.\n\n\n####Defining collections in schemas\n\nCollections can be conveniently defined in a model schema:\n\n    var ZooSchema = new Gnd.Schema({\n      name: {type: String},\n      animals: new Gnd.CollectionSchemaType(Animal, 'animals')\n    });\n\n    var Zoo = Gnd.Model.extend('zoo', ZooSchema);\n\nModel properties such as *animals* collection in the above example are not populated when the model is instantiated. They are instead lazily populated when the property is accessed the first time:\n\n    // get(key?: string, args?:{}, opts?: {})\n    var animals = cphZoo.get('animals')\n    \n    // We can listen to events on a collection\n    animals.on('removed:', function(item){\n      // item was removed from animals.\n    });\n    \n    animlals.on('added:', function(item){\n      // item was added to animals.\n    });\n\n*animals* will be populated lazily after calling get. In the same way as models, the collection returned by get is a Promise\u003cCollection\u003e, meaning that it is empty initially but will be populated as soon as data is received from the different storages available. This works efficiently combined with ViewModels, where the data will be displayed as soon as it is available.\n\nThe *get* method accepts in its options a *Query* object, so that the received collection can be filtered or sorted as desired.\n\n####Instantiating collections\n\nAlthoug the recommended way to instantiate a collection is using the *get* method on a model, sometimes is required to retrieve a collection directly. This can be achieved with the *all* method on a model:\n\n    // Get an orphan collection with all animals\n    var animals = Animal.all();\n\n    // Get all animals for a given zoo\n    var animals = Animal.all(cphZoo, 'animals');\n\n####Reference counting\n\nCollections *retains* all the items that are part of it. So if we for example add an item to a collection, we can safely (and often we must to avoid leaks) release it. The collection will release the object automatically if that item is removed from it later or if the collection is destroyed.\n\n####Collection Events\n\nCollections emits a few events that notifies about its changes:\n\n  - *updated:* emitted when some element in the collection has changed any property.\n  - *sorted:* emitted when the sorting function has been changed.\n  - *added:* emitted when an item has been added to the collection.\n  - *removed:* emitted when an item has been removed from the collection.\n  - *resynced:* emitted when the collection has been resynced.\n  \n###Sequences\n\nSequences provides a convenient way to represent a sorted list of model instances. They are specially useful when a sorted list of objects can be accessed and manipulated by several users simultaneously.\n\nA sequence can be kept synchronized across many clients and is implemented as a Commutative Replicated Data Type (CRDT) in order to achieve eventual consistency. This implies that sequences will eventually converge to a common state even when multiple client simultaneously modifies the same sequence.\n\nSequences likewise Collections are normally defined as properties in models using a schema datatype\n\n\n####Defining sequences in schemas\n\nCollections can be conveniently defined in a model schema:\n\n    var UserSchema = new Gnd.Schema({\n      name: {type: String},\n      playlist: new Gnd.SequenceSchemaType(Song, 'songs')\n    });\n\n    var Users = Gnd.Model.extend('User', UserSchema);\n\nModel properties such as the *playlist* sequence in the above example are not populated when the model is instantiated. They are instead lazily populated when the property is accessed the first time:\n\n    // get(key?: string, args?:{}, opts?: {})\n    var playlist = myUser.get('playlist');\n\n*playlist* will be populated lazily after calling get. In the same way as models, the sequence returned by *get* is a Promise\u003cSequence\u003e, meaning that it is empty initially but will be populated as soon as data is received from the different storages available. This works efficiently combined with ViewModels, where the data will be displayed as soon as it is available.\n\n####Instantiating sequences\n\nA sequence can also be instantiated by using the *seq* function on a model:\n\n    // Get the animals sequence\n    var playlist = myUser.seq(Song, 'songs');\n      \n    // Push a model to the back of the sequence\n    playlist.push((new Animal({name: 'tiger'}).autorelease());\n\n    // Unshift a model to the front of the sequence\n    playlist.unshift((new Animal({name: 'lion'}).autorelease());\n\n    // Insert a model at index 1 of the sequence\n    playlist.insert(1, (new Animal({name: 'panther'}).autorelease());\n\n    // Remove the model at index 2 from the sequence\n    playlist.remove(2);\n\nSequences also provide a number of functional methods for traversing the sequence items such as *each*, *pluck*, *first*, *last* etc. To traverse all items in a sequence you could do:\n\n    var playlist = myUser.seq(Song, 'songs');\n    \n    playlist.then(function(){\n      playlist.each(function(song){\n        console.log(song.name);\n      });\n    });\n\n####Reference counting\n\nSequences *retains* all the items that are part of it. So if we for example add a item to a sequence, we can safely \n(and often we must to avoid leaks) release it. The sequence will release the object automatically if that item is removed from it later or if the sequence is destroyed.\n\n####Sequence Events\n\nSequences emits a few events that notifies about its changes:\n\n  - *updated:* emitted when some model in the sequence has changed any property.\n  - *inserted:* emitted when an item has been inserted in the sequence.\n  - *removed:* emitted when an item has been removed from the sequence.\n  - *resynced:* emitted when the sequence has been resynced.\n\n\n##Events\n\nEvents in ground try to mimick the EventEmitter object from early versions of NodeJS.\n\nOne important consideration to keep in mind is that ground events are propagated inmediately\ni.e., they do not wait for the next event loop. The reason for this is to provide high \nperformance and responsivity. The major implication of this is that you have always to place\nyour listeners before you emit, otherwise the event will be missed.\n\n\n##Promises\n\nGround provides a ver minimal Promise implementation that follows [Promise /A+](http://promises-aplus.github.com/promises-spec).\n\n\u003ca href=\"http://promises-aplus.github.com/promises-spec\"\u003e\u003cimg src=\"http://promises-aplus.github.com/promises-spec/assets/logo-small.png\" alt=\"Promises/A+ logo\" align=\"right\" /\u003e\u003c/a\u003e\n\nTODO: Examples:\n\n\n##Offline\n\nA modern web application should be able to work offline. Ground provides a complete synchronization mechanism between client and server instances of models and collections. Data required by the local instances of models are cached so that they are available when working offline, and all data produced while being offline gets updated automatically as soon as the application gets connectivity with the server.\n\n\n#Views\n\n\n##ViewModel and Declarative Bindings\n\nGround supports the popular MVVM pattern, as a specialization of the MVC. This\npattern implies that the controller is replaced by a ViewModel\n(The model of the view), which provides mechanisms for easily binding model properties to a View (in this case just some HTML portion). \n\nThe bindings are expressed in the view as *data* attributes in any valid HTML tag that forms the view. With this pattern, the view still stays free of \napplication logic, but the view can react when the underlying model is modified in some way.\n\nLets start with a simple dynamic list example:\n\nHTML View:\n\n    \u003clu id=\"myTodoList\"\u003e\n      \u003cli\u003eTodo List Header\u003cli/\u003e\n      \u003cli data-each=\"todos: todo\" data-bind=\"text: todo.description\" data-class=\"active: todo.isActive\"\u003e\u003cli/\u003e\n      \u003cli\u003eTodo List footer\u003cli/\u003e\n    \u003clu/\u003e\n    \nJavascript:\n\n    var todos = new Collection([\n      {description:\"Prepare Food\", active: true},\n      {description:\"Clean the house\", active: false},\n      {description:\"Go to a meeting\", active: true},\n    ]);\n\n    var viewModel = \n      new ViewModel(document.getElementById('myTodoList'), {todos: collection});\n\nThis example demonstrates binding a Collection to a list. The bindings will not just populate the list from the \ncollection, but also keep it up-to-date at all times, adding and removing items as necessary. For example, if the filter function in the model is updated,\nthe HTML list will just show the filtered nodes, or if some item that is part\nof the list is updated, the list will also display the changes automatically.\n\nNested bindings are also supported, so it is possible to nest collections of collections that behave as expected:\n\n    // TODO: Add an example here...\n\nThe ViewModel class accepts in its constructor customized data binders, but\nout fo the box it provides the most common ones: *bind*, *each*, *show*, *class* and *event*.\n\n\n###Available binders\n\nGround provides a basic set of binders that cover the most common needs, but more binders can be added easily if necessary.\n\n####bind\n\nThis binder binds an attribute or the innerHTML of a tag with the given model properties. It accepts the following syntax:\n\n    data-bind=\"attr0: keypath0; attr1: keypath1; ... ;attrn: keypathn\"\n\nThe attr's are tag attributes. The special attribute *text* is used to represent the inner HTML of the node.\n\nExamples: \n\n    \u003cimg data-bind=\"src: myimage.src; alt: myimage.desc\"\u003e\u003c/img\u003e\n    \u003ch1 data-bind=\"text: obj.title\"\u003e\u003c/h1\u003e\n\n####each\n\nThe each binder is used to bind collections and sequences. Its syntax is as\nfollows:\n\n    data-each=\"keypath: alias\"\n\nThe HTML node where data-each is placed will be repeated as many times as elements in the bound collection. The node is allowed to have any other binders,\nalso it may have subnodes with binders as well, and even the data-each binder, allowing as much nesting as necessary.\n\n\n####show\n\nThis binder is used to show or hide an HTML element depending on the value of a property bound to it:\n\n    data-show=\"[!]keypath\"\n    \nIt supports negating the keypath value (using the optional exclamation character), and by that it becomes in practice a *data-hide* binder.\n\n\n####class\n\nThis binder is used to add one or several css classes to an HTML element depending on the given properties.\n\n    data-class=\"className0, className1, ... classNameN: [!]keypath1; className10, className11, ... className1N: [!]keypath2 ...\"\n\nAn arbitrary set of classes can therefore be associated to a boolean value in the specified keypath. The keypath can be negated in a similar way to the show binder.\n\n\n####event\n\nThis binder attaches a event to a given element. This binder is particularly useful combined with the *each* binder, since it will bind events\nto nodes that are added and removed dynamically.\n\n    data-event=\"eventName1: keypath1; eventName2: keypath2; ... \"\n\nThe events that can be bound to keypaths are any standard DOM events, such as\n*change*, *click*, *keyup*, etc\n\n\n#Server\n\nGround provides a server component for [Node](http://nodejs.org) that is necessary for some of the functionality\nprovided by models, such as automatic synchronization. \n\nThe server can be spawned multiple times in the same machine or in a cluster of machines in order to provide \nscalability, but you will still need a load balancer in front of the nodes. The communication between nodes is\nachieved using the excellent pub/sub functionality in [Redis](http://redis.io), so this is a required component\nas well.\n\nThe server is designed to work with [Mongoose](http://mongoosejs.com) as database ORM. \n\n\n#Utilities\n\n\n\n##DOM\n\nYou will notice that when developing applications with Ground, you will not need to interact with the DOM as often as you may do, in fact, Ground encourages to avoid interacting with the DOM as much as possible. Using complex queries to create behaviour in a web application often leads to code of poor quality and innecessary complexity. Still, there are situations where it is unavoidable to access to the DOM, for example when attaching a root element to a ViewModel or defining entry elements in a hierarchical route. \n\nInstead of leaving the DOM manipulation to a heavy weight library such as jQuery, Ground provides a minimal set of efficient and cross browser utilities to fullfill most of the required needs. The methods provided try to be close to jQuery APIs.\n\n###Selection\n\nYou make selections as in jQuery by using the $ method. Only a few selectors\nare available, and they will all return an array like wrapper object with all\nthe HTML elements that match the query:\n\n    Gnd.$(queryString: string, context?: HTMLElement): Gnd.Query;\n\nYou can use the context to constraint the query to just a subtree of the DOM.\n\n- By Id\n\n        var $myid = Gnd.$('#myid')  \n\n- By class name\n    \n        var $redBoxes = Gnd.$('.red-box')\n    \n- By Name\n\n        var $alldivs = Gnd.$('div');\n\n\n###Creation\n\n\nDOM fragments can be created by giving HTML code:\n\n    var $fragment = Gnd.$('\u003cdiv\u003e\u003cp\u003eHello World\u003c/p\u003e\u003cdiv\u003e')\n    Gnd.$('body')[0].appendChild($fragment[0]);\n\n\n###Attributes\n\nAttributes can be read and wrote similar to jQuery:\n\n    Gnd.$(div).attr('', )\n\n    var attr = $(div).attr('');\n\n###Text and Html\n\n\n\n###Events\n\n\n\n#[Reference](http://gnd.io/api)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foptimalbits%2Fground","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foptimalbits%2Fground","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foptimalbits%2Fground/lists"}