diff --git a/static/js/correlationsDialog.cms.js b/static/js/correlationsDialog.cms.js
new file mode 100644
index 0000000..5c3bb2d
--- /dev/null
+++ b/static/js/correlationsDialog.cms.js
@@ -0,0 +1,243 @@
+pandora.ui.correlationsDialog = function() {
+
+ function getData(callback) {
+ let categories = {}
+ let keywords = {}
+ let segments = {}
+ pandora.api.find({
+ query: {conditions: [
+ {key: 'id', operator: '!=', value: 'BA'} // "Blue"
+ ], operator: ''}
+ }, function(result) {
+ let length = result.data.items
+ let count = 0
+ pandora.api.find({
+ keys: ['id'],
+ query: {conditions: [], operator: ''},
+ range: [0, 1000000],
+ sort: [{key: 'id', operator: '+'}]
+ }, function(result) {
+ result.data.items.forEach(function(item) {
+ pandora.api.get({
+ id: item.id,
+ keys: ['layers']
+ }, function(result) {
+ result.data.layers.keywords.forEach(function(keyword) {
+ let parts = keyword.value.split(': ')
+ if (parts.length != 2) {
+ return
+ }
+ let catKey = parts[0]
+ categories[catKey] = categories[catKey] || []
+ if (!categories[catKey].includes(keyword.value)) {
+ categories[catKey].push(keyword.value)
+ }
+ let segKey = item.id + '/' + keyword['in'] + '-' + keyword.out
+ segments[segKey] = segments[segKey] || []
+ segments[segKey].push(keyword.value)
+ })
+ if (++count == length) {
+ Object.keys(segments).forEach(function(segKey) {
+ segments[segKey].forEach(function(value1) {
+ keywords[value1] = keywords[value1] || {
+ count: 0,
+ keywords: {}
+ }
+ keywords[value1].count++
+ segments[segKey].forEach(function(value2) {
+ if (value1 != value2) {
+ keywords[value1].keywords[value2] = keywords[value1].keywords[value2] || 0
+ keywords[value1].keywords[value2]++
+ }
+ })
+ })
+ })
+ callback({
+ categories: categories,
+ keywords: keywords,
+ segments: segments
+ })
+ }
+ })
+ })
+ })
+ })
+ }
+
+ function getItems(categories, keywords, mainCat, relatedCat) {
+ return categories[mainCat].map(function(keyword) {
+ let max = 0
+ let values = []
+ Object.keys(keywords[keyword].keywords).filter(function(key) {
+ return key.startsWith(relatedCat + ': ')
+ }).forEach(function(key) {
+ if (keywords[keyword].keywords[key] > max) {
+ max = keywords[keyword].keywords[key]
+ values = [key]
+ } else if (keywords[keyword].keywords[key] == max) {
+ values.push(key)
+ }
+ })
+ return {
+ mainCount: keywords[keyword].count,
+ mainKeyword: keyword,
+ relatedCount: max,
+ relatedKeyword: values.join('; ')
+ }
+ })
+ }
+
+ let $loadingScreen = Ox.LoadingScreen()
+ let $dialog = Ox.Dialog({
+ buttons: [
+ Ox.Button({
+ title: Ox._('Close'),
+ width: 64
+ }).bindEvent({
+ click: function() {
+ $dialog.close()
+ }
+ })
+ ],
+ closeButton: true,
+ content: $loadingScreen,
+ height: window.innerHeight * 0.9 - 48,
+ title: Ox._('Correlations'),
+ width: 872
+ }).bindEvent({
+ open: function() {
+ $loadingScreen.start()
+ getData(function(data) {
+ console.log(data)
+ let categories = Object.keys(data.categories).sort()
+ let mainCat = 'lived space'
+ let relatedCat = 'architectural element'
+ let $menuBar = Ox.Bar({size: 24})
+ let $mainSelect = Ox.Select({
+ items: Object.keys(data.categories).sort().map(function(value) {
+ return {
+ id: value,
+ title: 'main: ' + value
+ }
+ }),
+ value: mainCat,
+ width: 320
+ }).css({
+ left: '4px',
+ position: 'absolute',
+ top: '4px'
+ }).bindEvent({
+ change: onChange
+ }).appendTo($menuBar)
+ let $relatedSelect = Ox.Select({
+ items: Object.keys(data.categories).sort().map(function(value) {
+ return {
+ id: value,
+ title: 'related: ' + value
+ }
+ }),
+ value: relatedCat,
+ width: 320
+ }).css({
+ left: '336px',
+ position: 'absolute',
+ top: '4px'
+ }).bindEvent({
+ change: onChange
+ }).appendTo($menuBar)
+ function onChange() {
+ mainCat = $mainSelect.value()
+ relatedCat = $relatedSelect.value()
+ listItems = getItems(data.categories, data.keywords, mainCat, relatedCat)
+ $list.options({items: listItems})
+ }
+ let $list = Ox.TableList({
+ columns: [
+ {
+ align: 'right',
+ format: Ox.formatNumber,
+ id: 'mainCount',
+ operator: '-',
+ title: Ox._('Count'),
+ visible: true,
+ width: 48
+ },
+ {
+ format: function(value) {
+ return '' + value + ''
+ },
+ id: 'mainKeyword',
+ operator: '+',
+ title: Ox._('Main Keyword'),
+ unique: true,
+ visible: true,
+ width: 256
+ },
+ {
+ align: 'right',
+ format: Ox.formatNumber,
+ id: 'relatedCount',
+ operator: '-',
+ title: Ox._('Count'),
+ visible: true,
+ width: 48
+ },
+ {
+ format: function(value, data) {
+ return value.split('; ').map(function(value) {
+ return '' + value + ''
+ }).join('; ')
+ },
+ id: 'relatedKeyword',
+ operator: '+',
+ title: Ox._('Related Keyword'),
+ visible: true,
+ width: 512
+ }
+ ],
+ columnsMovable: true,
+ columnsResizable: true,
+ columnsVisible: true,
+ items: [],
+ scrollbarVisible: true,
+ sort: [{key: 'mainCount', operator: '-'}]
+ }).bindEvent({
+ init: function(data) {
+ $status.html(Ox.formatNumber(data.items) + ' ' + Ox._('keywords'))
+ }
+ })
+ let listItems = []
+ onChange()
+ let $panel = Ox.SplitPanel({
+ elements: [
+ {element: $menuBar, size: 24},
+ {element: $list}
+ ],
+ orientation: 'vertical'
+ })
+ $loadingScreen.stop()
+ $dialog.options({
+ content: $panel
+ })
+ })
+
+ }
+ })
+ let $status = Ox.Element().css({
+ fontSize: '9px',
+ height: '10px',
+ marginLeft: '96px',
+ position: 'absolute',
+ textAlign: 'center',
+ top: '6px',
+ width: '680px'
+ }).appendTo($dialog.find('.OxButtonsbar'))
+
+ return $dialog
+
+}