uploadcare-widget 0.9 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/app/assets/images/uploadcare/images/tab-icons-active.png +0 -0
  2. data/app/assets/images/uploadcare/images/tab-icons.png +0 -0
  3. data/app/assets/javascripts/uploadcare/core/boot.js.coffee +0 -1
  4. data/app/assets/javascripts/uploadcare/core/namespace.coffee +12 -1
  5. data/app/assets/javascripts/uploadcare/files.js.coffee +14 -9
  6. data/app/assets/javascripts/uploadcare/files/base.js.coffee +4 -1
  7. data/app/assets/javascripts/uploadcare/files/uploaded.js.coffee +1 -1
  8. data/app/assets/javascripts/uploadcare/files/url.js.coffee +1 -1
  9. data/app/assets/javascripts/uploadcare/locale/en.js.coffee +2 -1
  10. data/app/assets/javascripts/uploadcare/locale/es.js.coffee +2 -1
  11. data/app/assets/javascripts/uploadcare/locale/ru.js.coffee +1 -0
  12. data/app/assets/javascripts/uploadcare/settings.js.coffee +19 -2
  13. data/app/assets/javascripts/uploadcare/templates/circle-canvas.jst.ejs +1 -0
  14. data/app/assets/javascripts/uploadcare/templates/circle-text.jst.ejs +3 -0
  15. data/app/assets/javascripts/uploadcare/templates/tab-file.jst.ejs +16 -14
  16. data/app/assets/javascripts/uploadcare/templates/widget-button.jst.ejs +4 -4
  17. data/app/assets/javascripts/uploadcare/templates/widget.jst.ejs +1 -1
  18. data/app/assets/javascripts/uploadcare/ui/progress.js.coffee +133 -83
  19. data/app/assets/javascripts/uploadcare/utils/abilities.js.coffee +6 -1
  20. data/app/assets/javascripts/uploadcare/widget.js.coffee.erb +3 -0
  21. data/app/assets/javascripts/uploadcare/widget/base-widget.js.coffee +2 -1
  22. data/app/assets/javascripts/uploadcare/widget/dialog.js.coffee +1 -0
  23. data/app/assets/javascripts/uploadcare/widget/dragdrop.js.coffee +14 -5
  24. data/app/assets/javascripts/uploadcare/widget/tabs/file-tab.js.coffee +2 -4
  25. data/app/assets/javascripts/uploadcare/widget/tabs/remote-tab.js.coffee +11 -1
  26. data/app/assets/javascripts/uploadcare/widget/widget.js.coffee +1 -0
  27. data/app/assets/stylesheets/uploadcare/dialog.css.scss +3 -0
  28. data/app/assets/stylesheets/uploadcare/images.css.scss +2 -1
  29. data/app/assets/stylesheets/uploadcare/widget.css.scss +12 -12
  30. data/lib/uploadcare-widget/version.rb +1 -1
  31. data/test/dummy/Gemfile.lock +2 -2
  32. data/test/dummy/spec/javascripts/spec/files.js.coffee +1 -1
  33. metadata +6 -7
  34. data/app/assets/javascripts/uploadcare/core/eve.js +0 -217
  35. data/app/assets/javascripts/uploadcare/core/raphael.js +0 -5605
  36. data/app/assets/javascripts/uploadcare/templates/circle.jst.ejs +0 -3
@@ -1,6 +1,5 @@
1
1
  # = require ./namespace
2
2
  # = require ./jquery
3
3
  # = require ./jquery-role
4
- # = require ./raphael
5
4
  # ≠ require ./testing
6
5
  # = require ./pusher
@@ -18,4 +18,15 @@ uploadcare.namespace = (path, fn) ->
18
18
  fn(target)
19
19
 
20
20
  uploadcare.expose = (key, value) ->
21
- window.uploadcare[key] = value || uploadcare[key]
21
+ parts = key.split('.')
22
+ last = parts.pop()
23
+
24
+ target = window.uploadcare
25
+ source = uploadcare
26
+
27
+ for part in parts
28
+ target[part] ||= {}
29
+ target = target[part]
30
+ source = source?[part]
31
+
32
+ target[last] = value || source[last]
@@ -41,18 +41,10 @@ namespace 'uploadcare', (ns) ->
41
41
  input: (settings, input) ->
42
42
  [new f.InputFile(settings, input)]
43
43
  url: (settings, urls) ->
44
- # We also accept plain UUIDs here for an internally used shortcut.
45
- # Typically, you should use the `uploaded` converter for clarity.
46
44
  unless $.isArray(urls)
47
45
  urls = [urls]
48
46
  for url in urls
49
- cdnBase = utils.escapeRegExp(settings.cdnBase)
50
- .replace(/^https?/i, 'https?')
51
- cdn = new RegExp("^#{cdnBase}/#{utils.uuidRegex.source}", 'i')
52
- if utils.fullUuidRegex.test(url) || cdn.test(url)
53
- new f.UploadedFile settings, url
54
- else
55
- new f.UrlFile settings, url
47
+ new f.UrlFile settings, url
56
48
  uploaded: (settings, uuids) ->
57
49
  unless $.isArray(uuids)
58
50
  uuids = [uuids]
@@ -65,3 +57,16 @@ namespace 'uploadcare', (ns) ->
65
57
  new f.ReadyFile(settings, fileData)
66
58
  else
67
59
  new f.DeletedFile()
60
+
61
+ # internally used shortcut
62
+ 'url-or-uploaded': (settings, urls) ->
63
+ unless $.isArray(urls)
64
+ urls = [urls]
65
+ cdnBase = utils.escapeRegExp(settings.cdnBase)
66
+ .replace(/^https?/i, 'https?')
67
+ cdn = new RegExp("^#{cdnBase}/#{utils.uuidRegex.source}", 'i')
68
+ for url in urls
69
+ if utils.fullUuidRegex.test(url) || cdn.test(url)
70
+ new f.UploadedFile settings, url
71
+ else
72
+ new f.UrlFile settings, url
@@ -92,6 +92,9 @@ namespace 'uploadcare.files', (ns) ->
92
92
  width: img.width
93
93
  height: img.height
94
94
 
95
+ img.onerror = =>
96
+ @reject()
97
+
95
98
  img.src = url
96
99
  ).promise()
97
100
 
@@ -196,6 +199,6 @@ namespace 'uploadcare.utils', (utils) ->
196
199
  if utils.isFile(value)
197
200
  value
198
201
  else
199
- uploadcare.fileFrom('url', value, settings)
202
+ uploadcare.fileFrom('url-or-uploaded', value, settings)
200
203
  else
201
204
  null
@@ -24,7 +24,7 @@ namespace 'uploadcare.files', (ns) ->
24
24
  class ns.ReadyFile extends ns.BaseFile
25
25
  constructor: (settings, @__fileData) ->
26
26
  super
27
- @fileId = @__fileData.file_id
27
+ @fileId = @__fileData.uuid
28
28
  @__uploadDf.resolve()
29
29
 
30
30
  __startUpload: ->
@@ -81,7 +81,7 @@ namespace 'uploadcare.files', (ns) ->
81
81
  success: (data) =>
82
82
  return if @__shutdown
83
83
  @__state('progress', data)
84
- [@fileName, @fileId] = [data.original_filename, data.file_id]
84
+ [@fileName, @fileId] = [data.original_filename, data.uuid]
85
85
  @__uploadDf.resolve(this)
86
86
 
87
87
  error: =>
@@ -37,7 +37,8 @@ uploadcare.namespace 'uploadcare.locale.translations', (ns) ->
37
37
  dropbox: 'Dropbox'
38
38
  gdrive: 'Google Drive'
39
39
  instagram: 'Instagram'
40
- vk: 'Vkontakte'
40
+ vk: 'VK'
41
+ evernote: 'Evernote'
41
42
  url: 'Arbitrary Links'
42
43
  url:
43
44
  title: 'Files from the Web'
@@ -32,7 +32,8 @@ uploadcare.namespace 'uploadcare.locale.translations', (ns) ->
32
32
  dropbox: 'Dropbox'
33
33
  gdrive: 'Google Drive'
34
34
  instagram: 'Instagram'
35
- vk: 'Vkontakte'
35
+ vk: 'VK'
36
+ evernote: 'Evernote'
36
37
  url: 'Una dirección cualquiera'
37
38
  url:
38
39
  title: 'Archivos de la web'
@@ -39,6 +39,7 @@ uploadcare.namespace 'uploadcare.locale.translations', (ns) ->
39
39
  gdrive: 'Google Drive'
40
40
  instagram: 'Instagram'
41
41
  vk: 'ВКонтакте'
42
+ evernote: 'Evernote'
42
43
  url: 'Произвольную ссылку'
43
44
  url:
44
45
  title: 'Файлы с других сайтов'
@@ -23,14 +23,14 @@ namespace 'uploadcare.settings', (ns) ->
23
23
  'public-key': null
24
24
  'pusher-key': '79ae88bd931ea68464d9'
25
25
  'social-base': 'https://social.uploadcare.com'
26
- 'tabs': 'file url facebook gdrive instagram'
26
+ 'tabs': 'file url facebook gdrive instagram evernote'
27
27
  'url-base': 'https://upload.uploadcare.com'
28
28
  'script-base': if SCRIPT_BASE? then SCRIPT_BASE else ''
29
29
  'script-ext': '.min.js'
30
30
 
31
31
  presets =
32
32
  'tabs':
33
- all: 'file url facebook vk dropbox gdrive instagram'
33
+ all: 'file url facebook vk dropbox gdrive instagram evernote'
34
34
  default: defaults.tabs
35
35
 
36
36
 
@@ -159,3 +159,20 @@ namespace 'uploadcare.settings', (ns) ->
159
159
  waitForSettingsCb.add (common) ->
160
160
  fn normalize $.extend({}, common, settings or {})
161
161
 
162
+ class ns.CssCollector
163
+ constructor: () ->
164
+ @urls = []
165
+ @styles = []
166
+
167
+ addUrl: (url) ->
168
+ if not /^https?:\/\//i.test(url)
169
+ throw new Error('Embedded urls should be absolute. ' + url)
170
+
171
+ unless url in @urls
172
+ @urls.push url
173
+
174
+ addStyle: (style) ->
175
+ @styles.push style
176
+
177
+ tabsCss = new ns.CssCollector
178
+ expose 'tabsCss', tabsCss
@@ -0,0 +1,3 @@
1
+ <div class="uploadcare-widget-circle-back" role="uploadcare-circle-back">
2
+ <div class="uploadcare-widget-circle-text" role="uploadcare-circle-text"></div>
3
+ </div>
@@ -11,18 +11,20 @@
11
11
  <div class="uploadcare-dialog-big-button" role="uploadcare-dialog-browse-file">
12
12
  <%- t('dialog.tabs.file.button') %>
13
13
  </div>
14
- <div class="uploadcare-dialog-file-or">
15
- <%- t('dialog.tabs.file.also') %>
16
- </div>
17
- <div class="uploadcare-dialog-file-sources">
18
- <% for (var i = 0; i < avalibleTabs.length; i++) {
19
- var tab = avalibleTabs[i];
20
- if (tab == 'file') continue; %>
21
- <div
22
- class="uploadcare-dialog-file-source"
23
- role="uploadcare-dialog-switch-tab"
24
- data-tab="<%- tab %>"
25
- ><%- t('dialog.tabs.file.tabNames.' + tab) %></div>
26
- <% } %>
27
- </div>
14
+ <% if (avalibleTabs.length > 1) { %>
15
+ <div class="uploadcare-dialog-file-or">
16
+ <%- t('dialog.tabs.file.also') %>
17
+ </div>
18
+ <div class="uploadcare-dialog-file-sources">
19
+ <% for (var i = 0; i < avalibleTabs.length; i++) {
20
+ var tab = avalibleTabs[i];
21
+ if (tab == 'file') continue; %>
22
+ <div
23
+ class="uploadcare-dialog-file-source"
24
+ role="uploadcare-dialog-switch-tab"
25
+ data-tab="<%- tab %>"
26
+ ><%- t('dialog.tabs.file.tabNames.' + tab) %></div>
27
+ <% } %>
28
+ </div>
29
+ <% } %>
28
30
  </div>
@@ -1,4 +1,4 @@
1
- <li
2
- role="uploadcare-widget-buttons-<%= name %>"
3
- class="uploadcare-widget-buttons-<%= name %>"
4
- ><%- caption %></li>
1
+ <div
2
+ role="uploadcare-widget-buttons-<%= name %>"
3
+ class="uploadcare-widget-button uploadcare-widget-buttons-<%= name %>"
4
+ ><%- caption %></div>
@@ -1,6 +1,6 @@
1
1
  <div class="uploadcare-widget">
2
2
  <div role="uploadcare-widget-status"></div>
3
3
  <div role="uploadcare-widget-status-text" class="uploadcare-widget-status-text"></div>
4
- <ul role="uploadcare-widget-buttons" class="uploadcare-widget-buttons"></ul>
4
+ <div role="uploadcare-widget-buttons" class="uploadcare-widget-buttons"></div>
5
5
  <div class="uploadcare-widget-dragndrop-area" role="uploadcare-drop-area"><%- t('draghere') %></div>
6
6
  </div>
@@ -1,34 +1,21 @@
1
1
  {
2
2
  namespace,
3
3
  files,
4
- jQuery: $
4
+ jQuery: $,
5
+ utils: {abilities}
5
6
  } = uploadcare
6
7
 
7
8
  {tpl} = uploadcare.templates
8
9
 
9
10
  namespace 'uploadcare.ui.progress', (ns) ->
10
- class ns.Circle
11
- constructor: (@element) ->
12
- # should work with other jqueries
13
- @element = $(@element)
14
-
15
- @element.html(tpl('circle'))
16
- @pie = @element.find('@uploadcare-widget-status')
17
- @center = @element.find('@uploadcare-circle-center')
18
- @element.addClass 'uploadcare-widget-circle'
19
-
20
- @setColorTheme 'default'
21
-
22
- @size = Math.min(@element.width(), @element.height())
23
- @pie.width(@size).height(@size)
24
11
 
25
- @angleOffset = -90
26
- @raphael = @__initRaphael()
27
- @path = @raphael.path()
28
- @path.attr(segment: 0, stroke: false)
29
- @fullDelay = 500 # ms
30
- @__update(0, true)
12
+ class ns.Circle
31
13
 
14
+ constructor: (element) ->
15
+ if abilities.canvas
16
+ @renderer = new ns.CanvasRenderer element
17
+ else
18
+ @renderer = new ns.TextRenderer element
32
19
  @observed = null
33
20
 
34
21
  listen: (file, selector = 'uploadProgress') ->
@@ -41,24 +28,40 @@ namespace 'uploadcare.ui.progress', (ns) ->
41
28
  @observed = file
42
29
 
43
30
  if @observed.state() is "resolved"
44
- @__update 1, true
31
+ @renderer.setValue 1, true
45
32
  else
46
33
  @observed
47
34
  .progress (progress) =>
48
35
  # if we are still listening to this one
49
36
  if file == @observed
50
- @__update selectorFn(progress)
37
+ @renderer.setValue selectorFn(progress)
51
38
 
52
39
  .always (uploadedFile) =>
53
40
  if file == @observed
54
- @__update 1, false
41
+ @renderer.setValue 1, false
55
42
  @
56
43
 
57
-
58
44
  reset: (filled = false) ->
59
45
  @observed = null
60
- @__update (if filled then 100 else 0), true
46
+ @renderer.setValue (if filled then 1 else 0), true
47
+
48
+ setColorTheme: (theme) ->
49
+ @renderer.setColorTheme theme
50
+
51
+
61
52
 
53
+
54
+ class ns.BaseRenderer
55
+ constructor: (el) ->
56
+ @element = $ el
57
+ @element.data 'uploadcare-progress-renderer', this
58
+ @element.addClass 'uploadcare-widget-circle'
59
+ @size = Math.min(@element.width(), @element.height())
60
+ setColorTheme: (theme) ->
61
+ if $.type(theme) is 'string'
62
+ theme = @colorThemes[theme]
63
+ @colorTheme = $.extend {}, @colorThemes.default, theme
64
+ setValue: (value, instant=false) -> throw new Error 'not implemented'
62
65
  colorThemes:
63
66
  default:
64
67
  back: '#e1e5e7'
@@ -71,65 +74,112 @@ namespace 'uploadcare.ui.progress', (ns) ->
71
74
  back: '#bfbfbf'
72
75
  front: '#8c8c8c'
73
76
 
77
+
78
+ class ns.TextRenderer extends ns.BaseRenderer
79
+ constructor: ->
80
+ super
81
+
82
+ $.extend true, @colorThemes, {
83
+ default:
84
+ front: '#000'
85
+ grey:
86
+ front: '#888'
87
+ darkGrey:
88
+ front: '#555'
89
+ }
90
+
91
+ @element.addClass 'uploadcare-widget-circle--text'
92
+ @element.html(tpl('circle-text'))
93
+ @background = @element.find('@uploadcare-circle-back')
94
+ @text = @element.find('@uploadcare-circle-text')
95
+ @setColorTheme 'default'
96
+
97
+
74
98
  setColorTheme: (theme) ->
75
- if $.type(theme) is 'string'
76
- theme = @colorThemes[theme]
77
- @colorTheme = $.extend {}, @colorThemes.default, theme
78
-
79
- @pie.css 'background', @colorTheme.back
80
- @center.css 'background', @colorTheme.center
99
+ super
100
+ @background.css 'background', @colorTheme.back
101
+ @text.css 'color', @colorTheme.front
81
102
 
82
- if @raphael
83
- @__update()
103
+ setValue: (val) ->
104
+ val = Math.round(val * 100)
105
+ @text.html "#{val} %"
84
106
 
85
- __update: (val = @currentVal, instant = false) -> # val in [0..1]
86
- val = 1 if val > 1
87
- @currentVal = val
88
- delay = @fullDelay * Math.abs(val - @value)
89
- @value = val
90
107
 
91
- if instant
92
- @path.attr(segment: @__segmentVal(@value))
93
- else do (value = @value) =>
94
- @path.animate {segment: @__segmentVal(value)}, delay, 'linear', =>
95
- # Revert value to current if changed during animation
96
- @__update(@value, true) if @value != value
97
-
98
- __segmentVal: (value) ->
99
- # Supposed to be = 360 * value,
100
- # but filling to 360 sometimes doesn't work to IE.
101
- # There probably is a correct solution to this.
102
- 360 * if value < 1 then value else 0.99999999
103
-
104
- __initRaphael: ->
105
- raphael = uploadcare.Raphael @pie.get(0), @size, @size
106
- size = @size
107
- angleOffset = @angleOffset
108
-
109
- getColor = =>
110
- @colorTheme.front
111
-
112
- raphael.customAttributes.segment = (angle) ->
113
- x = size / 2
114
- y = size / 2
115
- r = size / 2
116
- a1 = 0
117
- a2 = angle
118
- a1 += angleOffset
119
- a2 += angleOffset
120
-
121
- flag = (a2 - a1) > 180
122
- a1 = (a1 % 360) * Math.PI / 180
123
- a2 -= 0.00001
124
- a2 = (a2 % 360) * Math.PI / 180
125
-
126
- {
127
- path: [
128
- ["M", x, y]
129
- ["l", r * Math.cos(a1), r * Math.sin(a1)]
130
- ["A", r, r, 0, +flag, 1, x + r * Math.cos(a2), y + r * Math.sin(a2)], ["z"]
131
- ]
132
- fill: getColor()
133
- }
134
- return raphael
108
+ class ns.CanvasRenderer extends ns.BaseRenderer
135
109
 
110
+ constructor: ->
111
+ super
112
+
113
+ @canvasSize = @size * 2
114
+
115
+ @element.addClass 'uploadcare-widget-circle--canvas'
116
+ @element.html(tpl('circle-canvas'))
117
+
118
+ @setColorTheme 'default'
119
+ @setValue 0, true
120
+
121
+ @canvasEl = @element.find('canvas')
122
+ .css(width: @size, height: @size)
123
+ .prop(width: @canvasSize, height: @canvasSize)
124
+ @canvasCtx = @canvasEl.get(0).getContext '2d'
125
+
126
+ @__reRender()
127
+
128
+ setColorTheme: (theme) ->
129
+ super
130
+ @__reRender()
131
+
132
+ __reRender: ->
133
+ if @canvasCtx
134
+ ctx = @canvasCtx
135
+ halfSize = @canvasSize/2
136
+
137
+ # Clear
138
+ ctx.clearRect 0, 0, @canvasSize, @canvasSize
139
+
140
+ # Background circle
141
+ ctx.fillStyle = @colorTheme.back
142
+ ctx.beginPath()
143
+ ctx.arc(halfSize, halfSize, halfSize, 0, 2*Math.PI)
144
+ ctx.fill()
145
+
146
+ # Progress circle
147
+ offset = -Math.PI / 2
148
+ ctx.fillStyle = @colorTheme.front
149
+ ctx.beginPath()
150
+ ctx.moveTo(halfSize, halfSize)
151
+ ctx.arc(halfSize, halfSize, halfSize, offset, 2*Math.PI * @val + offset)
152
+ ctx.fill()
153
+
154
+ # Center circle
155
+ ctx.fillStyle = @colorTheme.center
156
+ ctx.beginPath()
157
+ ctx.arc(halfSize, halfSize, @canvasSize/15, 0, 2*Math.PI)
158
+ ctx.fill()
159
+
160
+ __animateValue: (targetValue) ->
161
+ perStep = if targetValue > @val then 0.05 else -0.05
162
+ @__animIntervalId = setInterval =>
163
+ newValue = @val + perStep
164
+ if (perStep > 0 and newValue > targetValue) or (perStep < 0 and newValue < targetValue)
165
+ newValue = targetValue
166
+ if newValue == targetValue
167
+ @__stopAnimation()
168
+ @__setValue newValue
169
+ , 25
170
+
171
+ __stopAnimation: ->
172
+ if @__animIntervalId
173
+ clearInterval @__animIntervalId
174
+ @__animIntervalId = null
175
+
176
+ __setValue: (val) ->
177
+ @val = val
178
+ @__reRender()
179
+
180
+ setValue: (val, instant = false) ->
181
+ @__stopAnimation()
182
+ if instant
183
+ @__setValue(val)
184
+ else
185
+ @__animateValue(val)