1/*
2 * Author: Heidi Pan <heidi.pan@intel.com>
3 * Copyright (c) 2015 Intel Corporation.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26// extract the field from the class description text
27function getField(classDescription, field) {
28  var pattern = new RegExp('\\+ __' + field + ':__ [A-Za-z0-9]*');
29  var label = new RegExp('\\+ __' + field + ':__');
30  if (classDescription) {
31    var matched = classDescription.match(pattern);
32    if (matched) {
33      return (matched[0].replace(label, '')).trim();
34    }
35  }
36  return 'other';
37}
38
39
40// generate html to group modules by the given field (e.g. category/connection type) of its children classes
41function listByGroup(modules, classes, field, projectRoot) {
42
43  var moduleClasses = {};
44  var modulesByGroup = {};
45  var i, j;
46  for (i = 0; i < modules.length; i++) {
47    moduleClasses[modules[i].name] = [];
48  }
49  for (i = 0; i < classes.length; i++) {
50    moduleClasses[classes[i].module].push(i);
51  }
52  for (var module in moduleClasses) {
53    var classIndices = moduleClasses[module];
54    var groups = [];
55    for (i = 0; i < classIndices.length; i++) {
56      groups.push(getField(classes[classIndices[i]].description, field));
57    }
58    if (groups.length != 0) {
59      var group = groups[0];
60      var sanitychecked = true;
61      for (i = 1; i < groups.length; i++) {
62        if (groups[i] != group) {
63          sanitychecked = false;
64          break;
65        }
66      }
67      if (!sanitychecked) {
68        // TODO
69      }
70      if (group in modulesByGroup) {
71        modulesByGroup[group].push(module);
72      } else {
73        modulesByGroup[group] = [module];
74      }
75    }
76  }
77  var groups = Object.keys(modulesByGroup).sort();
78  var html = '';
79  var pfx = projectRoot + 'modules/';
80  for (i = 0; i < groups.length; i++) {
81    var group = groups[i];
82    html += '<div class="upmGroup"><div class="right-arrow"></div>' + group + '</div><span class="upmModules" style="display:none">';
83    var moduleNames = modulesByGroup[group];
84    for (j = 0; j < moduleNames.length; j++) {
85      var moduleName = moduleNames[j];
86      html += '<a href="' + pfx + moduleName + '.html">' + moduleName + '</a>';
87    }
88    html += '</span>';
89  }
90  return html;
91}
92
93
94// click handler to change direction of arrow and toggle visibility of grouped modules
95var onClickHandler = "Y.on('domready', function() {       \
96  Y.on('click', function(e) {                             \
97    var classes = this.next('.upmModules').toggleView();  \
98    if (classes.getStyle('display') == 'none') {          \
99      this.one('> div').removeClass('down-arrow').addClass('right-arrow'); \
100    } else {                                              \
101      this.one('> div').removeClass('right-arrow').addClass('down-arrow'); \
102    }                                                     \
103  }, '.upmGroup');                                        \
104});";
105
106
107// css to generate triangle icons
108var insertStyles = "Y.one(document.head).append('<style> \
109  div.right-arrow {                                      \
110    width: 0;                                            \
111    height: 0;                                           \
112    border-bottom: 5px solid transparent;                \
113    border-top: 5px solid transparent;                   \
114    border-left: 5px solid #356de4;                      \
115    font-size: 0;                                        \
116    margin-right: 5px;                                   \
117    vertical-align: 5px;                                 \
118    float: left;                                         \
119  }                                                      \
120  div.down-arrow {                                       \
121    width: 0;                                            \
122    height: 0;                                           \
123    border-left: 5px solid transparent;                  \
124    border-right: 5px solid transparent;                 \
125    border-top: 5px solid #356de4;                       \
126    font-size: 0;                                        \
127    margin-right: 5px;                                   \
128    float: left;                                         \
129  }                                                      \
130  div.upmGroup {                                         \
131    font-weight: bold;                                   \
132  }                                                      \
133</style>');";
134
135
136var scripts = "YUI().use('node', 'event', function (Y) {"
137  + onClickHandler
138//  + insertStyles
139  + "});";
140
141
142module.exports = {
143
144  listByCategory: function() {
145    return listByGroup(this.modules, this.classes, 'Category', this.projectRoot);
146  },
147
148  listByManufacturer: function() {
149    return listByGroup(this.modules, this.classes, 'Manufacturer', this.projectRoot);
150  },
151
152  listByConnection: function() {
153    return listByGroup(this.modules, this.classes, 'Connection', this.projectRoot);
154  },
155
156  javascripts: function(options) {
157    return '<script type="text/javascript">' + scripts + '</script>';
158  },
159
160  // generate custom cross links
161  // assume lowercase script will be run, so generate class links with lower case
162  customCrossLinks: function() {
163    var selector = 'script[type="class-metadata"]'
164    var html = "<script type='text/javascript'>                                    \
165      var find = function(ar, elem) {                                              \
166        for (var i = 0; i < ar.length; i++) {                                      \
167          if (ar[i] == elem) {                                                     \
168            return true;                                                           \
169          }                                                                        \
170        }                                                                          \
171        return false;                                                              \
172      };                                                                           \
173      YUI().use('node', 'event', function (Y) {                                    \
174        Y.on('domready', function() {                                              \
175          var classes = Y.all('" + selector  + "').getHTML();                      \
176          for (var i = 0; i < classes.length; i++) {                               \
177            classes[i] = classes[i].toLowerCase();                                 \
178          }                                                                        \
179          Y.all('span.type').each(function(node) {                                 \
180            var t = node.getHTML();                                                \
181            if (find(classes, t.toLowerCase())) {                                  \
182              node.setHTML('<a href=' + t.toLowerCase() + '.html>' + t + '</a>');  \
183            }                                                                      \
184          });                                                                      \
185        });                                                                        \
186      });                                                                          \
187    </script>";
188    for (var i = 0; i < this.classes.length; i++) {
189      html += "<script type='class-metadata'>" + this.classes[i].name + "</script>";
190    }
191    return html;
192  }
193
194};