glintcms-starter-glintcms
Version:
This is a WebSite implementation with GlintCMS. It shows how you can use GlintCMS.
24 lines • 55.3 kB
JSON
{
"meta": {
"title": "GlintCMS | initiated by intesso",
"description": "The invisible Content Management System"
},
"home-title": "The invisible Content Management System",
"home-subtitle": "GlintCMS is a modular and flexible CMS that basically has no backend, but slick inline ediiting capabilities. It is built with node.js\n",
"home-teaser": "<p><img alt=\"\" src=\"/files/screenshots/edit-content.gif\" style=\"width:100%\" /></p>\n",
"home-box-1": "### TL;DR \n\nGlintCMS is an in-page, overlay style WYSIWYG (What you see is what you get) CMS. What this means is that to edit a page you simply navigate to the page as you would when you browse your website. Once you arrive at a page you use the overlaid main menu to perform tasks or you simply hover over the main section of the page to edit content or change page settings. \n\n\nThe building blocks of GlintCMS are designed that you can build Web-Sites as well as Web-Applications. \n\n\n### Stability\n\nGlintCMS is robust and is used e.g. on [www.intesso.com](http://intesso.com) and [www.glintcms.com](http://glintcms.com) (the site you are looking at). \n\n\nThe API Stability is somewhere between experimental and stable. \n",
"home-box-2": "### Design Principles \n\n - it is a [GlintApp](https://github.com/glintapp/glintapp) implementation\n - runs in node.js and in the browser with browserify\n - universal aka (isomorphic) javascript\n - modular | collection of reusable, replacable modules | follows unix philosophy\n - fast, no magic for SEO (like screen scraping of own content with headless browser)\n - for WebSites as well as for WebApps\n - Clean Code over Convention over Configuration\n - mostly framework agnostic\n - easy to learn\n - flexible\n - reusable\n - inline editing\n - minimal management backend\n - minimal build tasks\n - minimal configuration\n - no dynamic require\n - no magic\n - only simple abstractions\n\n",
"home-box-3": "\n",
"home-box-4": "### Use Cases \n\nFrom the very beginning GlintCMS was designed to run efficiently on both the server and in the browser. That's why it is a really good solution to many problems:\n\n- Web Application (Single Page Applications) \n- Web Sites / Platforms (Heavy server side rendering)\n- Hybrid variants of the above",
"home-box-5": "### Technology \n\nIt is written purely in JavaScript and runs on [node.js](https://nodejs.org) and in the browser thanks to [browserify](http://browserify.org) and makes use of many great modules from [npm](https://www.npmjs.com).\n\n- Works with all the newer browsers\n- Uses [Express](http://expressjs.com) on the server side\n- Runs on Linux and Mac OS, Windows is not yet supported (any help appreciated)\n- Tested with `node.js 0.12.7 and 4.1`\n",
"home-box-6": "### Getting Started \n\n\n>The best way to get started is to read along and install a starter project e.g. [glintcms-starter-intesso](https://github.com/glintcms/glintcms-starter-intesso). \n>\n> (it should only take a few of minutes to get going) \n\n\nYou can use it out of the box, for small to medium sites.\n\n\nHave a look at the code of the modules and shout out if you need <big>help</big>.\n\n\n\n> **[github](https://github.com/glintcms/glintcms)**\n\n\n> **[npm](https://www.npmjs.com/search?q=glintcms)**\n\n# Showtime\n\nOpen the demo page and enter the following **Email** and **Password**:\n\n- `Email` : *content@intesso.com*\n- `Password`: *ContentContent*\n\n<a href=\"//demo.glintcms.com/login\" target=\"_blank\" style=\"font-size: 32px;\"><h1>OPEN DEMO</h1></a>\n",
"www-title": "Works with what",
"www-content": "<h1 style=\"text-align:center\"><tt><span class=\"marker\">Built with</span></tt></h1>\n\n<p style=\"text-align:center\"><tt>The GlintCMS core modules are mainly built with:</tt></p>\n\n<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\" style=\"width:100%\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"node.js, efficient web server with javascript\" src=\"/files/works-with-what/nodejs.png\" style=\"height:80px; width:149px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"http://nodejs.org\">node.js</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"express.js, Fast, unopinionated and minimalist web framework for Node.js\" src=\"/files/works-with-what/express.png\" style=\"height:80px; width:222px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"http://expressjs.com\">express.js</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"npm, node package manager\" src=\"/files/works-with-what/npm.png\" style=\"height:80px; width:205px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"http://npmjs.org\">npm</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"browserify, bundle node.js modules for the browser\" src=\"/files/works-with-what/browserify-hat.png\" style=\"height:80px; width:95px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"http://browserify.org\">browserify</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"javascript, ES5\" src=\"/files/works-with-what/javascript.png\" style=\"height:80px; width:79px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"https://es5.github.io/\">JavaScript ES5</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n<p style=\"text-align:center\"><tt>... and many more great open source npm modules ...</tt></p>\n\n<p style=\"text-align:center\"> </p>\n\n<p style=\"text-align:center\"> </p>\n\n<h2 style=\"text-align:center\"><tt>Additionally this site uses</tt></h2>\n\n<p style=\"text-align:center\"><tt>(no GlintCMS Requirement):</tt></p>\n\n<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\" style=\"width:100%\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"\" src=\"/files/works-with-what/jquery.gif\" style=\"height:80px; width:124px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"http://jquery.org\">jQuery</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"\" src=\"/files/works-with-what/bootstrap-big.png\" style=\"height:80px; width:93px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"http://getbootstrap.com\">Bootstrap</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"html5\" src=\"/files/works-with-what/html5-256.png\" style=\"height:80px; width:80px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"http://www.html5rocks.com\">HTML 5</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td style=\"text-align:right\"><img alt=\"css 3\" src=\"/files/works-with-what/css3.png\" style=\"height:80px; width:80px\" /></td>\n\t\t\t<td>\n\t\t\t<h1><a href=\"http://code.tutsplus.com/series/css3-mastery\">CSS 3</a></h1>\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n<p style=\"text-align:center\"><tt>... and many more great open source npm modules ...</tt></p>\n\n<h1 style=\"text-align:center\"> </h1>\n\n<h1 style=\"text-align:center\"><tt>Compatible with</tt></h1>\n\n<p style=\"text-align:center\"><tt>It is one of the strengths of GlintCMS, that it is not very obtrusive.</tt></p>\n\n<p style=\"text-align:center\"><tt>You can use your own preferred frameworks and modules and just add GlintCMS alongside it.</tt></p>\n\n<p style=\"text-align:center\"><tt>So GlintCMS is basically compatible with almost everything.</tt></p>\n\n<p style=\"text-align:center\"> </p>\n\n<p style=\"text-align:center\"> </p>\n\n<p style=\"text-align:center\"> </p>\n",
"bb-title": "Building Blocks",
"bb-content": "# building blocks\n\n\n> building with blocks is fun!\n\n```\n \n +--------------+ +--------------+ +--------------+\n | | | | | |\n | wrap | +----> | container | +----> | block |\n | | | | | |\n +--------------+ +--------------+ +--------------+\n\n + +\n | |\n v v\n\n +--------------+ +--------------+ + + + + + + + +\n | | | |\n | widget | +----> | adapter | +----> + cache +\n | | | |\n +--------------+ +--------------+ + + + + + + + +\n \n\n```\ncreated with [asciiflow](http://asciiflow.com)\n\n## block\nBlocks are the heart of everything that is editable in *GlintCMS*.\n\nA block provider can be a plain text `glint-block-text`, or an image or a rich text e.g. `glint-block-ckeditor` etc.\n\nThe `block` itself (`glint-block`) is a unifying interface for the block providers.\n\nIt is the block providers responsibility to display its data and to turn it into something editable, when switching to edit mode.\n\nThey must basically implement the following sync functions:\n\n```javascript\nload(content)\nedit()\nvar content = save()\n```\n\n## adapter\nThe `adapter` (`glint-adapter`) is the unifying interface for the adapter providers like e.g. `glint-adapter-fs` or `glint-adapter-elasticsearch`.\n\nThe adapter provider is responsible for storing and retrieving the data/content.\n\nIt only solves access to single types, entities, documents or tables (the terms very with the providers technology, let's stick with the term `type`').\n\nIt does not combine instances of different types (joins), that's up to the\n\nAn adapter provider must implement these async functions:\n\n```javascript\nload(.., cb)\nsave(.., cb)\ndelete(.., cb)\nfind(.., cb)\n```\n\n## cache\nIs optional and is not yet implemented.\n\n\n## container\nThe `container` (`glint-container`) holds the different blocks and orchestrates nifty details, like\n- what should be loaded (rendered) on the server and what in the browser.\n- switching the blocks into the edit mode `edit` and back (`save` or `load` on cancel)\n- passing the data between the `adapter` and the `block`s.\n- a container has got one adapter and most likely has several `block`s.\n\nIf you don't have any editable content on your page, you don't need a container.\n\n\n## widget\nA `widget` (`glint-widget`) can be useful for displaying content, that does not need to be editable in this place.\n\nAs an example, you could use it to display the three latest blog entries on the first page.\n\nA `widget` implementation needs to implement the functions:\n```javascript\ndata(cb) // async, optional, if you don't need to load data in an async way\nrender(fn) // sync, returns the rendered content\n```\n\nThe `widget` itself exposes the `load` function to integrate with the `wrap` loading mechanism.\n\n## wrap\nThe `wrap` (`glint-wrap`) wraps it all up.\n- it can have several `container`s, `widget`s and `wrap`s.\n- it also is involved in what should be loaded (rendered) on the server and what in the browser.\n\n\n",
"doc-title": "Documentation",
"doc-content": "# API\n\nThe design of the module's `api` was chosen to get a good balance between \"easy to use\" and \"easy to extend\".\n\nThe `api` of the modules is designed after what we call the `associative-provider` model.\n\nYou wouldn't use a `TextBlock` directly, but via a `Block` that holds the `TextBlock`\n\t\n```javascript\n//e.g.: Block -> TextBlock\nvar block = Block(TextBlock()).use(Style());\n```\n\n\n# general\n\n## extendability\n\nHave a look at the [extend](EXTEND.md) documentation.\n\nThe following `api` document describes how to \"use\" the `building blocks`, (not how to extend them).\n\n\n## naming/require\nThe `building blocks` are called: `wrap, container, etc.` in this document. However, the module names to require them start always with `glint-`.\nAlso in general the module names are hierarchically structured, separated with a dash `-`, where on the left hand side is the more generic part of the name.\n\nSo if you want to use the `adapter` with the `ajax` provider for example, you do it like this:\n\n```javascript\nvar Adapter = require('glint-adapter');\nvar AjaxAdapter = require('glint-adapter-ajax');\n\nvar adapter = Adapter(AjaxAdapter());\n```\n\n\n## get/set\nGetter and Setter can be called like this:\n\n```javascript\n// set\nvar place = obj.place('server');\n\n// get\nconsole.log(obj.place());\n// --> server\n\n```\n\nWhen you provide a value (set), the method returns `this`, so that you can chain other methods.\n\n\n## chainable methods\nMost of the methods are chainable (they return this):\n\n```javascript\n// example:\nWrap(o)\n .editable(req.userCan('edit'))\n .i18n(req.i18n)\n .cid(req.params.article)\n .place(o.place)\n .load(res.locals, function(err, result) {\n debug('route loaded', err, req.params.article, result);\n if (err) return next(err);\n res.send(result.page);\n })\n```\n\n## events\n\nMost of the `building blocks ` inherit from `EventEmitter` and expose useful events:\n\n```javascript\n// Example from the code:\nvar EventEmitter = require('events').EventEmitter;\n\n/**\n * Expose Block element.\n */\nexports = module.exports = Block;\ninherits(Block, EventEmitter);\n```\n\nThe Events can be especially helpful, when designing a `plugin`.\n\n### get/set\n\nGetter and Setter emit an event:\n- `emit(name, value)`\n\n### methods\n\nThe building blocks methods emit events for every method with the given name:\n- `emit(pre-<methodName>, arguments)`\n- `emit(<methodName>, arguments)`\n- `emit(post-<methodName>, arguments)`\n\n\n## rendering/place\nrendering (load) is done by default on the server.\nediting, saving and deleting is always initiated in the browser.\nblocks and widgets can be defined to render in the browser when needed.\nhowever you can also override where the components (blocks and widgets) are rendered all together.\nyou can use this for example to let everything be rendered on the server,\nwhen the site is being called by a bot, search engine, crawler or the like.\n\n\n**place**\nglint is designed to use on the server as well as in the browser (pick you buzzword for it... universal, polymorph, what ever you like).\nWith the `place` get/set method, you can define, where you would like the control to be rendered.\n\nThese are the available options (strings):\n- server\n- browser \n- both\n- force:server\n- force:browser\n- force:both\n\n\n**priorities**\n\n (0:low priority ... 3:high priority)\n\n 0 render on server by default\n\n 1 Block.render('browser') or\n Widget.render('browser')\n -> render these items in the browser\n\n 2 Wrap.render('server') or\n Container.render('server')\n -> render ALL items on the server, e.g. when requested by a search engine.\n\n 3 SpecificBlock.render('force:both') or\n Widget.render('force:both)\n -> when a Specific Block has this flag, it will always be rendered on both sides (server and browser)\n\n 4 Same as priority 3 but with 'force:server' or 'force:client'\n -> render always on the server respectively in the browser\n\n\n# wrap\n\nA `wrap` can hold several `container`s and `widget`s as well as other `wrap`s.\nLet's call them `controls`. With the wrap, you can define how the `controls` are loaded.\nFirst you can define the default object with the method `defaults`.\nWith the methods `parallel`, `series` and `eventually`, you can define everything from a simple to a quite sophisticated loading execution.\nSee [flow-builder](https://github.com/intesso/flow-builder)\n\nThe `wrap` runs on the server and/or in the `browser` depending on the defined `place`s.\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nWrap.api === 'wrap'\n```\n\n### get/set\n\nYou can get/set these properties on the `wrap`.\n- key\n- id\n- selector\n- prepend\n- append\n- el\n- place\n- editable\n- cid\n\nWhen you set `editable` or `place` on the wrap, the value is also set on all of it`s controls.\n\n`cid` gets/sets the id on the first `container` that the `wrap` holds.\n\n\n## methods\n\n### constructor\n\n```javascript\n\n// the `wrap` has got the optional key, control arguments. \n// what's added in the constructor get's added with the `parallel` workflow.\nvar wrap = Wrap(key, control);\n\n// but you can also create the Wrap fist, and then define your workflow.\n// in this example the articles and projects `load in parallel` and after they are done,\n// the resulting transfer object is handled over to the next steps:\n// 1. in this exampe it's first the contentWidget,\n// 2. and then the layoutWrap after the previous step is done.\nvar wrap = Wrap();\nwrap\n .parallel(container)\n .parallel('articles', articles.selector('.js-articles'))\n .parallel('projects', projects.selector('.js-projects'))\n .series('content', contentWidget.place('force:server'))\n .series(LayoutWrap(o.layout).place('force:server'))\n```\n\n### defaults\n\nIt let's you define a default object, that's the starting object in every `load` workflow.\nThis object is the *initial workflow transfer object*\n\n```javascript\n// set single key, value\nwrap.defaults(key, value);\n// set object\nwrap.defaults(object);\n// get value\nwrap.defaults(key);\n```\n\n### parallel\nWhen you define several `controls` with the `parallel` method right after each other, they get executed in parallel, and only when all of them have finished (or one of them has an error), the next step is executed.\n\n```javascript\n// adds a single control, the clone of the resulting object merged with the transfer object.\nwrap.parallel(control;\n// adds a sincle control, the clone of the resulting object is insterted into the transfer object with the given `key`.\nwrap.parallel(key, control);\n\n// examples\nwrap.parallel(container);\nwrap.parallel('news', widget1);\nwrap.parallel('articles', widget2);\n```\n\n### series\n`series` method calls, are executed after the previous method has finished.\nIt has got the same signature as the `parallel` method.\n\n### eventually\n`eventually` method calls are started immediately, but are evaluated only at the very end when the whole workflow has finished.\nIt has got the same signature as the `parallel` method.\n\n### load\nCalling the `load` method, starts the defined wrap workflow.\n\n\n```javascript\n// it has got an optional context object. This object is taken as the *initial workflow transfer object* when provided.\n// the callback function `callback(err, result)` is called once everything is `load`ed.\n\nwrap.load([context, ] callback);\n// or\nwrap.load(callback);\n\n\n// Example:\nfunction(req, res, next) {\n wrap.load(res.locals, function(err, result) {\n if (err) return next(err);\n res.send(result.page);\n });\n}\n```\n\n\n\n# widget\nWith a widget, you can render/display noneditable content on the server and/or in the browser depending on the defined `place`.\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nWidget.api === 'widget'\n```\n\n### get/set\n\nYou can get/set these properties on the `widget`.\n- key\n- id\n- selector\n- prepend\n- append\n- el\n- place\n- template\n- data\n- render\n\nWhen you set `editable` or `place` on the wrap, the value is also set on all of it`s controls.\n\n`cid` gets/sets the id on the first `container` that the `wrap` holds.\n\n\n## methods\n\n### constructor\n\n```javascript\n// you can provide the `render` method in the constructor\nvar widget = Widget(renderFunction);\n\n// or you can provide the `data` and `render` method on the widget instance. Example:\nWidget()\n .data(function(fn) {\n adapter.findLatest(o.getLocale(), 3, fn);\n })\n .render(function(options) {\n return ejs.render(o.template || template, options);\n })\n```\n\n### data\nYou can optionally provide a `data` method, if your widget need's to make asynchronous data calls.\nIt returns `this` and takes a callback function with the parameters: `callback(err, result)`.\n\n\n```javascript\nwidget.data(callback);\n```\n\n### render\nThe `render` function is a synchronous function and must return the rendered content.\nThe data object is provided in the first argument.\nIt let's you choose what ever rendering engine you want to use (as long as it runs on the server as well as in the browser).\n\n```javascript\nwrap..render(function(options) {\n return compiledDotTemplate(options);\n})\n\n```\n\n\n### load\nThe `load` method is called from the `wrap` that contains this widget during the `load` workflow execution.\nMost probably, you never have to call this method directly.\nInternally, the `load` method calls the `data` method (if it was provided), and then `render` with the resulting object.\n\n\n\n# container\nContainers are only used when you use `blocks`.\nA container runs on the server and in the browser. On the server, only the `load` method is called (most likely from the surrounding `wrap`),\nIn the browser, there is more methods:\n- load\n- edit\n- save\n- cancel\n- delete\n\n\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nContainer.api === 'container'\n```\n\n### get/set\n\nYou can get/set these properties on the `container`.\n- key\n- id\n- place\n- template\n- editable\n- blocks\n- adapter\n\n\n## methods\n\n### constructor\n\n\n```javascript\n// you can optionally provide the `blocks` as well as the `adapter` in the constructor\n\nvar blocks = {\n title: text().selector('body h1'),\n short: text().selector('[data-id=short]'),\n text: editor().selector('[data-id=text]'),\n meta: Block(MetaBlock())\n};\n\nvar adapter = Adapter(AjaxAdapter())\n .db(db)\n .type(type)\n .use(Dates())\n .use(Id())\n\n// constructor\nvar container = Container(blocks, adapter);\n\n\n// or you can provide them afterwards. Example:\nvar container = Container();\ncontainer\n .blocks(blocks)\n .adapter(adapter)\n```\n\n\n### load\n(it runs either on server or browser depending on the `place`)\n\n> Internal sequence:\n\n1. it first calls the `adapter`s `load` method,\n2. afterwards all of the `block`s `load` methods\n\n\n### edit\n(runs only in the browser)\n\n> Internal sequence:\n\n1. it first calls the `load` method on this container\n2. it then calls the `edit` method on all of the `block`s.\n\n\n### save\n(runs only in the browser)\n\n> Internal sequence:\n\n1. first it calls all of the `block`s `save` methods\n2. it then calls the `adapter`s `save` method,\n3. aaand finally it calls the `load` method on this container to finish the command.\n\n\n\n### cancel\n(runs only in the browser)\n\n> Internal sequence:\n\n1. it basically just calls the `load` on this container.\n\n\n### delete\n(runs only in the browser)\n\n> Internal sequence:\n\n1. it first calls the `adapter`s `delete` method,\n2. and afterwards it calls the `load` on this container, to finish things up.\n\n\n\n# block\n\nThe `blocks` are the heart of everything that is editable in *GlintCMS*.\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nBlock.api === 'block'\n```\n\n### get/set\n\nYou can get/set these properties on the `block`.\n- id\n- selector\n- el\n- place\n\n\n## methods\n\n\n### constructor/methods\n\n```javascript\n// you normally instantiate the `block` with the specific `block-provider` that it should hold\nvar block = Block(blockProvider);\n\n// Example:\nvar block = Block(TextBlock()).use(Style());\n\n// however you can also add/remove the `block-provider` later with `delegate` and `undelegate`\nvar block = Block();\nblock.delegate(TextBlock());\n\n// you can also undelegate a block\nblock.undelegate(textBlock);\n```\n\nThe `block` basically delegates the method calls to the specific `block-provider`.\nDue to a runtime behaviour (missing `el` \"HTMLElement\"), the `block` has the ability to buffer method calls in a FIFO, and execute them later.\n\nIn addition to the 'getters and setters', it buffers and forwards the following methods:\n- load\n- edit\n- save\n- cancel\n- hasChanged\n- isValid\n\n### plugins\n\nYou can extend `block`s with plugins with the `use` method, as well as with the `mixin method`.\n\n#### use\n\nConsult the [extend] documentation or the code.\n\n#### mixin\n\nConsult the [extend] documentation or the code.\n\n\n```javascript\n// Example:\nvar block.use(Style());\n\n```\n\n\n# adapter\n\nThe `adapter` is the interface to the storage.\n\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nAdapter.api === 'adapter'\n```\n\n### get/set\n\nYou can get/set these properties on the `adapter`.\n- db\n- type\n- fn\n\n\n\n## methods\n\n\n### constructor/methods\n\n```javascript\n// you normally instantiate the `adapter` with the specific `adapter-provider` that it should delegate it's calls to.\nvar adapter = Adapter(adapter);\n\n// Example:\nvar adapter = Adapter(AjaxAdapter());\n\n// however you can also add/remove the `adapter-provider` later with `delegate` and `undelegate`\nvar adapter = Adapter();\nadapter.delegate(AjaxAdapter());\n\n// you can also undelegate a block\nadapter.undelegate(ajaxAdapter);\n```\n\nThe `adapter` basically delegates the method calls to the specific `adapter-provider`.\n- find(query, callback)\n- load(id, callback)\n- save(id, content, callback)\n- delete(id, callback)\n\nThe function has the form: `callback(err, result)`\n\nthe `result` object is the parsed javascript object for the given `id`,\nand an array with the matching objects on the `find` callback.\n\n### plugins\n\nYou can extend `adapter`s with plugins with the `use` method, as well as with the `mixin method`.\n\n#### use\n\nConsult the [extend] documentation or the code.\n\n#### mixin\n\nthe `mixin` is mainly used to extend the adapter's query capability.\nSince the `adapter` does not \"magically unify the different storage query language\", but exposes it directly,\nthe `adapter` needs a way to handle the different provider's queries.\n\nIt does it with the mixin:\n\n```javascript\nvar mixin = {\n fs: {\n findWithLocale: function(locale, fn) {\n var query = 'this.id.indexOf(\"__template__\") === -1 && this.locale === \"' + locale + '\"';\n this.find({$where: query}, fn);\n }\n },\n elasticsearch : {\n findWithLocale: function(locale, fn) {\n // pseudocode\n this.find(elasticSearchSpecificQuery, fn)\n }\n }\n};\n\nadapter.mixin(mixin);\n```\n\nAs you can see in the example, the mixin must have an object, with the `adapter-provider` name as the key,\nand the functions to `mixin` as the value (nested object).\n\nThis way you can support more than just one adapter-plugin,\nand if you use some one else's module that does not have the queries for your provider,\njust add them yourself and send a pull request.\n\n\n```javascript\n// Example:\nvar block.use(Style());\n\n```\n\n\n# trigger\n\nA `trigger` consumes the `container`s api methods and exposes them to the user in a usable form.\nTherefore `trigger`s are only useful in the browser, not on the server side.\nAlthough theoretically, you could write a trigger to use on the server side as well, maybe for application integration.\n\n```javascript\n// usage example with the trigger implementation: keyboard and sidenav.\n\nvar keyboard = require('glint-trigger-keyboard');\nvar sidenav = require('glint-trigger-sidenav');\n\nwrap.containers.forEach(function(container) {\n keyboard().add(container);\n sidenav().add(container);\n});\n```\n\nThe trigger itself ('glint-trigger') is only a `base class`, the trigger implementors can inherit:\n\n```javascript\n// Snippet from the code.\n\n/**\n * Expose `Keyboard`\n */\nexports = module.exports = Keyboard;\ninherits(Keyboard, Trigger);\n\n```\n\n# extend glintcms\n\nIt was important during the design of the module's `api`, to come up with something that's easy to extend.\nAnd I think you can say, it is a strength of *GlintCMS*, that it is very flexible and easy to extend.\n\n# providers\n\nIf you want to integrate third party modules for example for a new editing experience, you can just create a new `block-provider`, and implement the methods:\n\n- `load`\n- `edit`\n- `save`\n\nHave a look at e.g.: [glint-block-text](https://www.npmjs.com/package/glint-block-text)\n\nYou don't have to worry, how the stuff is being saved, the `adapter` takes care of that.\n\n\nÀ propos `adapter`, if you want store your data in another `database`, you can create a new `adapter-provider` and implement the methods:\n\n- `find`\n- `load`\n- `save`\n- `delete`\n\nCheck out e.g.: [glint-adapter-fs](https://www.npmjs.com/package/glint-adapter-fs)\n\nThen extend your find queries `adapter.mixin()` with the query language of your new `provider`.\n\n\n# plugins\n\nAnother great opportunity is, that you can create plugins for the different `building-blocks` either with the `use` or `mixin` method.\n\nActually, much of the functionality of *GlintCMS* is build with plugin modules:\n\nHave a look at the examples:\n\n- [block plugin](https://www.npmjs.com/package/glint-plugin-block-style-editable)\n- [adapter plugin](https://www.npmjs.com/package/glint-plugin-adapter-dates)\n- [wrap plugin](https://www.npmjs.com/package/glint-plugin-wrap-i18n)\n\n\nand search npm for [glint-plugin](https://www.npmjs.com/search?q=glint-plugin)\n\n\n### use\n\nThe `use` method takes a function as argument that's called with `this`, and returns `this`, to make it chainable.\n\nIt's probably easiest to look at the code, and the usage examples just mentioned before.\n\n```javascript\nBlock.prototype.use = function(plugin) {\n plugin(this);\n return this;\n};\n```\n\n### mixin\n\nIf the plugin is just a `function`, or a couple of functions, you can insert them with the `mixin` mechanism.\nIt takes an object with the required functions as key, value pairs, and it returns `this`, to make it chainable.\n\nMaybe the code is even more understandable than the explanation :-):\n\n```javascript\nBlock.prototype.mixin = function(mixins) {\n var self = this;\n Object.keys(mixins).forEach(function(key) {\n self[key] = mixins[key];\n });\n return this;\n};\n```\n\n### events\n\nPlugins get a lot of power from the events.\n\n<hr>\n\n# module development\n\nDeveloping modules for glint is not difficult. It does not force you using specific libraries, or patterns.\n\nHowever there is a few things you should consider:\n\n\n## general considerations\n- make sure your module runs on the server as well as in the browser (if it is not intended otherwise).\n- The main `glint building blocks` right now don't use ES2015, ECMAScript 6 or ES6 or how ever you call the latest JavaScript version.\n This helps to keep things simple and avoid running into compatibility pitfalls especially with the different browsers.\n- it is often better to keep the modules simple for every one, we don't use anything that needs to be compiled like e.g. less, sass or coffeescript.\n- if you still use something that needs to be compiled, anything like e.g. less, sass or coffeescript, do it in your build, and provide the compiled js, css.\n- also your module should be minimal and not depend on other large modules.\n- know what you `require('...')`\n- substack wrote a really helpful guide, how you can develop components with browserify: [browserify-handbook](https://github.com/substack/browserify-handbook#reusable-components)\n\n## structure\n- there is no restrictions on how to structure a glint module\n- the good thing about small modules is, you don't need to care about structure, but size\n- try to split it up into different modules, when it becomes too big\n- a flat folder structure will do most of the time\n\n## common modules\nIf you can, it makes sense to depend on a few common modules instead of many different ones.\nThis list contains modules (dependencies) that are used in many of the modules:\n\n```javascript\n{\n \"clone\": \"^1.0.2\",\n \"debug\": \"^2.2.0\",\n \"defaults\": \"^1.0.2\",\n \"dot\": \"^1.0.3\",\n \"ejs\": \"^2.3.4\",\n \"is-browser\": \"^2.0.1\",\n \"page\": \"git://github.com/intesso/page.js.git\",\n \"utils-merge\": \"^1.0.0\"\n}\n```\n\n## style\n> style is a very personal thing\n- the glint modules use 2 spaces indent, and yes they use semicolons\n- if your module does it differently, that's fine\n- the style should be consistent within a module (check before submitting a pull request).\n\n# care and share\n> And don't forget to share your extensions!\n> Just name the modules starting with `glint-` and publish them on [npm](https://www.npmjs.com).\n\n\n",
"img-title": "Impressions",
"img-content": "<p> </p>\n\n<h1 style=\"text-align:center\">Edit: Content</h1>\n\n<p><img alt=\"\" src=\"/files/screenshots/edit-content.gif\" style=\"width:100%\" /></p>\n\n<p> </p>\n\n<h1 style=\"text-align:center\">Edit: Image Upload</h1>\n\n<p><img alt=\"\" src=\"/files/screenshots/edit-image-upload.gif\" style=\"width:100%\" /></p>\n\n<p> </p>\n\n<h1 style=\"text-align:center\">Develop: Add new Block Field</h1>\n\n<p><img alt=\"\" src=\"/files/screenshots/develop-new-block-field.gif\" style=\"width:100%\" /></p>\n\n<p> </p>\n\n<p> </p>\n\n<p> </p>\n",
"contact-title": "Contact",
"contact-content": "# API\n\nThe design of the module's `api` was chosen to get a good balance between \"easy to use\" and \"easy to extend\".\n\nThe `api` of the modules is designed after what we call the `associative-provider` model.\n\nYou wouldn't use a `TextBlock` directly, but via a `Block` that holds the `TextBlock`\n\t\n```javascript\n//e.g.: Block -> TextBlock\nvar block = Block(TextBlock()).use(Style());\n```\n\n\n# general\n\n## extendability\n\nHave a look at the [extend](EXTEND.md) documentation.\n\nThe following `api` document describes how to \"use\" the `building blocks`, (not how to extend them).\n\n\n## naming/require\nThe `building blocks` are called: `wrap, container, etc.` in this document. However, the module names to require them start always with `glint-`.\nAlso in general the module names are hierarchically structured, separated with a dash `-`, where on the left hand side is the more generic part of the name.\n\nSo if you want to use the `adapter` with the `ajax` provider for example, you do it like this:\n\n```javascript\nvar Adapter = require('glint-adapter');\nvar AjaxAdapter = require('glint-adapter-ajax');\n\nvar adapter = Adapter(AjaxAdapter());\n```\n\n\n## get/set\nGetter and Setter can be called like this:\n\n```javascript\n// set\nvar place = obj.place('server');\n\n// get\nconsole.log(obj.place());\n// --> server\n\n```\n\nWhen you provide a value (set), the method returns `this`, so that you can chain other methods.\n\n\n## chainable methods\nMost of the methods are chainable (they return this):\n\n```javascript\n// example:\nWrap(o)\n .editable(req.userCan('edit'))\n .i18n(req.i18n)\n .cid(req.params.article)\n .place(o.place)\n .load(res.locals, function(err, result) {\n debug('route loaded', err, req.params.article, result);\n if (err) return next(err);\n res.send(result.page);\n })\n```\n\n## events\n\nMost of the `building blocks ` inherit from `EventEmitter` and expose useful events:\n\n```javascript\n// Example from the code:\nvar EventEmitter = require('events').EventEmitter;\n\n/**\n * Expose Block element.\n */\nexports = module.exports = Block;\ninherits(Block, EventEmitter);\n```\n\nThe Events can be especially helpful, when designing a `plugin`.\n\n### get/set\n\nGetter and Setter emit an event:\n- `emit(name, value)`\n\n### methods\n\nThe building blocks methods emit events for every method with the given name:\n- `emit(pre-<methodName>, arguments)`\n- `emit(<methodName>, arguments)`\n- `emit(post-<methodName>, arguments)`\n\n\n## rendering/place\nrendering (load) is done by default on the server.\nediting, saving and deleting is always initiated in the browser.\nblocks and widgets can be defined to render in the browser when needed.\nhowever you can also override where the components (blocks and widgets) are rendered all together.\nyou can use this for example to let everything be rendered on the server,\nwhen the site is being called by a bot, search engine, crawler or the like.\n\n\n**place**\nglint is designed to use on the server as well as in the browser (pick you buzzword for it... universal, polymorph, what ever you like).\nWith the `place` get/set method, you can define, where you would like the control to be rendered.\n\nThese are the available options (strings):\n- server\n- browser \n- both\n- force:server\n- force:browser\n- force:both\n\n\n**priorities**\n\n (0:low priority ... 3:high priority)\n\n 0 render on server by default\n\n 1 Block.render('browser') or\n Widget.render('browser')\n -> render these items in the browser\n\n 2 Wrap.render('server') or\n Container.render('server')\n -> render ALL items on the server, e.g. when requested by a search engine.\n\n 3 SpecificBlock.render('force:both') or\n Widget.render('force:both)\n -> when a Specific Block has this flag, it will always be rendered on both sides (server and browser)\n\n 4 Same as priority 3 but with 'force:server' or 'force:client'\n -> render always on the server respectively in the browser\n\n\n# wrap\n\nA `wrap` can hold several `container`s and `widget`s as well as other `wrap`s.\nLet's call them `controls`. With the wrap, you can define how the `controls` are loaded.\nFirst you can define the default object with the method `defaults`.\nWith the methods `parallel`, `series` and `eventually`, you can define everything from a simple to a quite sophisticated loading execution.\nSee [flow-builder](https://github.com/intesso/flow-builder)\n\nThe `wrap` runs on the server and/or in the `browser` depending on the defined `place`s.\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nWrap.api === 'wrap'\n```\n\n### get/set\n\nYou can get/set these properties on the `wrap`.\n- key\n- id\n- selector\n- prepend\n- append\n- el\n- place\n- editable\n- cid\n\nWhen you set `editable` or `place` on the wrap, the value is also set on all of it`s controls.\n\n`cid` gets/sets the id on the first `container` that the `wrap` holds.\n\n\n## methods\n\n### constructor\n\n```javascript\n\n// the `wrap` has got the optional key, control arguments. \n// what's added in the constructor get's added with the `parallel` workflow.\nvar wrap = Wrap(key, control);\n\n// but you can also create the Wrap fist, and then define your workflow.\n// in this example the articles and projects `load in parallel` and after they are done,\n// the resulting transfer object is handled over to the next steps:\n// 1. in this exampe it's first the contentWidget,\n// 2. and then the layoutWrap after the previous step is done.\nvar wrap = Wrap();\nwrap\n .parallel(container)\n .parallel('articles', articles.selector('.js-articles'))\n .parallel('projects', projects.selector('.js-projects'))\n .series('content', contentWidget.place('force:server'))\n .series(LayoutWrap(o.layout).place('force:server'))\n```\n\n### defaults\n\nIt let's you define a default object, that's the starting object in every `load` workflow.\nThis object is the *initial workflow transfer object*\n\n```javascript\n// set single key, value\nwrap.defaults(key, value);\n// set object\nwrap.defaults(object);\n// get value\nwrap.defaults(key);\n```\n\n### parallel\nWhen you define several `controls` with the `parallel` method right after each other, they get executed in parallel, and only when all of them have finished (or one of them has an error), the next step is executed.\n\n```javascript\n// adds a single control, the clone of the resulting object merged with the transfer object.\nwrap.parallel(control;\n// adds a sincle control, the clone of the resulting object is insterted into the transfer object with the given `key`.\nwrap.parallel(key, control);\n\n// examples\nwrap.parallel(container);\nwrap.parallel('news', widget1);\nwrap.parallel('articles', widget2);\n```\n\n### series\n`series` method calls, are executed after the previous method has finished.\nIt has got the same signature as the `parallel` method.\n\n### eventually\n`eventually` method calls are started immediately, but are evaluated only at the very end when the whole workflow has finished.\nIt has got the same signature as the `parallel` method.\n\n### load\nCalling the `load` method, starts the defined wrap workflow.\n\n\n```javascript\n// it has got an optional context object. This object is taken as the *initial workflow transfer object* when provided.\n// the callback function `callback(err, result)` is called once everything is `load`ed.\n\nwrap.load([context, ] callback);\n// or\nwrap.load(callback);\n\n\n// Example:\nfunction(req, res, next) {\n wrap.load(res.locals, function(err, result) {\n if (err) return next(err);\n res.send(result.page);\n });\n}\n```\n\n\n\n# widget\nWith a widget, you can render/display noneditable content on the server and/or in the browser depending on the defined `place`.\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nWidget.api === 'widget'\n```\n\n### get/set\n\nYou can get/set these properties on the `widget`.\n- key\n- id\n- selector\n- prepend\n- append\n- el\n- place\n- template\n- data\n- render\n\nWhen you set `editable` or `place` on the wrap, the value is also set on all of it`s controls.\n\n`cid` gets/sets the id on the first `container` that the `wrap` holds.\n\n\n## methods\n\n### constructor\n\n```javascript\n// you can provide the `render` method in the constructor\nvar widget = Widget(renderFunction);\n\n// or you can provide the `data` and `render` method on the widget instance. Example:\nWidget()\n .data(function(fn) {\n adapter.findLatest(o.getLocale(), 3, fn);\n })\n .render(function(options) {\n return ejs.render(o.template || template, options);\n })\n```\n\n### data\nYou can optionally provide a `data` method, if your widget need's to make asynchronous data calls.\nIt returns `this` and takes a callback function with the parameters: `callback(err, result)`.\n\n\n```javascript\nwidget.data(callback);\n```\n\n### render\nThe `render` function is a synchronous function and must return the rendered content.\nThe data object is provided in the first argument.\nIt let's you choose what ever rendering engine you want to use (as long as it runs on the server as well as in the browser).\n\n```javascript\nwrap..render(function(options) {\n return compiledDotTemplate(options);\n})\n\n```\n\n\n### load\nThe `load` method is called from the `wrap` that contains this widget during the `load` workflow execution.\nMost probably, you never have to call this method directly.\nInternally, the `load` method calls the `data` method (if it was provided), and then `render` with the resulting object.\n\n\n\n# container\nContainers are only used when you use `blocks`.\nA container runs on the server and in the browser. On the server, only the `load` method is called (most likely from the surrounding `wrap`),\nIn the browser, there is more methods:\n- load\n- edit\n- save\n- cancel\n- delete\n\n\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nContainer.api === 'container'\n```\n\n### get/set\n\nYou can get/set these properties on the `container`.\n- key\n- id\n- place\n- template\n- editable\n- blocks\n- adapter\n\n\n## methods\n\n### constructor\n\n\n```javascript\n// you can optionally provide the `blocks` as well as the `adapter` in the constructor\n\nvar blocks = {\n title: text().selector('body h1'),\n short: text().selector('[data-id=short]'),\n text: editor().selector('[data-id=text]'),\n meta: Block(MetaBlock())\n};\n\nvar adapter = Adapter(AjaxAdapter())\n .db(db)\n .type(type)\n .use(Dates())\n .use(Id())\n\n// constructor\nvar container = Container(blocks, adapter);\n\n\n// or you can provide them afterwards. Example:\nvar container = Container();\ncontainer\n .blocks(blocks)\n .adapter(adapter)\n```\n\n\n### load\n(it runs either on server or browser depending on the `place`)\n\n> Internal sequence:\n\n1. it first calls the `adapter`s `load` method,\n2. afterwards all of the `block`s `load` methods\n\n\n### edit\n(runs only in the browser)\n\n> Internal sequence:\n\n1. it first calls the `load` method on this container\n2. it then calls the `edit` method on all of the `block`s.\n\n\n### save\n(runs only in the browser)\n\n> Internal sequence:\n\n1. first it calls all of the `block`s `save` methods\n2. it then calls the `adapter`s `save` method,\n3. aaand finally it calls the `load` method on this container to finish the command.\n\n\n\n### cancel\n(runs only in the browser)\n\n> Internal sequence:\n\n1. it basically just calls the `load` on this container.\n\n\n### delete\n(runs only in the browser)\n\n> Internal sequence:\n\n1. it first calls the `adapter`s `delete` method,\n2. and afterwards it calls the `load` on this container, to finish things up.\n\n\n\n# block\n\nThe `blocks` are the heart of everything that is editable in *GlintCMS*.\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nBlock.api === 'block'\n```\n\n### get/set\n\nYou can get/set these properties on the `block`.\n- id\n- selector\n- el\n- place\n\n\n## methods\n\n\n### constructor/methods\n\n```javascript\n// you normally instantiate the `block` with the specific `block-provider` that it should hold\nvar block = Block(blockProvider);\n\n// Example:\nvar block = Block(TextBlock()).use(Style());\n\n// however you can also add/remove the `block-provider` later with `delegate` and `undelegate`\nvar block = Block();\nblock.delegate(TextBlock());\n\n// you can also undelegate a block\nblock.undelegate(textBlock);\n```\n\nThe `block` basically delegates the method calls to the specific `block-provider`.\nDue to a runtime behaviour (missing `el` \"HTMLElement\"), the `block` has the ability to buffer method calls in a FIFO, and execute them later.\n\nIn addition to the 'getters and setters', it buffers and forwards the following methods:\n- load\n- edit\n- save\n- cancel\n- hasChanged\n- isValid\n\n### plugins\n\nYou can extend `block`s with plugins with the `use` method, as well as with the `mixin method`.\n\n#### use\n\nConsult the [extend] documentation or the code.\n\n#### mixin\n\nConsult the [extend] documentation or the code.\n\n\n```javascript\n// Example:\nvar block.use(Style());\n\n```\n\n\n# adapter\n\nThe `adapter` is the interface to the storage.\n\n\n## properties\n\n### api\nthe `api` property must not be overwritten.\n\n```javascript\nAdapter.api === 'adapter'\n```\n\n### get/set\n\nYou can get/set these properties on the `adapter`.\n- db\n- type\n- fn\n\n\n\n## methods\n\n\n### constructor/methods\n\n```javascript\n// you normally instantiate the `adapter` with the specific `adapter-provider` that it should delegate it's calls to.\nvar adapter = Adapter(adapter);\n\n// Example:\nvar adapter = Adapter(AjaxAdapter());\n\n// however you can also add/remove the `adapter-provider` later with `delegate` and `undelegate`\nvar adapter = Adapter();\nadapter.delegate(AjaxAdapter());\n\n// you can also undelegate a block\nadapter.undelegate(ajaxAdapter);\n```\n\nThe `adapter` basically delegates the method calls to the specific `adapter-provider`.\n- find(query, callback)\n- load(id, callback)\n- save(id, content, callback)\n- delete(id, callback)\n\nThe function has the form: `callback(err, result)`\n\nthe `result` object is the parsed javascript object for the given `id`,\nand an array with the matching objects on the `find` callback.\n\n### plugins\n\nYou can extend `adapter`s with plugins with the `use` method, as well as with the `mixin method`.\n\n#### use\n\nConsult the [extend] documentation or the code.\n\n#### mixin\n\nthe `mixin` is mainly used to extend the adapter's query capability.\nSince the `adapter` does not \"magically unify the different storage query language\", but exposes it directly,\nthe `adapter` needs a way to handle the different provider's queries.\n\nIt does it with the mixin:\n\n```javascript\nvar mixin = {\n fs: {\n findWithLocale: function(locale, fn) {\n var query = 'this.id.indexOf(\"__template__\") === -1 && this.locale === \"' + locale + '\"';\n this.find({$where: query}, fn);\n }\n },\n elasticsearch : {\n findWithLocale: function(locale, fn) {\n // pseudocode\n this.find(elasticSearchSpecificQuery, fn)\n }\n }\n};\n\nadapter.mixin(mixin);\n```\n\nAs you can see in the example, the mixin must have an object, with the `adapter-provider` name as the key,\nand the functions to `mixin` as the value (nested object).\n\nThis way you can support more than just one adapter-plugin,\nand if you use some one else's module that does not have the queries for your provider,\njust add them yourself and send a pull request.\n\n\n```javascript\n// Example:\nvar block.use(Style());\n\n```\n\n\n# trigger\n\nA `trigger` consumes the `container`s api methods and exposes them to the user in a usable form.\nTherefore `trigger`s are only useful in the browser, not on the server side.\nAlthough theoretically, you could write a trigger to use on the server side as well, maybe for application integration.\n\n```javascript\n// usage example with the trigger implementation: keyboard and sidenav.\n\nvar keyboard = require('glint-trigger-keyboard');\nvar sidenav = require('glint-trigger-sidenav');\n\nwrap.containers.forEach(function(container) {\n keyboard().add(container);\n sidenav().add(container);\n});\n```\n\nThe trigger itself ('glint-trigger') is only a `base class`, the trigger implementors can inherit:\n\n```javascript\n// Snipp