Rift.IO OSM R1 Initial Submission
[osm/UI.git] / skyquake / framework / widgets / listy / listy.js
diff --git a/skyquake/framework/widgets/listy/listy.js b/skyquake/framework/widgets/listy/listy.js
new file mode 100644 (file)
index 0000000..ac0e58a
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 
+ *   Copyright 2016 RIFT.IO Inc
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+import React from 'react';
+import _ from 'lodash';
+
+/**
+ *
+ *
+ */
+export default class Listy extends React.Component {
+       constructor(props) {
+               super(props);
+       }
+
+       /**
+
+        */
+       createList(data, iter=0) {
+               var groupTag = this.props.groupTag.tag;
+               var groupClass = this.props.groupTag.className;
+               var itemTag = this.props.itemTag.tag;
+               var itemClass = this.props.itemTag.className;
+               var listHeaderTag = this.props.listHeaderTag.tag;
+               var listHeaderClass = this.props.listHeaderTag.className;
+
+               var listNode = null;
+               var self = this;
+               if (_.isArrayLike(data) && _.isObjectLike(data)) {
+                       var children = [];
+                       data.forEach(function(element, index, array) {
+                               if ( _.isArrayLike(element) || _.isObjectLike(element)) {
+                                       children.push(self.createList(element, iter+1));
+                               } else {
+                                       children.push(React.createElement(itemTag, {
+                                               key: index,
+                                               className: itemClass
+                                       }, element));
+                               }
+                       });
+
+                       listNode = React.createElement(groupTag, {
+                               key: iter,
+                               className: groupClass }, children);
+               }
+               else if (_.isObjectLike(data)) {
+                       var children = [];
+                       for (var key in data) {
+                               if ( _.isArrayLike(data[key]) || _.isObjectLike(data[key])) {
+                                       children.push(
+                                               React.createElement(listHeaderTag, {
+                                                       key: key + '_header',
+                                                       className: listHeaderClass }, key + ":")
+                                       );
+                                       children.push(
+                                               React.createElement(groupTag, {
+                                                       key: key + '_list',
+                                                       className: groupClass },
+                                                       [this.createList(data[key], iter + 1)])
+                                       );
+
+                               } else {
+                                       // TODO: Add span to line-wrap the data part (hanging)
+                                       children.push(React.createElement(itemTag, {
+                                               key: key,
+                                               className: itemClass},
+                                               key + ": " + data[key]));
+                               }
+                       }
+                       listNode = React.createElement(groupTag, {
+                               key: iter,
+                               className: groupClass }, children);
+               } else {
+                       listNode = React.createElement(itemTag, {
+                               className: itemClass}, data);
+               }
+
+               return listNode;
+       }
+
+       noDataMessage() {
+               return React.createElement("div", {
+                       className: this.props.noDataMessageClass},
+                       this.props.noDataMessage);
+       }
+
+       render () {
+               var data = this.props.data;
+
+               return React.createElement("div", {
+                       className: "listy" },
+                       _.isEmpty(data) ? 
+                       this.noDataMessage() : 
+                       this.createList(data)
+               )
+       }
+}
+
+Listy.validateTagDefinition = function(props, propName, componentName) {
+       let obj = props[propName];
+       let fullAttr = componentName + "." + propName;
+
+       if (!obj)
+               return new Error('Validation failed. "%" is undefined', fullAttr);
+       if (!obj.hasOwnProperty("tag") || _.isEmpty(obj.tag))
+               return new Error('Validation failed. "%s" missing attribute "tag"', fullAttr);
+       if (!obj.hasOwnProperty("className") || obj.className == undefined)
+               return new Error('Validation failed. "%s" missing attribute "className"', fullAttr);
+}
+
+Listy.propTypes = {
+       data: React.PropTypes.object,
+       groupTag: Listy.validateTagDefinition,
+       itemTag: Listy.validateTagDefinition,
+       listHeaderTag: Listy.validateTagDefinition,     
+       debugMode: React.PropTypes.bool
+}
+
+Listy.defaultProps = {
+       data: {},
+
+       // Visual Rules
+       groupTag: {
+               tag: "ul",
+               className: "listyGroup"
+       },
+       itemTag: {
+               tag: "li",
+               className: "listyItem"
+       },
+       listHeaderTag: {
+               tag: "h2",
+               className: "listyGroupHeader"
+       },
+       noDataMessage: "No data",
+       noDataMessageClass: "listyNoDataMessage",
+       debugMode: false
+}