diff --git a/README.md b/README.md
index 4af247e..a2436ba 100644
--- a/README.md
+++ b/README.md
@@ -111,6 +111,30 @@ Here are the names of the defaults:
}
```
+## Extending and Creating Elements
+
+You can extend current elements or create new ones.
+
+```js
+var Inky = require('inky').Inky;
+var format = require('util').format;
+
+Inky.prototype.componentLibrary.box = function (element) {
+ var classes = ['container'];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+
+ return format('
', classes.join(' '), element.html());
+};
+
+var inky = new Inky({
+ components: {
+ box: 'box'
+ }
+});
+```
+
## Programmatic Use
The Inky parser can be accessed directly for programmatic use. It takes in a [Cheerio](https://github.com/cheeriojs/cheerio) object of HTML, and gives you back a converted Cheerio object.
diff --git a/lib/componentFactory.js b/lib/componentFactory.js
index 0361e4d..2804f80 100644
--- a/lib/componentFactory.js
+++ b/lib/componentFactory.js
@@ -1,136 +1,28 @@
var format = require('util').format;
var $ = require('cheerio');
+var getKeyByValue = function(obj, val) {
+ for (var key in obj) {
+ if (obj[key] === val) {
+ return key;
+ }
+ }
+ return false;
+};
+
/**
* Returns output for desired custom element
* @param {object} element - Element as a Cheerio object.
* @returns {string} HTML converted from a custom element to table syntax.
*/
module.exports = function(element) {
- var inner = element.html();
-
- switch (element[0].name) {
- //
- case this.components.columns:
- return this.makeColumn(element, 'columns');
-
- //
- case this.components.row:
- var classes = ['row'];
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
-
- return format('', classes.join(' '), inner);
-
- //
- case this.components.button:
- var expander = '';
-
- // If we have the href attribute we can create an anchor for the inner of the button;
- if (element.attr('href')) {
- inner = format('%s ', element.attr('href'), inner);
- }
-
- // If the button is expanded, it needs a tag around the content
- if (element.hasClass('expand')) {
- inner = format('%s ', inner);
- expander = '\n ';
- }
-
- // The .button class is always there, along with any others on the element
- var classes = ['button'];
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
-
- return format('', classes.join(' '), inner, expander);
-
- //
- case this.components.container:
- var classes = ['container'];
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
-
- return format('', classes.join(' '), inner);
-
- //
- case this.components.inky:
- return ' ';
-
- //
- case this.components.blockGrid:
- var classes = ['block-grid', 'up-'+element.attr('up')];
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
- return format('', classes.join(' '), inner);
-
- //
- case this.components.menu:
- var classes = ['menu'];
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
- var centerAttr = element.attr('align') ? 'align="center"' : '';
- return format('', classes.join(' '), centerAttr, inner);
-
- // -
- case this.components.menuItem:
- var classes = ['menu-item'];
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
- return format('
%s ', classes.join(' '), element.attr('href'), inner);
-
- //
- case this.components.center:
- if (element.children().length > 0) {
- element.children().each(function() {
- $(this).attr('align', 'center');
- $(this).addClass('float-center');
- });
- element.find('item, .menu-item').addClass('float-center');
- }
-
- element.attr('data-parsed', '');
-
- return format('%s', $.html(element));
-
- //
- case this.components.callout:
- var classes = ['callout-inner'];
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
-
- return format('', classes.join(' '), inner);
-
- //
- case this.components.spacer:
- var classes = ['spacer'];
- var size = 16;
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
- if (element.attr('size')) {
- size = (element.attr('size'));
- }
-
- return format('', classes.join(' '), inner);
-
- //
- case this.components.wrapper:
- var classes = ['wrapper'];
- if (element.attr('class')) {
- classes = classes.concat(element.attr('class').split(' '));
- }
-
- return format('', classes.join(' '), inner);
-
- default:
- // If it's not a custom component, return it as-is
- return format('%s ', $.html(element));
+ var tag = element[0].name;
+ var componentKey = getKeyByValue(this.components, tag);
+
+ if (componentKey && this.componentTags.indexOf(tag) > -1 && typeof this.componentLibrary[componentKey] === 'function') {
+ return this.componentLibrary[componentKey].call(this, element);
+ } else {
+ // If it's not a custom component, return it as-is
+ return format('%s ', $.html(element));
}
}
diff --git a/lib/componentLibrary.js b/lib/componentLibrary.js
new file mode 100644
index 0000000..2caa057
--- /dev/null
+++ b/lib/componentLibrary.js
@@ -0,0 +1,141 @@
+var format = require('util').format;
+var $ = require('cheerio');
+
+/**
+ * Returns output for desired custom element
+ * @param {object} element - Element as a Cheerio object.
+ * @returns {string} HTML converted from a custom element to table syntax.
+ */
+module.exports = {
+ //
+ columns: function (element) {
+ return this.makeColumn(element, 'columns');
+ },
+
+ //
+ row: function (element) {
+ var classes = ['row'];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+
+ return format('', classes.join(' '), element.html());
+ },
+
+ //
+ button: function (element) {
+ var expander = '';
+ var inner = element.html();
+
+ // If we have the href attribute we can create an anchor for the inner of the button;
+ if (element.attr('href')) {
+ inner = format('%s ', element.attr('href'), inner);
+ }
+
+ // If the button is expanded, it needs a tag around the content
+ if (element.hasClass('expand') || element.hasClass('expanded')) {
+ inner = format('%s ', inner);
+ expander = '\n ';
+ }
+
+ // The .button class is always there, along with any others on the element
+ var classes = ['button'];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+
+ return format('', classes.join(' '), inner, expander);
+ },
+
+ //
+ container: function (element) {
+ var classes = ['container'];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+
+ return format('', classes.join(' '), element.html());
+ },
+
+ //
+ inky: function (element) {
+ return ' ';
+ },
+
+ //
+ blockGrid: function (element) {
+ var classes = ['block-grid', 'up-'+element.attr('up')];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+ return format('', classes.join(' '), element.html());
+ },
+
+ //
+ menu: function (element) {
+ var classes = ['menu'];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+ var centerAttr = element.attr('align') ? 'align="center"' : '';
+ return format('', classes.join(' '), centerAttr, element.html());
+ },
+
+ // -
+ menuItem: function (element) {
+ var classes = ['menu-item'];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+ return format('
%s ', classes.join(' '), element.attr('href'), element.html());
+ },
+
+ //
+ center: function (element) {
+ if (element.children().length > 0) {
+ element.children().each(function() {
+ $(this).attr('align', 'center');
+ $(this).addClass('float-center');
+ });
+ element.find('item, .menu-item').addClass('float-center');
+ }
+
+ element.attr('data-parsed', '');
+
+ return format('%s', $.html(element));
+ },
+
+ //
+ callout: function (element) {
+ var classes = ['callout-inner'];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+
+ return format('', classes.join(' '), element.html());
+ },
+
+ //
+ spacer: function (element) {
+ var classes = ['spacer'];
+ var size = 16;
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+ if (element.attr('size')) {
+ size = (element.attr('size'));
+ }
+
+ return format('', classes.join(' '), element.html());
+ },
+
+ //
+ wrapper: function (element) {
+ var classes = ['wrapper'];
+ if (element.attr('class')) {
+ classes = classes.concat(element.attr('class').split(' '));
+ }
+
+ return format('', classes.join(' '), element.html());
+ }
+};
\ No newline at end of file
diff --git a/lib/inky.js b/lib/inky.js
index 510177a..be3b2c9 100644
--- a/lib/inky.js
+++ b/lib/inky.js
@@ -61,4 +61,6 @@ Inky.prototype.releaseTheKraken = function($) {
Inky.prototype.componentFactory = require('./componentFactory');
+Inky.prototype.componentLibrary = require('./componentLibrary');
+
Inky.prototype.makeColumn = require('./makeColumn');
diff --git a/test/components.js b/test/components.js
index 1e3af90..8b7614b 100644
--- a/test/components.js
+++ b/test/components.js
@@ -1,7 +1,7 @@
var compare = require('./lib/compare');
describe('Center', () => {
- it('applies a text-center class and center alignment attribute to the first child', () => {
+ it('applies a float-center class and center alignment attribute to the first child', () => {
var input = `