beyond-rails 0.0.185 → 0.0.190

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/src/js/components/Alert.js +1 -1
  3. data/src/js/components/Autocomplete.js +1 -1
  4. data/src/js/components/AutocompleteMenu.js +1 -1
  5. data/src/js/components/BarChart.js +452 -0
  6. data/src/js/components/Btn.js +1 -1
  7. data/src/js/components/Checkbox.js +1 -1
  8. data/src/js/components/DateInput.js +1 -1
  9. data/src/js/components/DateMenu.js +1 -1
  10. data/src/js/components/DateTimeRanger.js +1 -1
  11. data/src/js/components/Datepicker.js +1 -1
  12. data/src/js/components/DatepickerBtnArrow.js +1 -1
  13. data/src/js/components/Dropdown.js +1 -1
  14. data/src/js/components/LineChart.js +535 -0
  15. data/src/js/components/Menu.js +1 -1
  16. data/src/js/components/Modal.js +64 -13
  17. data/src/js/components/Navbar.js +1 -1
  18. data/src/js/components/Radio.js +1 -1
  19. data/src/js/components/SearchDropdown.js +1 -1
  20. data/src/js/components/Sidebar.js +1 -1
  21. data/src/js/components/Tabbox.js +1 -1
  22. data/src/js/components/TimeInput.js +1 -1
  23. data/src/js/components/TimeMenu.js +1 -1
  24. data/src/js/components/Timepicker.js +1 -1
  25. data/src/js/components/Toast.js +1 -1
  26. data/src/js/components/ToastItem.js +1 -1
  27. data/src/js/components/Tooltip.js +1 -1
  28. data/src/js/decorators/chartCommon.js +218 -0
  29. data/src/js/{utils → decorators}/supportDom.js +1 -1
  30. data/src/js/index.js +6 -2
  31. data/src/js/jquery/bindModalFn.js +57 -6
  32. data/src/js/utils/index.js +10 -1
  33. data/src/js/utils/isDef.js +3 -0
  34. data/src/js/utils/isInt.js +3 -0
  35. data/src/js/utils/isUndef.js +3 -0
  36. data/src/sass/_beyond.scss +2 -0
  37. data/src/sass/abstracts/_variables.scss +5 -0
  38. data/src/sass/components/_breadcrumb.scss +3 -0
  39. data/src/sass/components/_chart.scss +14 -0
  40. data/src/sass/components/_mega-menu.scss +57 -0
  41. data/src/sass/components/_modal.scss +12 -1
  42. data/src/sass/components/_nav.scss +1 -0
  43. data/src/sass/layout/_flex-util.scss +3 -0
  44. metadata +34 -15
@@ -1,4 +1,4 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
 
3
3
  @supportDom
4
4
  export default class Menu {
@@ -1,6 +1,8 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
  import { noop } from '../utils'
3
3
 
4
+ let globalModalId = 0
5
+
4
6
  @supportDom
5
7
  export default class Modal {
6
8
 
@@ -15,19 +17,41 @@ export default class Modal {
15
17
  }
16
18
 
17
19
  init() {
18
- this.modalId = this.dom.dataset.modalOpener
19
- const selector = `[data-modal="${this.modalId}"]`
20
- this.modal = document.querySelector(selector)
21
- if (! this.modal) {
22
- throw new Error(`${selector} is not defined.`)
23
- }
20
+ this.bindEvents()
21
+ }
22
+
23
+ bindEvents() {
24
+ this.setModalDom()
24
25
  this.closeBtn = this.modal.querySelector('[data-close]')
25
26
  this.cancelBtn = this.modal.querySelector('[data-cancel]')
26
27
  this.confirmBtn = this.modal.querySelector('[data-confirm]')
27
28
  this.addEvents()
28
29
  }
29
30
 
30
- show() {
31
+ setModalDom() {
32
+ const { modalOpener, modal } = this.dom.dataset
33
+
34
+ if (modalOpener) {
35
+ this.modalId = this.dom.dataset.modalOpener
36
+ const selector = `[data-modal="${this.modalId}"]`
37
+ this.modal = document.querySelector(selector)
38
+ return
39
+ }
40
+
41
+ if (modal) {
42
+ this.modalId = modal
43
+ }
44
+ else {
45
+ this.modalId = `modal-${++globalModalId}`
46
+ this.dom.dataset.modal = this.modalId
47
+ }
48
+ this.modal = this.dom
49
+ }
50
+
51
+ show(html) {
52
+ if (html) {
53
+ this.replace(html)
54
+ }
31
55
  this.isVisible = true
32
56
  this.modal.style.display = 'block'
33
57
  setTimeout(() => {
@@ -43,20 +67,47 @@ export default class Modal {
43
67
  }, 300)
44
68
  }
45
69
 
70
+ replace(html) {
71
+ this.destroy()
72
+ this.modalId = null
73
+
74
+ // replace with new dom
75
+ const div = document.createElement('div')
76
+ div.innerHTML = html.trim()
77
+ const dom = div.firstChild
78
+ this.dom.parentNode.replaceChild(dom, this.dom)
79
+
80
+ this.dom = dom
81
+ this.dom._modal = this
82
+ this.init()
83
+ }
84
+
85
+ visible() {
86
+ return this.isVisible
87
+ }
88
+
89
+ addEventIfDomExists(dom, event, cb) {
90
+ if (dom) {
91
+ this.addEvent(dom, event, cb)
92
+ }
93
+ }
94
+
46
95
  addEvents() {
47
- this.addEvent(this.dom, 'click', () => this.show())
96
+ if (this.dom.dataset.modalOpener) {
97
+ this.addEventIfDomExists(this.dom, 'click', () => this.show())
98
+ }
48
99
 
49
- this.addEvent(this.closeBtn, 'click', () => {
100
+ this.addEventIfDomExists(this.closeBtn, 'click', () => {
50
101
  this.hide()
51
102
  this.options.cancel('close')
52
103
  })
53
104
 
54
- this.addEvent(this.cancelBtn, 'click', () => {
105
+ this.addEventIfDomExists(this.cancelBtn, 'click', () => {
55
106
  this.hide()
56
107
  this.options.cancel('cancel')
57
108
  })
58
109
 
59
- this.addEvent(this.modal, 'click', event => {
110
+ this.addEventIfDomExists(this.modal, 'click', event => {
60
111
  // is backdrop
61
112
  if (event.target.dataset.modal === this.modalId) {
62
113
  this.hide()
@@ -64,7 +115,7 @@ export default class Modal {
64
115
  }
65
116
  })
66
117
 
67
- this.addEvent(this.confirmBtn, 'click', () => {
118
+ this.addEventIfDomExists(this.confirmBtn, 'click', () => {
68
119
  if (typeof this.options.confirm === 'function') {
69
120
  this.options.confirm()
70
121
  }
@@ -1,4 +1,4 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
 
3
3
  @supportDom
4
4
  export default class Navbar {
@@ -1,4 +1,4 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
 
3
3
  @supportDom
4
4
  export default class Radio {
@@ -1,5 +1,5 @@
1
1
  import getFloatedTargetPos from '../utils/getFloatedTargetPos'
2
- import supportDom from '../utils/supportDom'
2
+ import supportDom from '../decorators/supportDom'
3
3
  import getKey from '../utils/getKey'
4
4
  import { debounce, noop, toPixel, throttle } from '../utils'
5
5
 
@@ -1,4 +1,4 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
 
3
3
  @supportDom
4
4
  export default class Sidebar {
@@ -1,4 +1,4 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
  import Dropdown from './Dropdown'
3
3
  import { noop } from '../utils'
4
4
 
@@ -1,5 +1,5 @@
1
1
  import { DEFAULT_TIMEZONE } from '../consts'
2
- import supportDom from '../utils/supportDom'
2
+ import supportDom from '../decorators/supportDom'
3
3
  import isTouchDevice from '../utils/isTouchDevice'
4
4
  import { format } from '../utils'
5
5
 
@@ -1,5 +1,5 @@
1
1
  import getFloatedTargetPos from '../utils/getFloatedTargetPos'
2
- import supportDom from '../utils/supportDom'
2
+ import supportDom from '../decorators/supportDom'
3
3
  import { getHours, getMinutes, range, toPixel } from '../utils'
4
4
 
5
5
  @supportDom
@@ -1,7 +1,7 @@
1
1
  import TimeInput from './TimeInput'
2
2
  import TimeMenu from './TimeMenu'
3
3
  import { DEFAULT_TIMEZONE } from '../consts'
4
- import supportDom from '../utils/supportDom'
4
+ import supportDom from '../decorators/supportDom'
5
5
  import {
6
6
  dateToTimestamp,
7
7
  noop,
@@ -1,4 +1,4 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
  import ToastItem from './ToastItem'
3
3
 
4
4
  @supportDom
@@ -1,4 +1,4 @@
1
- import supportDom from '../utils/supportDom'
1
+ import supportDom from '../decorators/supportDom'
2
2
 
3
3
  @supportDom
4
4
  export default class ToastItem {
@@ -1,5 +1,5 @@
1
1
  import getFloatedTargetPos from '../utils/getFloatedTargetPos'
2
- import supportDom from '../utils/supportDom'
2
+ import supportDom from '../decorators/supportDom'
3
3
  import { toPixel } from '../utils'
4
4
 
5
5
  const TOOLTIP_PLACEMENTS = ['top', 'bottom', 'left', 'right']
@@ -0,0 +1,218 @@
1
+ import isDef from '../utils/isDef'
2
+ import isUndef from '../utils/isUndef'
3
+ import { getDomPos, range, toPixel, isFunction } from '../utils'
4
+
5
+ export default function chartCommon(target) {
6
+
7
+ return class extends target {
8
+
9
+ init() {
10
+ this.layers = []
11
+ if (isFunction(super.init)) {
12
+ super.init()
13
+ }
14
+ }
15
+
16
+ get firstLayer() {
17
+ return this.layers[0]
18
+ }
19
+
20
+ addLayer() {
21
+ const { dom } = this
22
+ const canvas = document.createElement('canvas')
23
+ canvas.style.position = 'absolute'
24
+ canvas.style.top = 0
25
+ canvas.style.left = 0
26
+ canvas.style.right = 0
27
+ canvas.style.bottom = 0
28
+ const ctx = canvas.getContext('2d')
29
+
30
+ this.setCanvasSize(canvas)
31
+ this.layers.push({ canvas, ctx })
32
+
33
+ dom.style.position = 'relative'
34
+ dom.appendChild(canvas)
35
+ }
36
+
37
+ bindMedia() {
38
+ if (this.media) {
39
+ return
40
+ }
41
+ this.media = window.matchMedia(`(resolution: ${this.dpr}dppx)`)
42
+ this._handleDprChange = this.handleDprChange.bind(this)
43
+ this.media.addListener(this._handleDprChange)
44
+ }
45
+
46
+ clear() {
47
+ const { ctx } = this
48
+ ctx.fillStyle = this.bgColor
49
+ ctx.fillRect(0, 0, this.width, this.height)
50
+ }
51
+
52
+ fillCircle(ctx, x, y, radius, style, alpha) {
53
+ ctx.save()
54
+ ctx.beginPath()
55
+ ctx.arc(x, y, radius, 0, 2 * Math.PI)
56
+ ctx.fillStyle = style
57
+ ctx.globalAlpha = alpha || 1
58
+ ctx.fill()
59
+ ctx.closePath()
60
+ ctx.restore()
61
+ }
62
+
63
+ getAutoStep(firstValue, lastValue, pointsLength) {
64
+ return (lastValue - firstValue) / (pointsLength - 1)
65
+ }
66
+
67
+ getHighestCanvas() {
68
+ const { layers, canvas } = this
69
+ if (layers.length === 0) {
70
+ return canvas
71
+ }
72
+ return layers[layers.length - 1].canvas
73
+ }
74
+
75
+ // real position in window including scrolling distance
76
+ getMousePos(canvasMousePos) {
77
+ const domPos = getDomPos(this.dom)
78
+ return {
79
+ x: domPos.x + canvasMousePos.x,
80
+ y: domPos.y + canvasMousePos.y
81
+ }
82
+ }
83
+
84
+ getMousePosInCanvas(event) {
85
+ const rect = this.canvas.getBoundingClientRect()
86
+ return {
87
+ x: event.clientX - rect.left,
88
+ y: event.clientY - rect.top
89
+ }
90
+ }
91
+
92
+ getLengthTotalData(gap, gutter, values, measureLength, toLabel) {
93
+
94
+ const valueCount = values.length
95
+ const marked = {}
96
+
97
+ // mark the first and last
98
+ marked[0] = true
99
+ marked[valueCount - 1] = true
100
+
101
+ // Check whether a value can be marked next
102
+ // For example, gap is 2
103
+ //
104
+ // values: 1 2 3 4 5 6 7
105
+ // marked: v v
106
+ //
107
+ // 4 will only be marked because it has enough gap on left and right side.
108
+ const hasGap = index => {
109
+ return range(index - gap, index).every(i => isUndef(marked[i])) &&
110
+ range(index + 1, index + gap + 1).every(i => isUndef(marked[i]))
111
+ }
112
+
113
+ return values.reduce((res, value, i) => {
114
+
115
+ if (i === 0) {
116
+ const label = toLabel(value)
117
+ const length = measureLength(label)
118
+ const lengthTotal = res.lengthTotal + length + gutter
119
+ const rows = res.rows.slice()
120
+ rows.push({ label, length, value })
121
+ return { lengthTotal, rows }
122
+ }
123
+ if (i === (valueCount - 1)) {
124
+ const label = toLabel(value)
125
+ const length = measureLength(label)
126
+ const lengthTotal = res.lengthTotal + length
127
+ const rows = res.rows.slice()
128
+ rows.push({ label, length, value })
129
+ return { lengthTotal, rows }
130
+ }
131
+ if (hasGap(i)) {
132
+ const label = toLabel(value)
133
+ marked[i] = true
134
+ const length = measureLength(label)
135
+ const lengthTotal = res.lengthTotal + length + gutter
136
+ const rows = res.rows.slice()
137
+ rows.push({ label, length, value })
138
+ return { lengthTotal, rows }
139
+ }
140
+ return res
141
+ }, {
142
+ lengthTotal: 0,
143
+ rows: []
144
+ })
145
+ }
146
+
147
+ getStepStartEnd(step, firstValue, lastValue) {
148
+
149
+ const stepStart = parseInt(firstValue / step, 10) * step
150
+ let stepEnd = parseInt(lastValue / step, 10) * step
151
+
152
+ if (stepEnd < lastValue) {
153
+ stepEnd += step
154
+ }
155
+ return [stepStart, stepEnd]
156
+ }
157
+
158
+ raf(fn) {
159
+ if (isDef(window.requestAnimationFrame)) {
160
+ return window.requestAnimationFrame(fn)
161
+ }
162
+ return fn()
163
+ }
164
+
165
+ removeAllLayers() {
166
+ const { dom } = this
167
+ this.layers.forEach(layer => {
168
+ const { canvas } = layer
169
+ if (dom.contains(canvas)) {
170
+ dom.removeChild(canvas)
171
+ }
172
+ })
173
+ }
174
+
175
+ setCanvas() {
176
+ const canvas = document.createElement('canvas')
177
+ const ctx = canvas.getContext('2d')
178
+
179
+ this.canvas = canvas
180
+ this.ctx = ctx
181
+ this.setCanvasFontSize(this.canvas, this.fontSize)
182
+ this.setCanvasSize(canvas)
183
+
184
+ this.dom.appendChild(canvas)
185
+ }
186
+
187
+ setCanvasFontSize(canvas, fontSize) {
188
+ const ctx = canvas.getContext('2d')
189
+ const args = ctx.font.split(' ')
190
+ ctx.font = fontSize + 'px ' + args[args.length - 1]
191
+ }
192
+
193
+ setCanvasSize(canvas) {
194
+ const { dpr, width, height } = this
195
+
196
+ // https://coderwall.com/p/vmkk6a/how-to-make-the-canvas-not-look-like-crap-on-retina
197
+ canvas.width = width * dpr
198
+ canvas.height = height * dpr
199
+ canvas.style.width = toPixel(width)
200
+ canvas.style.height = toPixel(height)
201
+ canvas.getContext('2d').scale(dpr, dpr)
202
+ }
203
+
204
+ setDomWidthIfNeeded() {
205
+ if (isUndef(this.options.width)) {
206
+ this.width = this.dom.offsetWidth
207
+ }
208
+ }
209
+
210
+ setDpr() {
211
+ this.dpr = window.devicePixelRatio || 1
212
+ }
213
+
214
+ unbindMedia() {
215
+ this.media.removeListener(this._handleDprChange)
216
+ }
217
+ }
218
+ }
@@ -1,4 +1,4 @@
1
- import { isFunction } from './index'
1
+ import { isFunction } from '../utils'
2
2
  import createdComponents from '../consts/createdComponents'
3
3
 
4
4
  export default function supportDom(target) {
@@ -6,19 +6,21 @@ import './polyfills/nodeRemove'
6
6
  import './polyfills/elementDataset'
7
7
  import Alert from './components/Alert'
8
8
  import Autocomplete from './components/Autocomplete'
9
+ import BarChart from './components/BarChart'
9
10
  import Btn from './components/Btn'
10
11
  import Checkbox from './components/Checkbox'
11
12
  import DateTimeRanger from './components/DateTimeRanger'
12
13
  import Datepicker from './components/Datepicker'
13
14
  import Dropdown from './components/Dropdown'
15
+ import LineChart from './components/LineChart'
14
16
  import Menu from './components/Menu'
15
17
  import Modal from './components/Modal'
16
18
  import Navbar from './components/Navbar'
17
19
  import Radio from './components/Radio'
18
20
  import SearchDropdown from './components/SearchDropdown'
19
21
  import Sidebar from './components/Sidebar'
20
- import Timepicker from './components/Timepicker'
21
22
  import Tabbox from './components/Tabbox'
23
+ import Timepicker from './components/Timepicker'
22
24
  import Toast from './components/Toast'
23
25
  import Tooltip from './components/Tooltip'
24
26
  import bind from './utils/bind'
@@ -28,19 +30,21 @@ import unbindAll from './utils/unbindAll'
28
30
  export {
29
31
  Alert,
30
32
  Autocomplete,
33
+ BarChart,
31
34
  Btn,
32
35
  Checkbox,
33
36
  DateTimeRanger,
34
37
  Datepicker,
35
38
  Dropdown,
39
+ LineChart,
36
40
  Menu,
37
41
  Modal,
38
42
  Navbar,
39
43
  Radio,
40
44
  SearchDropdown,
41
45
  Sidebar,
42
- Timepicker,
43
46
  Tabbox,
47
+ Timepicker,
44
48
  Toast,
45
49
  Tooltip,
46
50
  bind,