jh-componentj 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +61 -0
  3. package/dist/tvjs-xp.js +2375 -0
  4. package/dist/tvjs-xp.min.js +5 -0
  5. package/dist/tvjs-xp.min.js.LICENSE.txt +6 -0
  6. package/package.json +69 -0
  7. package/src/Main.vue +170 -0
  8. package/src/apps/App1.vue +71 -0
  9. package/src/apps/App2.vue +155 -0
  10. package/src/components/AppTag.vue +48 -0
  11. package/src/components/Chartbox.vue +87 -0
  12. package/src/components/Codepane.vue +260 -0
  13. package/src/components/Multiselect.vue +106 -0
  14. package/src/components/MyVueComponent.vue +26 -0
  15. package/src/components/StdInput.vue +70 -0
  16. package/src/components/Window.vue +95 -0
  17. package/src/components/dragg.js +32 -0
  18. package/src/extensions/chart-link/main.js +299 -0
  19. package/src/extensions/chart-link/shared.js +10 -0
  20. package/src/extensions/chart-link/utils.js +17 -0
  21. package/src/extensions/chart-link/x.json +11 -0
  22. package/src/extensions/grid-resize/Splitter.vue +80 -0
  23. package/src/extensions/grid-resize/main.js +152 -0
  24. package/src/extensions/grid-resize/utils.js +25 -0
  25. package/src/extensions/grid-resize/x.json +11 -0
  26. package/src/extensions/legend-buttons/AddWin.vue +91 -0
  27. package/src/extensions/legend-buttons/main.js +156 -0
  28. package/src/extensions/legend-buttons/x.json +11 -0
  29. package/src/extensions/settings-win/SettingsWin.vue +76 -0
  30. package/src/extensions/settings-win/main.js +39 -0
  31. package/src/extensions/settings-win/utils.js +19 -0
  32. package/src/extensions/settings-win/x.json +11 -0
  33. package/src/index.html +19 -0
  34. package/src/index_dev.js +27 -0
  35. package/src/index_prod.js +28 -0
  36. package/src/main.js +14 -0
  37. package/src/stuff/utils.js +16 -0
@@ -0,0 +1,299 @@
1
+
2
+ /* Example:
3
+
4
+ rules: {
5
+ '* -> *': {}, // From each to each
6
+ '*': { // The same as ^
7
+ cursor: true, // bool, 'X', 'Y', 'XY'
8
+ position: 'X', // bool, 'X', 'Y', 'XY'
9
+ tools: true
10
+ },
11
+ 'trading-vue-1 -> trading-vue-2': {
12
+ data: [
13
+ 'onchart.SMA',
14
+ 'RSI4H',
15
+ {
16
+ from: 'chart.data',
17
+ to: 'datasets',
18
+ obj: {
19
+ id: 'small-tf-data',
20
+ type: 'SourceData'
21
+ }
22
+ }
23
+ ]
24
+ },
25
+ 'none': {
26
+ range: 'X', // bool, 'X', 'Y', 'XY'
27
+ }
28
+ }
29
+ */
30
+
31
+ import Shared from './shared.js'
32
+ import Utils from './utils.js'
33
+
34
+ export default class Main {
35
+
36
+ constructor(tv, dc, sett) {
37
+
38
+ if (sett.use_window) {
39
+ if (!window.xchartlink$) {
40
+ window.xchartlink$ = {}
41
+ }
42
+ this.shared = window.xchartlink$
43
+ } else {
44
+ this.shared = Shared
45
+ }
46
+
47
+ this.tv = tv
48
+ this.dc = dc
49
+ this.sett = sett
50
+ this.targets = {}
51
+
52
+ this.onsettings({'chart-link': sett})
53
+ }
54
+
55
+ onsettings(all) {
56
+ clearTimeout(this.reset_id)
57
+ this.sett = all['chart-link']
58
+ if (!this.shared.rules) {
59
+ this.shared.rules = {}
60
+ this.shared.refs = {}
61
+ this.shared.meta = {}
62
+ }
63
+
64
+ let el = document.getElementById(this.tv.id)
65
+
66
+ if (this.sett.rules && el) {
67
+ this.shared.rules[this.tv.id] = this.sett.rules
68
+ }
69
+
70
+ this.shared.refs[this.tv.id] = this.tv
71
+
72
+ this.combine()
73
+ this.reset_id = setTimeout(() => this.reset())
74
+ }
75
+
76
+ // Combine rules from different instances
77
+ combine() {
78
+ this.shared.combined = {}
79
+ for (var id in this.shared.rules) {
80
+ for (var r in this.shared.rules[id]) {
81
+ this.shared.combined[r] =
82
+ this.shared.rules[id][r]
83
+ }
84
+ }
85
+ }
86
+
87
+ // Compile rules for this instance
88
+ compile() {
89
+
90
+ let gebcn = 'getElementsByClassName'
91
+ let els = [...document[gebcn]('trading-vue')]
92
+ this.targets = {}
93
+
94
+ for (let el of els) {
95
+ if (el.id === this.tv.id) continue
96
+ this.targets[el.id] = {}
97
+ }
98
+
99
+ let rules = this.rank(this.shared.combined)
100
+
101
+ for (var r of rules) {
102
+ let dst = r.pair[1]
103
+ if (dst === '*') {
104
+ dst = Object.keys(this.targets)
105
+ }
106
+ if (Array.isArray(dst)) {
107
+ for (var d of dst) {
108
+ if (!(d in this.targets)) continue
109
+ Object.assign(this.targets[d], r.r)
110
+ }
111
+ } else {
112
+ if (!(dst in this.targets)) continue
113
+ Object.assign(this.targets[dst], r.r)
114
+ }
115
+ }
116
+ }
117
+
118
+ // Select, rank & sort the rules
119
+ rank(rules) {
120
+ let out = []
121
+ for (var r in rules) {
122
+ let pair = this.splitr(r)
123
+ if (!this.matches(pair[0])) continue
124
+ if (pair[0] === '*') {
125
+ var rank = 20
126
+ } else if (Array.isArray(pair[0]) ) {
127
+ rank = 10
128
+ } else {
129
+ rank = 0
130
+ }
131
+ if (pair[1] === '*') {
132
+ rank += 2
133
+ } else if (Array.isArray(pair[1]) ) {
134
+ rank += 1
135
+ } else {
136
+ rank += 0
137
+ }
138
+ out.push({pair, rank, r: rules[r]})
139
+ }
140
+ return out.sort((a, b) => b.rank - a.rank)
141
+ }
142
+
143
+ // Check if the source of a rule matches tv.id
144
+ matches(src) {
145
+ return src === '*' || src === this.tv.id ||
146
+ (Array.isArray(src) && src.includes(this.tv.id))
147
+ }
148
+
149
+ splitr(rule) {
150
+ if (rule.trim() === '*') return ['*', '*']
151
+ return rule.split('->').map(x => {
152
+ let tup = x.split(',')
153
+ if (tup.length > 1) {
154
+ return tup.map(y => y.trim())
155
+ }
156
+ return x.trim()
157
+ })
158
+
159
+ }
160
+
161
+ // Apply all rules for this instance
162
+ reset() {
163
+ this.compile()
164
+
165
+ // Enable some chart hook events
166
+ this.tv.$refs.chart.hooks('xchanged')
167
+
168
+
169
+ this.tv.$watch(x => this.dc.get('.')
170
+ .filter(x => x.settings.$state),
171
+ this.ontools.bind(this))
172
+
173
+ }
174
+
175
+ // Listening to the Chart.vue hooks &
176
+ // other events
177
+ update(e) {
178
+ switch (e.event) {
179
+ case '?x-changed':
180
+ let cursor = e.args[0]
181
+ if (cursor.preventDefault) return
182
+ let main = this.tv.$refs.chart._layout.grids[cursor.grid_id]
183
+ let mc = this.tv.$refs.chart.cursor
184
+ cursor.t = mc.t
185
+ cursor.$ = mc.y$
186
+ for (var id in this.targets) {
187
+ let r = this.targets[id].cursor
188
+ if (r) {
189
+ let tv = this.shared.refs[id]
190
+ let g = tv.$refs.chart._layout.grids[0]
191
+ let xx = this.isX(r)
192
+ let yy = g.id === main.id && this.isY(r)
193
+ let upd = {
194
+ preventDefault: true,
195
+ x: xx ? g.t2screen(cursor.t) : -10,
196
+ y: yy ? g.$2screen(cursor.$) : -10,
197
+ grid_id: 0
198
+ }
199
+ tv.$refs.chart.cursor_changed(upd)
200
+ tv.$refs.chart.cursor.t = xx ? cursor.t : -10
201
+ tv.$refs.chart.cursor.y$ = yy ? cursor.$ : -10
202
+ }
203
+ }
204
+ break
205
+ case 'range-changed':
206
+ let now = new Date().getTime()
207
+ let meta = this.shared.meta[this.tv.id]
208
+ if (meta && meta.position) {
209
+ if (meta.position.lock > now) return
210
+ }
211
+ let range = e.args[0]
212
+ for (var id in this.targets) {
213
+ let r = this.targets[id].position
214
+ let tv = this.shared.refs[id]
215
+ let xx = this.isX(r)
216
+ let yy = this.isY(r)
217
+ if (!this.shared.meta[id]) {
218
+ this.shared.meta[id] = {}
219
+ }
220
+ // Prevents an infinite loop
221
+ this.shared.meta[id].position = {
222
+ lock: now + 100
223
+ }
224
+ if (xx) tv.goto(range[1])
225
+ }
226
+ break
227
+ }
228
+ }
229
+
230
+ ontools(n, p) {
231
+ let rem = Utils.removed(
232
+ n.map(x => x.settings.$uuid),
233
+ p.map(x => x.settings.$uuid)
234
+ )
235
+ let now = new Date().getTime()
236
+ let meta = this.shared.meta[this.tv.id]
237
+ if (meta && meta.tools) {
238
+ if (meta.tools.lock > now) return
239
+ }
240
+ for (var id in this.targets) {
241
+ let r = this.targets[id].tools
242
+ let tv = this.shared.refs[id]
243
+ if (r) {
244
+ if (!this.shared.meta[id]) {
245
+ this.shared.meta[id] = {}
246
+ }
247
+ // Prevents an infinite loop
248
+ this.shared.meta[id].tools = {
249
+ lock: now + 100
250
+ }
251
+ this.copy_tools(n, tv)
252
+ rem.forEach(r => tv.data.del(`${r}`))
253
+ }
254
+ }
255
+ }
256
+
257
+ copy_tools(n, tv) {
258
+ for (var tool of n) {
259
+ if (tool.id.includes('offchart')) continue
260
+ let uuid = tool.settings.$uuid
261
+ let exi = tv.data.get_one(`${uuid}`)
262
+ if (exi) {
263
+ tv.$set(exi, 'settings', Utils.copy(
264
+ tool.settings,
265
+ {
266
+ $selected: false,
267
+ $state: 'finished'
268
+ })
269
+ )
270
+ // TODO: maybe add a proper method
271
+ // of accessing overlays
272
+ let ovs = tv.$refs.chart.$refs.sec[0]
273
+ .$refs.grid
274
+ .$children.filter(x => x.tool)
275
+
276
+ for (var ov of ovs) {
277
+ ov.pins.forEach(x => x.re_init())
278
+ }
279
+
280
+ } else {
281
+ let copy = Utils.copy(tool)
282
+ copy.settings.$selected = false
283
+ copy.settings.$state = 'finished'
284
+ tv.data.add('onchart', copy)
285
+ }
286
+ }
287
+ }
288
+
289
+ isX(rule) {
290
+ return rule === true ||
291
+ (typeof rule === 'string' && rule.includes('X'))
292
+ }
293
+
294
+ isY(rule) {
295
+ return rule === true ||
296
+ (typeof rule === 'string' && rule.includes('Y'))
297
+ }
298
+
299
+ }
@@ -0,0 +1,10 @@
1
+
2
+ // Object shared beetween tvjs instances
3
+
4
+ class Shared {
5
+ constructor() {
6
+ this.__id__ = Math.random()
7
+ }
8
+ }
9
+
10
+ export default new Shared()
@@ -0,0 +1,17 @@
1
+ export default {
2
+
3
+ copy(obj, mod) {
4
+ let copy = JSON.parse(JSON.stringify(obj))
5
+ return Object.assign(copy, mod)
6
+ },
7
+
8
+ removed(ids, prev) {
9
+ let list = []
10
+ for (var id of prev) {
11
+ if (!ids.includes(id)) {
12
+ list.push(id)
13
+ }
14
+ }
15
+ return list
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "chart-link",
3
+ "author": "StdSquad",
4
+ "version": "1.0.0",
5
+ "components": [],
6
+ "widgets": [],
7
+ "overlays": [],
8
+ "skins": [],
9
+ "colorpacks": [],
10
+ "deps": {}
11
+ }
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <span class="h-splitter"
3
+ @mousedown="hs_mousedown" :style="hs_style">
4
+ </span>
5
+ </template>
6
+ <script>
7
+
8
+ import Utils from './utils.js'
9
+
10
+ export default {
11
+ name: 'Splitter',
12
+ props: ['id', 'main', 'dc', 'tv', 'data'],
13
+ mounted() {
14
+ this.MIN_HEIGHT = this.data.sett.min_height || 20
15
+ },
16
+ methods: {
17
+ hs_mousedown(e) {
18
+ this.drag = {
19
+ type: 'hs',
20
+ y: e.clientY,
21
+ h1: this.data.grid1.height,
22
+ h2: this.data.grid2.height
23
+ }
24
+ Utils.add_style('disable-user-select', `body * {
25
+ user-select: none;
26
+ }
27
+ .trading-vue-chart {
28
+ pointer-events: none;
29
+ }`)
30
+ },
31
+ hs_mouseup(e) {
32
+ this.drag = null
33
+ Utils.rem_style('disable-user-select')
34
+ },
35
+ hs_mousemove(e) {
36
+ if (this.drag) {
37
+ let off = e.clientY - this.drag.y
38
+ let new_h1 = this.drag.h1 + off
39
+ let new_h2 = this.drag.h2 - off
40
+ if (new_h1 > this.MIN_HEIGHT &&
41
+ new_h2 > this.MIN_HEIGHT) {
42
+ this.data.grid1.height = new_h1
43
+ this.data.grid2.height = new_h2
44
+ }
45
+ this.main.calc_heights()
46
+ }
47
+ },
48
+ hs_mouseleave(e) {
49
+ this.drag = null
50
+ Utils.rem_style('disable-user-select')
51
+ }
52
+ },
53
+ computed: {
54
+ hs_style() {
55
+ return {
56
+ drag: null,
57
+ top: this.data.grid2.offset + 'px',
58
+ //backgroundColor: this.colors.splitter
59
+ }
60
+ },
61
+ }
62
+ }
63
+ </script>
64
+ <style scoped>
65
+ .h-splitter {
66
+ position: absolute;
67
+ left: 0;
68
+ height: 5px;
69
+ margin-top: -2px;
70
+ width: 100%;
71
+ z-index: 1;
72
+ background-color: #3ee4afb5;
73
+ opacity: 0;
74
+ pointer-events: all;
75
+ }
76
+ .h-splitter:hover {
77
+ cursor: row-resize;
78
+ opacity: 1;
79
+ }
80
+ </style>
@@ -0,0 +1,152 @@
1
+
2
+ // Extension's controller
3
+
4
+ import { Utils } from 'trading-vue-js'
5
+ import Vue from 'vue'
6
+ import Splitter from './Splitter.vue'
7
+
8
+ export default class Main {
9
+
10
+ constructor(tv, dc, sett) {
11
+
12
+ this.widgets = {}
13
+ this.tv = tv
14
+ this.dc = dc
15
+ this.sett = sett
16
+
17
+ setTimeout(() => {
18
+
19
+ this.tv.$el.addEventListener(
20
+ 'mousemove', this.onmousemove.bind(this)
21
+ )
22
+
23
+ this.tv.$el.addEventListener(
24
+ 'mouseup', this.onmouseup.bind(this)
25
+ )
26
+
27
+ this.tv.$el.addEventListener(
28
+ 'mouseleave', this.onmouseleave.bind(this)
29
+ )
30
+
31
+ this.place_splitters()
32
+ this.calc_heights()
33
+
34
+ // Track changes of grids count
35
+ this.tv.$watch(x =>
36
+ this.dc.get('.').map(x => x.id),
37
+ this.ongrids.bind(this))
38
+
39
+ })
40
+
41
+ }
42
+
43
+ // Listens to all tvjs events, creates new widgets
44
+ update(e) {
45
+ switch(e.event) {
46
+
47
+ }
48
+ }
49
+
50
+ // Extension settings has changed
51
+ onsettings(sett) {}
52
+
53
+ ongrids() {
54
+ setTimeout(() => {
55
+ this.remove_widgets()
56
+ this.place_splitters()
57
+ })
58
+ }
59
+
60
+ onmousemove(e) {
61
+ // List of widgets created by this controller
62
+ let list = this.tv.$refs.widgets.$children
63
+ .filter(x => x.main === this)
64
+
65
+ for (var s of list) {
66
+ s.hs_mousemove(e)
67
+ }
68
+ }
69
+
70
+ onmouseup(e) {
71
+ // List of widgets created by this controller
72
+ let list = this.tv.$refs.widgets.$children
73
+ .filter(x => x.main === this)
74
+
75
+ for (var s of list) {
76
+ s.hs_mouseup(e)
77
+ }
78
+ }
79
+
80
+ onmouseleave(e) {
81
+ // List of widgets created by this controller
82
+ let list = this.tv.$refs.widgets.$children
83
+ .filter(x => x.main === this)
84
+
85
+ for (var s of list) {
86
+ s.hs_mouseleave(e)
87
+ }
88
+ }
89
+
90
+ place_splitters() {
91
+ let grids = this.tv.$refs.chart._layout.grids
92
+ for (var i = 1; i < grids.length; i++) {
93
+ let g1 = grids[i-1]
94
+ let g2 = grids[i]
95
+ let id = `Splitter-${g1.id}-${g2.id}-${Utils.uuid2()}`
96
+ Vue.set(this.widgets, id, {
97
+ id: id,
98
+ cls: Splitter,
99
+ data: {
100
+ grid1: g1,
101
+ grid2: g2,
102
+ sett: this.sett
103
+ }
104
+ })
105
+ }
106
+ }
107
+
108
+ calc_heights() {
109
+ let hs = []
110
+ for (var g of this.tv.$refs.chart._layout.grids) {
111
+ hs.push(g.height)
112
+ }
113
+ let sum = hs.reduce((a, b) => a + b, 0)
114
+ hs = hs.map(h => h / sum)
115
+ this.grid_ovs().forEach((ov, i) => {
116
+ if (!ov.grid) {
117
+ Vue.set(ov, 'grid', {})
118
+ }
119
+ Vue.set(ov.grid, 'height', hs[i] || 1)
120
+ })
121
+ }
122
+
123
+ // Grid defining overlays
124
+ grid_ovs() {
125
+ let list = [this.dc.data.chart]
126
+ for (var ov of this.dc.data.offchart) {
127
+ if (!ov.grid || ov.grid.id === undefined) {
128
+ list.push(ov)
129
+ }
130
+ }
131
+ return list
132
+ }
133
+
134
+ remove_widgets() {
135
+ for (var id in this.widgets) {
136
+ this.tv.$delete(this.widgets, id)
137
+ }
138
+ }
139
+
140
+ destroy() {
141
+ this.tv.$el.removeEventListener(
142
+ 'mousemove', this.onmousemove
143
+ )
144
+ this.tv.$el.removeEventListener(
145
+ 'mouseup', this.mouseup
146
+ )
147
+ this.tv.$el.removeEventListener(
148
+ 'mouseleave', this.mouseleave
149
+ )
150
+ }
151
+
152
+ }
@@ -0,0 +1,25 @@
1
+ export default {
2
+
3
+ add_style(id, style) {
4
+
5
+ var stbr = document.getElementById(id)
6
+ if (stbr) {
7
+ var sheetParent = stbr.parentNode
8
+ sheetParent.removeChild(stbr)
9
+ }
10
+
11
+ var sheet = document.createElement('style')
12
+ sheet.setAttribute("id", id)
13
+ sheet.innerHTML = style
14
+ document.body.appendChild(sheet)
15
+ },
16
+
17
+ rem_style(id, style) {
18
+ var stbr = document.getElementById(id)
19
+ if (stbr) {
20
+ var sheetParent = stbr.parentNode
21
+ sheetParent.removeChild(stbr)
22
+ }
23
+ }
24
+
25
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "grid-resize",
3
+ "author": "StdSquad",
4
+ "version": "1.0.0",
5
+ "components": [],
6
+ "widgets": [],
7
+ "overlays": [],
8
+ "skins": [],
9
+ "colorpacks": [],
10
+ "deps": {}
11
+ }
@@ -0,0 +1,91 @@
1
+ <template>
2
+ <window title="Add Overlay" class="add-win"
3
+ @close="on_close" :tv='tv'>
4
+ <div class="add-win-list">
5
+ <div v-for="ov of ovs" class="add-win-item"
6
+ @click="on_click(ov.name)">
7
+ <span>{{ov.name}}</span>
8
+ <span class="add-win-item-desc">
9
+ {{ov.methods.meta_info().desc}}
10
+ </span>
11
+ </div>
12
+ </div>
13
+ </window>
14
+ </template>
15
+ <script>
16
+
17
+ import Window from '../../components/Window.vue'
18
+
19
+ export default {
20
+ name: 'AddWin',
21
+ props: ['id', 'main', 'dc', 'tv', 'data'],
22
+ components: { Window },
23
+ mounted() {
24
+ },
25
+ methods: {
26
+ on_close() {
27
+ this.$props.main.remove_widget(this.$props.id)
28
+ },
29
+ on_click(name) {
30
+ this.on_close()
31
+ this.main.add_overlay({
32
+ side: this.data.type,
33
+ index: this.data.index,
34
+ type: name
35
+ })
36
+ }
37
+ },
38
+ computed: {
39
+ sett() {
40
+ return this.$props.data.ov.settings
41
+ }
42
+ },
43
+ data() {
44
+ return {
45
+ ovs: this.tv.overlays.filter(x => x.methods.calc)
46
+ }
47
+ }
48
+ }
49
+ </script>
50
+ <style scoped>
51
+ .tvjs-x-window.add-win {
52
+ padding-bottom: 30px;
53
+ border: 1px solid #80808011;
54
+ }
55
+ .add-win-list {
56
+ height: 300px;
57
+ overflow-x: hidden;
58
+ overflow-y: auto;
59
+ user-select: none;
60
+ }
61
+ /* Hide scrollbar for Chrome, Safari and Opera */
62
+ .add-win-list::-webkit-scrollbar {
63
+ display: none;
64
+ }
65
+
66
+ /* Hide scrollbar for IE, Edge and Firefox */
67
+ .add-win-list {
68
+ -ms-overflow-style: none; /* IE and Edge */
69
+ scrollbar-width: none; /* Firefox */
70
+ }
71
+ .add-win-item {
72
+ color: #ffffff88;
73
+ width: 100%;
74
+ padding: 5px;
75
+ cursor: pointer;
76
+ }
77
+ .add-win-item:hover {
78
+ background: #88888822;
79
+ color: #ffffffff;
80
+ }
81
+ .add-win-item-desc {
82
+ color: #ffffff33;
83
+ margin-left: 3px;
84
+ }
85
+ .add-win-item:hover .add-win-item-desc {
86
+ color: #ffffff44;
87
+ }
88
+ .add-win-empty {
89
+ opacity: 0.5;
90
+ }
91
+ </style>