caboose-cms 0.5.221 → 0.5.222

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +8 -8
  2. data/app/assets/javascripts/caboose/admin_media_index.js +401 -0
  3. data/app/assets/javascripts/caboose/jquery-ui.drag-multiple.min.js +4 -0
  4. data/app/assets/javascripts/plupload/Moxie.swf +0 -0
  5. data/app/assets/javascripts/plupload/Moxie.xap +0 -0
  6. data/app/assets/javascripts/plupload/i18n/ar.js +2 -0
  7. data/app/assets/javascripts/plupload/i18n/az.js +2 -0
  8. data/app/assets/javascripts/plupload/i18n/bg.js +2 -0
  9. data/app/assets/javascripts/plupload/i18n/bs.js +2 -0
  10. data/app/assets/javascripts/plupload/i18n/ca.js +2 -0
  11. data/app/assets/javascripts/plupload/i18n/cs.js +2 -0
  12. data/app/assets/javascripts/plupload/i18n/cy.js +2 -0
  13. data/app/assets/javascripts/plupload/i18n/da.js +2 -0
  14. data/app/assets/javascripts/plupload/i18n/de.js +2 -0
  15. data/app/assets/javascripts/plupload/i18n/el.js +2 -0
  16. data/app/assets/javascripts/plupload/i18n/en.js +2 -0
  17. data/app/assets/javascripts/plupload/i18n/es.js +2 -0
  18. data/app/assets/javascripts/plupload/i18n/et.js +2 -0
  19. data/app/assets/javascripts/plupload/i18n/fa.js +2 -0
  20. data/app/assets/javascripts/plupload/i18n/fi.js +2 -0
  21. data/app/assets/javascripts/plupload/i18n/fr.js +2 -0
  22. data/app/assets/javascripts/plupload/i18n/he.js +2 -0
  23. data/app/assets/javascripts/plupload/i18n/hr.js +2 -0
  24. data/app/assets/javascripts/plupload/i18n/hu.js +2 -0
  25. data/app/assets/javascripts/plupload/i18n/hy.js +2 -0
  26. data/app/assets/javascripts/plupload/i18n/id.js +2 -0
  27. data/app/assets/javascripts/plupload/i18n/it.js +2 -0
  28. data/app/assets/javascripts/plupload/i18n/ja.js +2 -0
  29. data/app/assets/javascripts/plupload/i18n/ka.js +2 -0
  30. data/app/assets/javascripts/plupload/i18n/kk.js +2 -0
  31. data/app/assets/javascripts/plupload/i18n/km.js +2 -0
  32. data/app/assets/javascripts/plupload/i18n/ko.js +2 -0
  33. data/app/assets/javascripts/plupload/i18n/ku_IQ.js +2 -0
  34. data/app/assets/javascripts/plupload/i18n/lt.js +2 -0
  35. data/app/assets/javascripts/plupload/i18n/lv.js +2 -0
  36. data/app/assets/javascripts/plupload/i18n/mn.js +2 -0
  37. data/app/assets/javascripts/plupload/i18n/ms.js +2 -0
  38. data/app/assets/javascripts/plupload/i18n/nl.js +2 -0
  39. data/app/assets/javascripts/plupload/i18n/pl.js +2 -0
  40. data/app/assets/javascripts/plupload/i18n/pt_BR.js +2 -0
  41. data/app/assets/javascripts/plupload/i18n/ro.js +2 -0
  42. data/app/assets/javascripts/plupload/i18n/ru.js +2 -0
  43. data/app/assets/javascripts/plupload/i18n/sk.js +2 -0
  44. data/app/assets/javascripts/plupload/i18n/sq.js +2 -0
  45. data/app/assets/javascripts/plupload/i18n/sr.js +2 -0
  46. data/app/assets/javascripts/plupload/i18n/sr_RS.js +2 -0
  47. data/app/assets/javascripts/plupload/i18n/sv.js +2 -0
  48. data/app/assets/javascripts/plupload/i18n/th_TH.js +2 -0
  49. data/app/assets/javascripts/plupload/i18n/tr.js +2 -0
  50. data/app/assets/javascripts/plupload/i18n/uk_UA.js +2 -0
  51. data/app/assets/javascripts/plupload/i18n/vi.js +2 -0
  52. data/app/assets/javascripts/plupload/i18n/zh_CN.js +2 -0
  53. data/app/assets/javascripts/plupload/i18n/zh_TW.js +2 -0
  54. data/app/assets/javascripts/plupload/jquery.plupload.queue/css/jquery.plupload.queue.css +185 -0
  55. data/app/assets/javascripts/plupload/jquery.plupload.queue/img/backgrounds.gif +0 -0
  56. data/app/assets/javascripts/plupload/jquery.plupload.queue/img/buttons-disabled.png +0 -0
  57. data/app/assets/javascripts/plupload/jquery.plupload.queue/img/buttons.png +0 -0
  58. data/app/assets/javascripts/plupload/jquery.plupload.queue/img/delete.gif +0 -0
  59. data/app/assets/javascripts/plupload/jquery.plupload.queue/img/done.gif +0 -0
  60. data/app/assets/javascripts/plupload/jquery.plupload.queue/img/error.gif +0 -0
  61. data/app/assets/javascripts/plupload/jquery.plupload.queue/img/throbber.gif +0 -0
  62. data/app/assets/javascripts/plupload/jquery.plupload.queue/img/transp50.png +0 -0
  63. data/app/assets/javascripts/plupload/jquery.plupload.queue/jquery.plupload.queue.js +428 -0
  64. data/app/assets/javascripts/plupload/jquery.plupload.queue/jquery.plupload.queue.min.js +1 -0
  65. data/app/assets/javascripts/plupload/jquery.ui.plupload/css/jquery.ui.plupload.css +370 -0
  66. data/app/assets/javascripts/plupload/jquery.ui.plupload/img/loading.gif +0 -0
  67. data/app/assets/javascripts/plupload/jquery.ui.plupload/img/plupload.png +0 -0
  68. data/app/assets/javascripts/plupload/jquery.ui.plupload/jquery.ui.plupload.js +1323 -0
  69. data/app/assets/javascripts/plupload/jquery.ui.plupload/jquery.ui.plupload.min.js +1 -0
  70. data/app/assets/javascripts/plupload/moxie.js +10726 -0
  71. data/app/assets/javascripts/plupload/moxie.min.js +15 -0
  72. data/app/assets/javascripts/plupload/plupload.dev.js +2315 -0
  73. data/app/assets/javascripts/plupload/plupload.full.min.js +28 -0
  74. data/app/assets/javascripts/plupload/plupload.min.js +13 -0
  75. data/app/assets/stylesheets/caboose/admin_media_index.css.scss +115 -0
  76. data/app/controllers/caboose/application_controller.rb +1 -1
  77. data/app/controllers/caboose/cart_controller.rb +1 -1
  78. data/app/controllers/caboose/media_categories_controller.rb +44 -8
  79. data/app/controllers/caboose/media_controller.rb +116 -0
  80. data/app/controllers/caboose/posts_controller.rb +1 -1
  81. data/app/controllers/caboose/sns_controller.rb +60 -0
  82. data/app/models/caboose/block.rb +4 -2
  83. data/app/models/caboose/media.rb +94 -0
  84. data/app/models/caboose/media_category.rb +55 -15
  85. data/app/models/caboose/schema.rb +6 -9
  86. data/app/models/caboose/tax_calculator.rb +1 -1
  87. data/app/views/caboose/{images → media}/admin_edit.html.erb +0 -0
  88. data/app/views/caboose/media/admin_index.html.erb +49 -0
  89. data/app/views/caboose/posts/admin_edit_general.html.erb +3 -1
  90. data/config/routes.rb +30 -17
  91. data/lib/caboose.rb +6 -0
  92. data/lib/caboose/version.rb +1 -1
  93. metadata +81 -11
  94. data/app/assets/javascripts/caboose/admin_images_index.js +0 -171
  95. data/app/assets/stylesheets/caboose/admin_images_index.css.scss +0 -53
  96. data/app/controllers/caboose/images_controller.rb +0 -149
  97. data/app/models/caboose/media_file.rb +0 -18
  98. data/app/models/caboose/media_image.rb +0 -43
  99. data/app/views/caboose/images/admin_index.html.erb +0 -59
  100. data/app/views/caboose/images/admin_new.html.erb +0 -80
  101. data/app/views/caboose/images/admin_s3_result.html.erb +0 -3
@@ -0,0 +1 @@
1
+ ;(function(e,t){function r(e){return plupload.translate(e)||e}function i(t,n){n.contents().each(function(t,n){n=e(n),n.is(".plupload")||n.remove()}),n.prepend('<div class="plupload_wrapper plupload_scroll"><div id="'+t+'_container" class="plupload_container">'+'<div class="plupload">'+'<div class="plupload_header">'+'<div class="plupload_header_content">'+'<div class="plupload_header_title">'+r("Select files")+"</div>"+'<div class="plupload_header_text">'+r("Add files to the upload queue and click the start button.")+"</div>"+"</div>"+"</div>"+'<div class="plupload_content">'+'<div class="plupload_filelist_header">'+'<div class="plupload_file_name">'+r("Filename")+"</div>"+'<div class="plupload_file_action">&nbsp;</div>'+'<div class="plupload_file_status"><span>'+r("Status")+"</span></div>"+'<div class="plupload_file_size">'+r("Size")+"</div>"+'<div class="plupload_clearer">&nbsp;</div>'+"</div>"+'<ul id="'+t+'_filelist" class="plupload_filelist"></ul>'+'<div class="plupload_filelist_footer">'+'<div class="plupload_file_name">'+'<div class="plupload_buttons">'+'<a href="#" class="plupload_button plupload_add" id="'+t+'_browse">'+r("Add Files")+"</a>"+'<a href="#" class="plupload_button plupload_start">'+r("Start Upload")+"</a>"+"</div>"+'<span class="plupload_upload_status"></span>'+"</div>"+'<div class="plupload_file_action"></div>'+'<div class="plupload_file_status"><span class="plupload_total_status">0%</span></div>'+'<div class="plupload_file_size"><span class="plupload_total_file_size">0 b</span></div>'+'<div class="plupload_progress">'+'<div class="plupload_progress_container">'+'<div class="plupload_progress_bar"></div>'+"</div>"+"</div>"+'<div class="plupload_clearer">&nbsp;</div>'+"</div>"+"</div>"+"</div>"+"</div>"+'<input type="hidden" id="'+t+'_count" name="'+t+'_count" value="0" />'+"</div>")}var n={};e.fn.pluploadQueue=function(s){return s?(this.each(function(){function c(t){var n;t.status==plupload.DONE&&(n="plupload_done"),t.status==plupload.FAILED&&(n="plupload_failed"),t.status==plupload.QUEUED&&(n="plupload_delete"),t.status==plupload.UPLOADING&&(n="plupload_uploading");var r=e("#"+t.id).attr("class",n).find("a").css("display","block");t.hint&&r.attr("title",t.hint)}function h(){e("span.plupload_total_status",a).html(u.total.percent+"%"),e("div.plupload_progress_bar",a).css("width",u.total.percent+"%"),e("span.plupload_upload_status",a).html(t.sprintf(r("Uploaded %d/%d files"),u.total.uploaded,u.files.length))}function p(){var n=e("ul.plupload_filelist",a).html(""),i=0,s;e.each(u.files,function(t,r){s="",r.status==plupload.DONE&&(r.target_name&&(s+='<input type="hidden" name="'+f+"_"+i+'_tmpname" value="'+plupload.xmlEncode(r.target_name)+'" />'),s+='<input type="hidden" name="'+f+"_"+i+'_name" value="'+plupload.xmlEncode(r.name)+'" />',s+='<input type="hidden" name="'+f+"_"+i+'_status" value="'+(r.status==plupload.DONE?"done":"failed")+'" />',i++,e("#"+f+"_count").val(i)),n.append('<li id="'+r.id+'">'+'<div class="plupload_file_name"><span>'+r.name+"</span></div>"+'<div class="plupload_file_action"><a href="#"></a></div>'+'<div class="plupload_file_status">'+r.percent+"%</div>"+'<div class="plupload_file_size">'+plupload.formatSize(r.size)+"</div>"+'<div class="plupload_clearer">&nbsp;</div>'+s+"</li>"),c(r),e("#"+r.id+".plupload_delete a").click(function(t){e("#"+r.id).remove(),u.removeFile(r),t.preventDefault()})}),e("span.plupload_total_file_size",a).html(plupload.formatSize(u.total.size)),u.total.queued===0?e("span.plupload_add_text",a).html(r("Add Files")):e("span.plupload_add_text",a).html(t.sprintf(r("%d files queued"),u.total.queued)),e("a.plupload_start",a).toggleClass("plupload_disabled",u.files.length==u.total.uploaded+u.total.failed),n[0].scrollTop=n[0].scrollHeight,h(),!u.files.length&&u.features.dragdrop&&u.settings.dragdrop&&e("#"+f+"_filelist").append('<li class="plupload_droptext">'+r("Drag files here.")+"</li>")}function d(){delete n[f],u.destroy(),a.html(l),u=a=l=null}var u,a,f,l;a=e(this),f=a.attr("id"),f||(f=plupload.guid(),a.attr("id",f)),l=a.html(),i(f,a),s=e.extend({dragdrop:!0,browse_button:f+"_browse",container:f},s),s.dragdrop&&(s.drop_element=f+"_filelist"),u=new plupload.Uploader(s),n[f]=u,u.bind("UploadFile",function(t,n){e("#"+n.id).addClass("plupload_current_file")}),u.bind("Init",function(t,n){!s.unique_names&&s.rename&&a.on("click","#"+f+"_filelist div.plupload_file_name span",function(n){var r=e(n.target),i,s,o,u="";i=t.getFile(r.parents("li")[0].id),o=i.name,s=/^(.+)(\.[^.]+)$/.exec(o),s&&(o=s[1],u=s[2]),r.hide().after('<input type="text" />'),r.next().val(o).focus().blur(function(){r.show().next().remove()}).keydown(function(t){var n=e(this);t.keyCode==13&&(t.preventDefault(),i.name=n.val()+u,r.html(i.name),n.blur())})}),e("#"+f+"_container").attr("title","Using runtime: "+n.runtime),e("a.plupload_start",a).click(function(t){e(this).hasClass("plupload_disabled")||u.start(),t.preventDefault()}),e("a.plupload_stop",a).click(function(e){e.preventDefault(),u.stop()}),e("a.plupload_start",a).addClass("plupload_disabled")}),u.bind("Error",function(t,n){var i=n.file,s;i&&(s=n.message,n.details&&(s+=" ("+n.details+")"),n.code==plupload.FILE_SIZE_ERROR&&alert(r("Error: File too large:")+" "+i.name),n.code==plupload.FILE_EXTENSION_ERROR&&alert(r("Error: Invalid file extension:")+" "+i.name),i.hint=s,e("#"+i.id).attr("class","plupload_failed").find("a").css("display","block").attr("title",s)),n.code===plupload.INIT_ERROR&&setTimeout(function(){d()},1)}),u.bind("PostInit",function(t){t.settings.dragdrop&&t.features.dragdrop&&e("#"+f+"_filelist").append('<li class="plupload_droptext">'+r("Drag files here.")+"</li>")}),u.init(),u.bind("StateChanged",function(){u.state===plupload.STARTED?(e("li.plupload_delete a,div.plupload_buttons",a).hide(),u.disableBrowse(!0),e("span.plupload_upload_status,div.plupload_progress,a.plupload_stop",a).css("display","block"),e("span.plupload_upload_status",a).html("Uploaded "+u.total.uploaded+"/"+u.files.length+" files"),s.multiple_queues&&e("span.plupload_total_status,span.plupload_total_file_size",a).show()):(p(),e("a.plupload_stop,div.plupload_progress",a).hide(),e("a.plupload_delete",a).css("display","block"),s.multiple_queues&&u.total.uploaded+u.total.failed==u.files.length&&(e(".plupload_buttons,.plupload_upload_status",a).css("display","inline"),u.disableBrowse(!1),e(".plupload_start",a).addClass("plupload_disabled"),e("span.plupload_total_status,span.plupload_total_file_size",a).hide()))}),u.bind("FilesAdded",p),u.bind("FilesRemoved",function(){var t=e("#"+f+"_filelist").scrollTop();p(),e("#"+f+"_filelist").scrollTop(t)}),u.bind("FileUploaded",function(e,t){c(t)}),u.bind("UploadProgress",function(t,n){e("#"+n.id+" div.plupload_file_status",a).html(n.percent+"%"),c(n),h()}),s.setup&&s.setup(u)}),this):n[e(this[0]).attr("id")]}})(jQuery,mOxie);
@@ -0,0 +1,370 @@
1
+ /*
2
+ Plupload
3
+ ------------------------------------------------------------------- */
4
+
5
+ .plupload_wrapper * {
6
+ box-sizing: content-box;
7
+ }
8
+
9
+ .plupload_button {
10
+ cursor: pointer;
11
+ outline: none;
12
+ }
13
+
14
+ .plupload_wrapper {
15
+ font: normal 11px Verdana,sans-serif;
16
+ width: 100%;
17
+ min-width: 520px;
18
+ line-height: 12px;
19
+ }
20
+
21
+ .plupload_container {
22
+ _height: 300px;
23
+ min-height: 300px;
24
+ position: relative;
25
+ }
26
+
27
+ .plupload_filelist_footer {border-width: 1px 0 0 0}
28
+ .plupload_file {border-width: 0 0 1px 0}
29
+ .plupload_container .plupload_header {border-width: 0 0 1px 0; position: relative;}
30
+
31
+ .plupload_delete .ui-icon,
32
+ .plupload_done .ui-icon,
33
+ .plupload_failed .ui-icon {
34
+ cursor:pointer;
35
+ }
36
+
37
+ .plupload_header_content {
38
+ height: 56px;
39
+ padding: 0 160px 0 60px;
40
+ position: relative;
41
+ }
42
+
43
+ .plupload_logo {
44
+ width: 40px;
45
+ height: 40px;
46
+ background: url('../img/plupload.png') no-repeat 0 0;
47
+ position: absolute;
48
+ top: 8px;
49
+ left: 8px;
50
+ }
51
+
52
+ .plupload_header_content_bw .plupload_logo {
53
+ background-position: -40px 0;
54
+ }
55
+
56
+ .plupload_header_title {
57
+ font: normal 18px sans-serif;
58
+ line-height: 19px;
59
+ padding: 6px 0 3px;
60
+ }
61
+
62
+ .plupload_header_text {
63
+ font: normal 12px sans-serif;
64
+ }
65
+
66
+ .plupload_view_switch {
67
+ position: absolute;
68
+ right: 16px;
69
+ bottom: 8px;
70
+ margin: 0;
71
+ display: none;
72
+ }
73
+
74
+ .plupload_view_switch .ui-button {
75
+ margin-right: -0.31em;
76
+ }
77
+
78
+ .plupload_content {
79
+ position: absolute;
80
+ top: 86px;
81
+ bottom: 44px;
82
+ left: 0;
83
+ right: 0;
84
+ overflow-y: auto;
85
+ width: 100%;
86
+ }
87
+
88
+ .plupload_filelist {
89
+ border-collapse: collapse;
90
+ border-left: none;
91
+ border-right: none;
92
+ margin: 0;
93
+ padding: 0;
94
+ width: 100%;
95
+ -moz-user-select: none;
96
+ -webkit-user-select: none;
97
+ user-select: none;
98
+ }
99
+
100
+ .plupload_filelist_content {
101
+ padding: 0;
102
+ margin: 0;
103
+ }
104
+
105
+ .plupload_cell {padding: 8px 6px;}
106
+
107
+ .plupload_file {
108
+ list-style: none;
109
+ display: block;
110
+ position: relative;
111
+ overflow: hidden;
112
+ line-height: 12px;
113
+ }
114
+
115
+ .plupload_file_thumb {
116
+ position: relative;
117
+ background-image: none;
118
+ background-color: #eee;
119
+ }
120
+
121
+ .plupload_file_loading .plupload_file_thumb {
122
+ background: #eee url(../img/loading.gif) center no-repeat;
123
+ }
124
+
125
+ .plupload_file_name {
126
+ overflow: hidden;
127
+ text-overflow: ellipsis;
128
+ white-space: nowrap;
129
+ }
130
+
131
+ .plupload_filelist_header {
132
+ border-top: none;
133
+ }
134
+
135
+ .plupload_filelist_footer {
136
+ position: absolute;
137
+ bottom: 0;
138
+ left: 0;
139
+ right: 0;
140
+ }
141
+
142
+ .plupload_buttons {
143
+ position: relative;
144
+ }
145
+
146
+ /* list view */
147
+ .plupload_view_list .plupload_file {
148
+ border-left: none;
149
+ border-right: none;
150
+ border-top: none;
151
+ height: 29px;
152
+ width: 100% !important;
153
+ /* fix IE6 vertical white-space bug */
154
+ _float: left;
155
+ _clear: left;
156
+ }
157
+
158
+ .plupload_view_list div.plupload_file_size,
159
+ .plupload_view_list div.plupload_file_status,
160
+ .plupload_view_list div.plupload_file_action {
161
+ padding: 8px 6px;
162
+ position: absolute;
163
+ top: 0;
164
+ right: 0;
165
+ }
166
+
167
+ .plupload_view_list div.plupload_file_name {
168
+ margin-right: 156px;
169
+ padding: 8px 6px;
170
+ _width: 75%;
171
+ }
172
+
173
+ .plupload_view_list div.plupload_file_size {
174
+ right: 28px;
175
+ }
176
+
177
+ .plupload_view_list div.plupload_file_status {
178
+ right: 82px;
179
+ }
180
+
181
+ .plupload_view_list .plupload_file_rename {
182
+ margin-left: -2px;
183
+ }
184
+
185
+ .plupload_view_list .plupload_file_size,
186
+ .plupload_view_list .plupload_file_status,
187
+ .plupload_filelist_footer .plupload_file_size,
188
+ .plupload_filelist_footer .plupload_file_status {
189
+ text-align: right;
190
+ width: 52px;
191
+ }
192
+
193
+ .plupload_view_list .plupload_file_thumb {
194
+ position: absolute;
195
+ top: -999px;
196
+ }
197
+
198
+ .plupload_view_list .plupload_file_progress {
199
+ display: none;
200
+ }
201
+
202
+
203
+ /* thumbs view */
204
+ .plupload_view_thumbs .plupload_content {
205
+ top: 57px;
206
+ }
207
+
208
+ .plupload_view_thumbs .plupload_filelist_header {
209
+ display: none;
210
+ }
211
+
212
+ .plupload_view_thumbs .plupload_file {
213
+ padding: 6px;
214
+ margin: 10px;
215
+ border: 1px solid #fff;
216
+ float: left;
217
+ }
218
+
219
+ .plupload_view_thumbs .plupload_file_thumb,
220
+ .plupload_view_thumbs .plupload_file_dummy {
221
+ text-align: center;
222
+ overflow: hidden;
223
+ }
224
+
225
+ .plupload_view_thumbs .plupload_file_dummy {
226
+ font-size: 21px;
227
+ font-weight: bold;
228
+ text-transform: lowercase;
229
+ overflow: hidden;
230
+ border: none;
231
+ position: absolute;
232
+ top: 0;
233
+ left: 0;
234
+ width: 100%;
235
+ height: 100%;
236
+ }
237
+
238
+ .plupload_view_thumbs div.plupload_file_action {
239
+ position: absolute;
240
+ top: 0;
241
+ right: 0;
242
+ }
243
+
244
+ .plupload_view_thumbs div.plupload_file_name {
245
+ padding: 0;
246
+ font-weight: bold;
247
+ }
248
+
249
+ .plupload_view_thumbs .plupload_file_rename {
250
+ padding: 1px 0;
251
+ width: 100% !important;
252
+ }
253
+
254
+ .plupload_view_thumbs div.plupload_file_size {
255
+ font-size: 0.8em;
256
+ font-weight: normal;
257
+ }
258
+
259
+ .plupload_view_thumbs div.plupload_file_status {
260
+ position: relative;
261
+ height: 3px;
262
+ overflow: hidden;
263
+ text-indent: -999px;
264
+ margin-bottom: 3px;
265
+ }
266
+
267
+ .plupload_view_thumbs div.plupload_file_progress {
268
+ border: none;
269
+ height: 100%;
270
+ }
271
+
272
+ .plupload .ui-sortable-helper,
273
+ .plupload .ui-sortable .plupload_file {
274
+ cursor:move;
275
+ }
276
+
277
+ .plupload_file_action {width: 16px;}
278
+ .plupload_file_name {
279
+ overflow: hidden;
280
+ padding-left: 10px;
281
+ }
282
+
283
+ .plupload_file_rename {
284
+ border: none;
285
+ font: normal 11px Verdana, sans-serif;
286
+ padding: 1px 2px;
287
+ line-height: 11px;
288
+ height: 11px;
289
+ }
290
+
291
+ .plupload_progress {width: 60px;}
292
+ .plupload_progress_container {padding: 1px;}
293
+
294
+
295
+ /* Floats */
296
+
297
+ .plupload_right {float: right;}
298
+ .plupload_left {float: left;}
299
+ .plupload_clear,.plupload_clearer {clear: both;}
300
+ .plupload_clearer, .plupload_progress_bar {
301
+ display: block;
302
+ font-size: 0;
303
+ line-height: 0;
304
+ }
305
+ .plupload_clearer {height: 0;}
306
+
307
+ /* Misc */
308
+ .plupload_hidden {display: none !important;}
309
+
310
+ .plupload_droptext {
311
+ position: absolute;
312
+ top: 0;
313
+ left: 0;
314
+ right: 0;
315
+ bottom: 0;
316
+ background: transparent;
317
+ text-align: center;
318
+ vertical-align: middle;
319
+ border: 0;
320
+ line-height: 160px;
321
+ display: none;
322
+ }
323
+
324
+ .plupload_dropbox .plupload_droptext {
325
+ display: block;
326
+ }
327
+
328
+ .plupload_buttons, .plupload_upload_status {float: left}
329
+
330
+ .plupload_message {
331
+ position: absolute;
332
+ top: -1px;
333
+ left: -1px;
334
+ height: 100%;
335
+ width: 100%;
336
+ }
337
+
338
+ .plupload_message p {
339
+ padding:0.7em;
340
+ margin:0;
341
+ }
342
+
343
+ .plupload_message strong {
344
+ font-weight: bold;
345
+ }
346
+
347
+ plupload_message i {
348
+ font-style: italic;
349
+ }
350
+
351
+ .plupload_message p span.ui-icon {
352
+ float: left;
353
+ margin-right: 0.3em;
354
+ }
355
+
356
+ .plupload_header_content .ui-state-error,
357
+ .plupload_header_content .ui-state-highlight {
358
+ border:none;
359
+ }
360
+
361
+ .plupload_message_close {
362
+ position:absolute;
363
+ top:5px;
364
+ right:5px;
365
+ cursor:pointer;
366
+ }
367
+
368
+ .plupload .ui-sortable-placeholder {
369
+ height:35px;
370
+ }
@@ -0,0 +1,1323 @@
1
+ /**
2
+ * jquery.ui.plupload.js
3
+ *
4
+ * Copyright 2013, Moxiecode Systems AB
5
+ * Released under GPL License.
6
+ *
7
+ * License: http://www.plupload.com/license
8
+ * Contributing: http://www.plupload.com/contributing
9
+ *
10
+ * Depends:
11
+ * jquery.ui.core.js
12
+ * jquery.ui.widget.js
13
+ * jquery.ui.button.js
14
+ * jquery.ui.progressbar.js
15
+ *
16
+ * Optionally:
17
+ * jquery.ui.sortable.js
18
+ */
19
+
20
+ /* global jQuery:true */
21
+
22
+ /**
23
+ jQuery UI based implementation of the Plupload API - multi-runtime file uploading API.
24
+
25
+ To use the widget you must include _jQuery_ and _jQuery UI_ bundle (including `ui.core`, `ui.widget`, `ui.button`,
26
+ `ui.progressbar` and `ui.sortable`).
27
+
28
+ In general the widget is designed the way that you do not usually need to do anything to it after you instantiate it.
29
+ But! You still can intervenue, to some extent, in case you need to. Although, due to the fact that widget is based on
30
+ _jQuery UI_ widget factory, there are some specifics. See examples below for more details.
31
+
32
+ @example
33
+ <!-- Instantiating: -->
34
+ <div id="uploader">
35
+ <p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
36
+ </div>
37
+
38
+ <script>
39
+ $('#uploader').plupload({
40
+ url : '../upload.php',
41
+ filters : [
42
+ {title : "Image files", extensions : "jpg,gif,png"}
43
+ ],
44
+ rename: true,
45
+ sortable: true,
46
+ flash_swf_url : '../../js/Moxie.swf',
47
+ silverlight_xap_url : '../../js/Moxie.xap',
48
+ });
49
+ </script>
50
+
51
+ @example
52
+ // Invoking methods:
53
+ $('#uploader').plupload(options);
54
+
55
+ // Display welcome message in the notification area
56
+ $('#uploader').plupload('notify', 'info', "This might be obvious, but you need to click 'Add Files' to add some files.");
57
+
58
+ @example
59
+ // Subscribing to the events...
60
+ // ... on initialization:
61
+ $('#uploader').plupload({
62
+ ...
63
+ viewchanged: function(event, args) {
64
+ // stuff ...
65
+ }
66
+ });
67
+ // ... or after initialization
68
+ $('#uploader').on("viewchanged", function(event, args) {
69
+ // stuff ...
70
+ });
71
+
72
+ @class UI.Plupload
73
+ @constructor
74
+ @param {Object} settings For detailed information about each option check documentation.
75
+ @param {String} settings.url URL of the server-side upload handler.
76
+ @param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled.
77
+ @param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.
78
+ @param {Object} [settings.filters={}] Set of file type filters.
79
+ @param {Array} [settings.filters.mime_types=[]] List of file types to accept, each one defined by title and list of extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`
80
+ @param {String|Number} [settings.filters.max_file_size=0] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
81
+ @param {Boolean} [settings.filters.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
82
+ @param {Number} [settings.filters.max_file_count=0] Limit the number of files that can reside in the queue at the same time (default is 0 - no limit).
83
+ @param {String} [settings.flash_swf_url] URL of the Flash swf.
84
+ @param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.
85
+ @param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
86
+ @param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.
87
+ @param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.
88
+ @param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.
89
+ @param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.
90
+ @param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
91
+ @param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.
92
+ @param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}`
93
+ @param {Number} [settings.resize.width] If image is bigger, it will be resized.
94
+ @param {Number} [settings.resize.height] If image is bigger, it will be resized.
95
+ @param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).
96
+ @param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.
97
+ @param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.
98
+ @param {String} [settings.silverlight_xap_url] URL of the Silverlight xap.
99
+ @param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.
100
+
101
+ @param {Boolean} [settings.autostart=false] Whether to auto start uploading right after file selection.
102
+ @param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop.
103
+ @param {Boolean} [settings.rename=false] Enable ability to rename files in the queue.
104
+ @param {Boolean} [settings.sortable=false] Enable ability to sort files in the queue, changing their uploading priority.
105
+ @param {Object} [settings.buttons] Control the visibility of functional buttons.
106
+ @param {Boolean} [settings.buttons.browse=true] Display browse button.
107
+ @param {Boolean} [settings.buttons.start=true] Display start button.
108
+ @param {Boolean} [settings.buttons.stop=true] Display stop button.
109
+ @param {Object} [settings.views] Control various views of the file queue.
110
+ @param {Boolean} [settings.views.list=true] Enable list view.
111
+ @param {Boolean} [settings.views.thumbs=false] Enable thumbs view.
112
+ @param {String} [settings.views.default='list'] Default view.
113
+ @param {Boolean} [settings.views.remember=true] Whether to remember the current view (requires jQuery Cookie plugin).
114
+ @param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure.
115
+ */
116
+ ;(function(window, document, plupload, o, $) {
117
+
118
+ /**
119
+ Dispatched when the widget is initialized and ready.
120
+
121
+ @event ready
122
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
123
+ */
124
+
125
+ /**
126
+ Dispatched when file dialog is closed.
127
+
128
+ @event selected
129
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
130
+ @param {Array} files Array of selected files represented by plupload.File objects
131
+ */
132
+
133
+ /**
134
+ Dispatched when file dialog is closed.
135
+
136
+ @event removed
137
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
138
+ @param {Array} files Array of removed files represented by plupload.File objects
139
+ */
140
+
141
+ /**
142
+ Dispatched when upload is started.
143
+
144
+ @event start
145
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
146
+ */
147
+
148
+ /**
149
+ Dispatched when upload is stopped.
150
+
151
+ @event stop
152
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
153
+ */
154
+
155
+ /**
156
+ Dispatched during the upload process.
157
+
158
+ @event progress
159
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
160
+ @param {plupload.File} file File that is being uploaded (includes loaded and percent properties among others).
161
+ @param {Number} size Total file size in bytes.
162
+ @param {Number} loaded Number of bytes uploaded of the files total size.
163
+ @param {Number} percent Number of percentage uploaded of the file.
164
+ */
165
+
166
+ /**
167
+ Dispatched when file is uploaded.
168
+
169
+ @event uploaded
170
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
171
+ @param {plupload.File} file File that was uploaded.
172
+ @param {Enum} status Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
173
+ */
174
+
175
+ /**
176
+ Dispatched when upload of the whole queue is complete.
177
+
178
+ @event complete
179
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
180
+ @param {Array} files Array of uploaded files represented by plupload.File objects
181
+ */
182
+
183
+ /**
184
+ Dispatched when the view is changed, e.g. from `list` to `thumbs` or vice versa.
185
+
186
+ @event viewchanged
187
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
188
+ @param {String} type Current view type.
189
+ */
190
+
191
+ /**
192
+ Dispatched when error of some kind is detected.
193
+
194
+ @event error
195
+ @param {plupload.Uploader} uploader Uploader instance sending the event.
196
+ @param {String} error Error message.
197
+ @param {plupload.File} file File that was uploaded.
198
+ @param {Enum} status Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.
199
+ */
200
+
201
+ var uploaders = {};
202
+
203
+ function _(str) {
204
+ return plupload.translate(str) || str;
205
+ }
206
+
207
+ function renderUI(obj) {
208
+ obj.id = obj.attr('id');
209
+
210
+ obj.html(
211
+ '<div class="plupload_wrapper">' +
212
+ '<div class="ui-widget-content plupload_container">' +
213
+ '<div class="ui-state-default ui-widget-header plupload_header">' +
214
+ '<div class="plupload_header_content">' +
215
+ '<div class="plupload_logo"> </div>' +
216
+ '<div class="plupload_header_title">' + _("Select files") + '</div>' +
217
+ '<div class="plupload_header_text">' + _("Add files to the upload queue and click the start button.") + '</div>' +
218
+ '<div class="plupload_view_switch">' +
219
+ '<input type="radio" id="'+obj.id+'_view_list" name="view_mode_'+obj.id+'" checked="checked" /><label class="plupload_button" for="'+obj.id+'_view_list" data-view="list">' + _('List') + '</label>' +
220
+ '<input type="radio" id="'+obj.id+'_view_thumbs" name="view_mode_'+obj.id+'" /><label class="plupload_button" for="'+obj.id+'_view_thumbs" data-view="thumbs">' + _('Thumbnails') + '</label>' +
221
+ '</div>' +
222
+ '</div>' +
223
+ '</div>' +
224
+
225
+ '<table class="plupload_filelist plupload_filelist_header ui-widget-header">' +
226
+ '<tr>' +
227
+ '<td class="plupload_cell plupload_file_name">' + _('Filename') + '</td>' +
228
+ '<td class="plupload_cell plupload_file_status">' + _('Status') + '</td>' +
229
+ '<td class="plupload_cell plupload_file_size">' + _('Size') + '</td>' +
230
+ '<td class="plupload_cell plupload_file_action">&nbsp;</td>' +
231
+ '</tr>' +
232
+ '</table>' +
233
+
234
+ '<div class="plupload_content">' +
235
+ '<div class="plupload_droptext">' + _("Drag files here.") + '</div>' +
236
+ '<ul class="plupload_filelist_content"> </ul>' +
237
+ '<div class="plupload_clearer">&nbsp;</div>' +
238
+ '</div>' +
239
+
240
+ '<table class="plupload_filelist plupload_filelist_footer ui-widget-header">' +
241
+ '<tr>' +
242
+ '<td class="plupload_cell plupload_file_name">' +
243
+ '<div class="plupload_buttons"><!-- Visible -->' +
244
+ '<a class="plupload_button plupload_add">' + _("Add Files") + '</a>&nbsp;' +
245
+ '<a class="plupload_button plupload_start">' + _("Start Upload") + '</a>&nbsp;' +
246
+ '<a class="plupload_button plupload_stop plupload_hidden">'+_("Stop Upload") + '</a>&nbsp;' +
247
+ '</div>' +
248
+
249
+ '<div class="plupload_started plupload_hidden"><!-- Hidden -->' +
250
+ '<div class="plupload_progress plupload_right">' +
251
+ '<div class="plupload_progress_container"></div>' +
252
+ '</div>' +
253
+
254
+ '<div class="plupload_cell plupload_upload_status"></div>' +
255
+
256
+ '<div class="plupload_clearer">&nbsp;</div>' +
257
+ '</div>' +
258
+ '</td>' +
259
+ '<td class="plupload_file_status"><span class="plupload_total_status">0%</span></td>' +
260
+ '<td class="plupload_file_size"><span class="plupload_total_file_size">0 kb</span></td>' +
261
+ '<td class="plupload_file_action"></td>' +
262
+ '</tr>' +
263
+ '</table>' +
264
+
265
+ '</div>' +
266
+ '<input class="plupload_count" value="0" type="hidden">' +
267
+ '</div>'
268
+ );
269
+ }
270
+
271
+
272
+ $.widget("ui.plupload", {
273
+
274
+ widgetEventPrefix: '',
275
+
276
+ contents_bak: '',
277
+
278
+ options: {
279
+ browse_button_hover: 'ui-state-hover',
280
+ browse_button_active: 'ui-state-active',
281
+
282
+ filters: {},
283
+
284
+ // widget specific
285
+ buttons: {
286
+ browse: true,
287
+ start: true,
288
+ stop: true
289
+ },
290
+
291
+ views: {
292
+ list: true,
293
+ thumbs: false,
294
+ active: 'list',
295
+ remember: true // requires: https://github.com/carhartl/jquery-cookie, otherwise disabled even if set to true
296
+ },
297
+
298
+ thumb_width: 100,
299
+ thumb_height: 60,
300
+
301
+ multiple_queues: true, // re-use widget by default
302
+ dragdrop : true,
303
+ autostart: false,
304
+ sortable: false,
305
+ rename: false
306
+ },
307
+
308
+ FILE_COUNT_ERROR: -9001,
309
+
310
+ _create: function() {
311
+ var id = this.element.attr('id');
312
+ if (!id) {
313
+ id = plupload.guid();
314
+ this.element.attr('id', id);
315
+ }
316
+ this.id = id;
317
+
318
+ // backup the elements initial state
319
+ this.contents_bak = this.element.html();
320
+ renderUI(this.element);
321
+
322
+ // container, just in case
323
+ this.container = $('.plupload_container', this.element).attr('id', id + '_container');
324
+
325
+ this.content = $('.plupload_content', this.element);
326
+
327
+ if ($.fn.resizable) {
328
+ this.container.resizable({
329
+ handles: 's',
330
+ minHeight: 300
331
+ });
332
+ }
333
+
334
+ // list of files, may become sortable
335
+ this.filelist = $('.plupload_filelist_content', this.container)
336
+ .attr({
337
+ id: id + '_filelist',
338
+ unselectable: 'on'
339
+ });
340
+
341
+
342
+ // buttons
343
+ this.browse_button = $('.plupload_add', this.container).attr('id', id + '_browse');
344
+ this.start_button = $('.plupload_start', this.container).attr('id', id + '_start');
345
+ this.stop_button = $('.plupload_stop', this.container).attr('id', id + '_stop');
346
+ this.thumbs_switcher = $('#' + id + '_view_thumbs');
347
+ this.list_switcher = $('#' + id + '_view_list');
348
+
349
+ if ($.ui.button) {
350
+ this.browse_button.button({
351
+ icons: { primary: 'ui-icon-circle-plus' },
352
+ disabled: true
353
+ });
354
+
355
+ this.start_button.button({
356
+ icons: { primary: 'ui-icon-circle-arrow-e' },
357
+ disabled: true
358
+ });
359
+
360
+ this.stop_button.button({
361
+ icons: { primary: 'ui-icon-circle-close' }
362
+ });
363
+
364
+ this.list_switcher.button({
365
+ text: false,
366
+ icons: { secondary: "ui-icon-grip-dotted-horizontal" }
367
+ });
368
+
369
+ this.thumbs_switcher.button({
370
+ text: false,
371
+ icons: { secondary: "ui-icon-image" }
372
+ });
373
+ }
374
+
375
+ // progressbar
376
+ this.progressbar = $('.plupload_progress_container', this.container);
377
+
378
+ if ($.ui.progressbar) {
379
+ this.progressbar.progressbar();
380
+ }
381
+
382
+ // counter
383
+ this.counter = $('.plupload_count', this.element)
384
+ .attr({
385
+ id: id + '_count',
386
+ name: id + '_count'
387
+ });
388
+
389
+ // initialize uploader instance
390
+ this._initUploader();
391
+ },
392
+
393
+ _initUploader: function() {
394
+ var self = this
395
+ , id = this.id
396
+ , uploader
397
+ , options = {
398
+ container: id + '_buttons',
399
+ browse_button: id + '_browse'
400
+ }
401
+ ;
402
+
403
+ $('.plupload_buttons', this.element).attr('id', id + '_buttons');
404
+
405
+ if (self.options.dragdrop) {
406
+ this.filelist.parent().attr('id', this.id + '_dropbox');
407
+ options.drop_element = this.id + '_dropbox';
408
+ }
409
+
410
+ this.filelist.on('click', function(e) {
411
+ if ($(e.target).hasClass('plupload_action_icon')) {
412
+ self.removeFile($(e.target).closest('.plupload_file').attr('id'));
413
+ e.preventDefault();
414
+ }
415
+ });
416
+
417
+ uploader = this.uploader = uploaders[id] = new plupload.Uploader($.extend(this.options, options));
418
+
419
+ if (self.options.views.thumbs) {
420
+ uploader.settings.required_features.display_media = true;
421
+ }
422
+
423
+ // for backward compatibility
424
+ if (self.options.max_file_count) {
425
+ plupload.extend(uploader.getOption('filters'), {
426
+ max_file_count: self.options.max_file_count
427
+ });
428
+ }
429
+
430
+ plupload.addFileFilter('max_file_count', function(maxCount, file, cb) {
431
+ if (maxCount <= this.files.length - (this.total.uploaded + this.total.failed)) {
432
+ self.browse_button.button('disable');
433
+ this.disableBrowse();
434
+
435
+ this.trigger('Error', {
436
+ code : self.FILE_COUNT_ERROR,
437
+ message : _("File count error."),
438
+ file : file
439
+ });
440
+ cb(false);
441
+ } else {
442
+ cb(true);
443
+ }
444
+ });
445
+
446
+
447
+ uploader.bind('Error', function(up, err) {
448
+ var message, details = "";
449
+
450
+ message = '<strong>' + err.message + '</strong>';
451
+
452
+ switch (err.code) {
453
+ case plupload.FILE_EXTENSION_ERROR:
454
+ details = o.sprintf(_("File: %s"), err.file.name);
455
+ break;
456
+
457
+ case plupload.FILE_SIZE_ERROR:
458
+ details = o.sprintf(_("File: %s, size: %d, max file size: %d"), err.file.name, plupload.formatSize(err.file.size), plupload.formatSize(plupload.parseSize(up.getOption('filters').max_file_size)));
459
+ break;
460
+
461
+ case plupload.FILE_DUPLICATE_ERROR:
462
+ details = o.sprintf(_("%s already present in the queue."), err.file.name);
463
+ break;
464
+
465
+ case self.FILE_COUNT_ERROR:
466
+ details = o.sprintf(_("Upload element accepts only %d file(s) at a time. Extra files were stripped."), up.getOption('filters').max_file_count || 0);
467
+ break;
468
+
469
+ case plupload.IMAGE_FORMAT_ERROR :
470
+ details = _("Image format either wrong or not supported.");
471
+ break;
472
+
473
+ case plupload.IMAGE_MEMORY_ERROR :
474
+ details = _("Runtime ran out of available memory.");
475
+ break;
476
+
477
+ /* // This needs a review
478
+ case plupload.IMAGE_DIMENSIONS_ERROR :
479
+ details = o.sprintf(_('Resoultion out of boundaries! <b>%s</b> runtime supports images only up to %wx%hpx.'), up.runtime, up.features.maxWidth, up.features.maxHeight);
480
+ break; */
481
+
482
+ case plupload.HTTP_ERROR:
483
+ details = _("Upload URL might be wrong or doesn't exist.");
484
+ break;
485
+ }
486
+
487
+ message += " <br /><i>" + details + "</i>";
488
+
489
+ self._trigger('error', null, { up: up, error: err } );
490
+
491
+ // do not show UI if no runtime can be initialized
492
+ if (err.code === plupload.INIT_ERROR) {
493
+ setTimeout(function() {
494
+ self.destroy();
495
+ }, 1);
496
+ } else {
497
+ self.notify('error', message);
498
+ }
499
+ });
500
+
501
+
502
+ uploader.bind('PostInit', function(up) {
503
+ // all buttons are optional, so they can be disabled and hidden
504
+ if (!self.options.buttons.browse) {
505
+ self.browse_button.button('disable').hide();
506
+ up.disableBrowse(true);
507
+ } else {
508
+ self.browse_button.button('enable');
509
+ }
510
+
511
+ if (!self.options.buttons.start) {
512
+ self.start_button.button('disable').hide();
513
+ }
514
+
515
+ if (!self.options.buttons.stop) {
516
+ self.stop_button.button('disable').hide();
517
+ }
518
+
519
+ if (!self.options.unique_names && self.options.rename) {
520
+ self._enableRenaming();
521
+ }
522
+
523
+ if (self.options.dragdrop && up.features.dragdrop) {
524
+ self.filelist.parent().addClass('plupload_dropbox');
525
+ }
526
+
527
+ self._enableViewSwitcher();
528
+
529
+ self.start_button.click(function(e) {
530
+ if (!$(this).button('option', 'disabled')) {
531
+ self.start();
532
+ }
533
+ e.preventDefault();
534
+ });
535
+
536
+ self.stop_button.click(function(e) {
537
+ self.stop();
538
+ e.preventDefault();
539
+ });
540
+
541
+ self._trigger('ready', null, { up: up });
542
+ });
543
+
544
+ // uploader internal events must run first
545
+ uploader.init();
546
+
547
+ uploader.bind('FileFiltered', function(up, file) {
548
+ self._addFiles(file);
549
+ });
550
+
551
+ uploader.bind('FilesAdded', function(up, files) {
552
+ self._trigger('selected', null, { up: up, files: files } );
553
+
554
+ // re-enable sortable
555
+ if (self.options.sortable && $.ui.sortable) {
556
+ self._enableSortingList();
557
+ }
558
+
559
+ self._trigger('updatelist', null, { filelist: self.filelist });
560
+
561
+ if (self.options.autostart) {
562
+ // set a little delay to make sure that QueueChanged triggered by the core has time to complete
563
+ setTimeout(function() {
564
+ self.start();
565
+ }, 10);
566
+ }
567
+ });
568
+
569
+ uploader.bind('FilesRemoved', function(up, files) {
570
+ // destroy sortable if enabled
571
+ if ($.ui.sortable && self.options.sortable) {
572
+ $('tbody', self.filelist).sortable('destroy');
573
+ }
574
+
575
+ $.each(files, function(i, file) {
576
+ $('#' + file.id).toggle("highlight", function() {
577
+ $(this).remove();
578
+ });
579
+ });
580
+
581
+ if (up.files.length) {
582
+ // re-initialize sortable
583
+ if (self.options.sortable && $.ui.sortable) {
584
+ self._enableSortingList();
585
+ }
586
+ }
587
+
588
+ self._trigger('updatelist', null, { filelist: self.filelist });
589
+ self._trigger('removed', null, { up: up, files: files } );
590
+ });
591
+
592
+ uploader.bind('QueueChanged StateChanged', function() {
593
+ self._handleState();
594
+ });
595
+
596
+ uploader.bind('UploadFile', function(up, file) {
597
+ self._handleFileStatus(file);
598
+ });
599
+
600
+ uploader.bind('FileUploaded', function(up, file) {
601
+ self._handleFileStatus(file);
602
+ self._trigger('uploaded', null, { up: up, file: file } );
603
+ });
604
+
605
+ uploader.bind('UploadProgress', function(up, file) {
606
+ self._handleFileStatus(file);
607
+ self._updateTotalProgress();
608
+ self._trigger('progress', null, { up: up, file: file } );
609
+ });
610
+
611
+ uploader.bind('UploadComplete', function(up, files) {
612
+ self._addFormFields();
613
+ self._trigger('complete', null, { up: up, files: files } );
614
+ });
615
+ },
616
+
617
+
618
+ _setOption: function(key, value) {
619
+ var self = this;
620
+
621
+ if (key == 'buttons' && typeof(value) == 'object') {
622
+ value = $.extend(self.options.buttons, value);
623
+
624
+ if (!value.browse) {
625
+ self.browse_button.button('disable').hide();
626
+ self.uploader.disableBrowse(true);
627
+ } else {
628
+ self.browse_button.button('enable').show();
629
+ self.uploader.disableBrowse(false);
630
+ }
631
+
632
+ if (!value.start) {
633
+ self.start_button.button('disable').hide();
634
+ } else {
635
+ self.start_button.button('enable').show();
636
+ }
637
+
638
+ if (!value.stop) {
639
+ self.stop_button.button('disable').hide();
640
+ } else {
641
+ self.start_button.button('enable').show();
642
+ }
643
+ }
644
+
645
+ self.uploader.settings[key] = value;
646
+ },
647
+
648
+
649
+ /**
650
+ Start upload. Triggers `start` event.
651
+
652
+ @method start
653
+ */
654
+ start: function() {
655
+ this.uploader.start();
656
+ this._trigger('start', null, { up: this.uploader });
657
+ },
658
+
659
+
660
+ /**
661
+ Stop upload. Triggers `stop` event.
662
+
663
+ @method stop
664
+ */
665
+ stop: function() {
666
+ this.uploader.stop();
667
+ this._trigger('stop', null, { up: this.uploader });
668
+ },
669
+
670
+
671
+ /**
672
+ Enable browse button.
673
+
674
+ @method enable
675
+ */
676
+ enable: function() {
677
+ this.browse_button.button('enable');
678
+ this.uploader.disableBrowse(false);
679
+ },
680
+
681
+
682
+ /**
683
+ Disable browse button.
684
+
685
+ @method disable
686
+ */
687
+ disable: function() {
688
+ this.browse_button.button('disable');
689
+ this.uploader.disableBrowse(true);
690
+ },
691
+
692
+
693
+ /**
694
+ Retrieve file by it's unique id.
695
+
696
+ @method getFile
697
+ @param {String} id Unique id of the file
698
+ @return {plupload.File}
699
+ */
700
+ getFile: function(id) {
701
+ var file;
702
+
703
+ if (typeof id === 'number') {
704
+ file = this.uploader.files[id];
705
+ } else {
706
+ file = this.uploader.getFile(id);
707
+ }
708
+ return file;
709
+ },
710
+
711
+ /**
712
+ Return array of files currently in the queue.
713
+
714
+ @method getFiles
715
+ @return {Array} Array of files in the queue represented by plupload.File objects
716
+ */
717
+ getFiles: function() {
718
+ return this.uploader.files;
719
+ },
720
+
721
+
722
+ /**
723
+ Remove the file from the queue.
724
+
725
+ @method removeFile
726
+ @param {plupload.File|String} file File to remove, might be specified directly or by it's unique id
727
+ */
728
+ removeFile: function(file) {
729
+ if (plupload.typeOf(file) === 'string') {
730
+ file = this.getFile(file);
731
+ }
732
+ this.uploader.removeFile(file);
733
+ },
734
+
735
+
736
+ /**
737
+ Clear the file queue.
738
+
739
+ @method clearQueue
740
+ */
741
+ clearQueue: function() {
742
+ this.uploader.splice();
743
+ },
744
+
745
+
746
+ /**
747
+ Retrieve internal plupload.Uploader object (usually not required).
748
+
749
+ @method getUploader
750
+ @return {plupload.Uploader}
751
+ */
752
+ getUploader: function() {
753
+ return this.uploader;
754
+ },
755
+
756
+
757
+ /**
758
+ Trigger refresh procedure, specifically browse_button re-measure and re-position operations.
759
+ Might get handy, when UI Widget is placed within the popup, that is constantly hidden and shown
760
+ again - without calling this method after each show operation, dialog trigger might get displaced
761
+ and disfunctional.
762
+
763
+ @method refresh
764
+ */
765
+ refresh: function() {
766
+ this.uploader.refresh();
767
+ },
768
+
769
+
770
+ /**
771
+ Display a message in notification area.
772
+
773
+ @method notify
774
+ @param {Enum} type Type of the message, either `error` or `info`
775
+ @param {String} message The text message to display.
776
+ */
777
+ notify: function(type, message) {
778
+ var popup = $(
779
+ '<div class="plupload_message">' +
780
+ '<span class="plupload_message_close ui-icon ui-icon-circle-close" title="'+_('Close')+'"></span>' +
781
+ '<p><span class="ui-icon"></span>' + message + '</p>' +
782
+ '</div>'
783
+ );
784
+
785
+ popup
786
+ .addClass('ui-state-' + (type === 'error' ? 'error' : 'highlight'))
787
+ .find('p .ui-icon')
788
+ .addClass('ui-icon-' + (type === 'error' ? 'alert' : 'info'))
789
+ .end()
790
+ .find('.plupload_message_close')
791
+ .click(function() {
792
+ popup.remove();
793
+ })
794
+ .end();
795
+
796
+ $('.plupload_header', this.container).append(popup);
797
+ },
798
+
799
+
800
+ /**
801
+ Destroy the widget, the uploader, free associated resources and bring back original html.
802
+
803
+ @method destroy
804
+ */
805
+ destroy: function() {
806
+ // destroy uploader instance
807
+ this.uploader.destroy();
808
+
809
+ // unbind all button events
810
+ $('.plupload_button', this.element).unbind();
811
+
812
+ // destroy buttons
813
+ if ($.ui.button) {
814
+ $('.plupload_add, .plupload_start, .plupload_stop', this.container)
815
+ .button('destroy');
816
+ }
817
+
818
+ // destroy progressbar
819
+ if ($.ui.progressbar) {
820
+ this.progressbar.progressbar('destroy');
821
+ }
822
+
823
+ // destroy sortable behavior
824
+ if ($.ui.sortable && this.options.sortable) {
825
+ $('tbody', this.filelist).sortable('destroy');
826
+ }
827
+
828
+ // restore the elements initial state
829
+ this.element
830
+ .empty()
831
+ .html(this.contents_bak);
832
+ this.contents_bak = '';
833
+
834
+ $.Widget.prototype.destroy.apply(this);
835
+ },
836
+
837
+
838
+ _handleState: function() {
839
+ var up = this.uploader
840
+ , filesPending = up.files.length - (up.total.uploaded + up.total.failed)
841
+ , maxCount = up.getOption('filters').max_file_count || 0
842
+ ;
843
+
844
+ if (plupload.STARTED === up.state) {
845
+ $([])
846
+ .add(this.stop_button)
847
+ .add('.plupload_started')
848
+ .removeClass('plupload_hidden');
849
+
850
+ this.start_button.button('disable');
851
+
852
+ if (!this.options.multiple_queues) {
853
+ this.browse_button.button('disable');
854
+ up.disableBrowse();
855
+ }
856
+
857
+ $('.plupload_upload_status', this.element).html(o.sprintf(_('Uploaded %d/%d files'), up.total.uploaded, up.files.length));
858
+ $('.plupload_header_content', this.element).addClass('plupload_header_content_bw');
859
+ }
860
+ else if (plupload.STOPPED === up.state) {
861
+ $([])
862
+ .add(this.stop_button)
863
+ .add('.plupload_started')
864
+ .addClass('plupload_hidden');
865
+
866
+ if (filesPending) {
867
+ this.start_button.button('enable');
868
+ } else {
869
+ this.start_button.button('disable');
870
+ }
871
+
872
+ if (this.options.multiple_queues) {
873
+ $('.plupload_header_content', this.element).removeClass('plupload_header_content_bw');
874
+ }
875
+
876
+ // if max_file_count defined, only that many files can be queued at once
877
+ if (this.options.multiple_queues && maxCount && maxCount > filesPending) {
878
+ this.browse_button.button('enable');
879
+ up.disableBrowse(false);
880
+ }
881
+
882
+ this._updateTotalProgress();
883
+ }
884
+
885
+ if (up.total.queued === 0) {
886
+ $('.ui-button-text', this.browse_button).html(_('Add Files'));
887
+ } else {
888
+ $('.ui-button-text', this.browse_button).html(o.sprintf(_('%d files queued'), up.total.queued));
889
+ }
890
+
891
+ up.refresh();
892
+ },
893
+
894
+
895
+ _handleFileStatus: function(file) {
896
+ var $file = $('#' + file.id), actionClass, iconClass;
897
+
898
+ // since this method might be called asynchronously, file row might not yet be rendered
899
+ if (!$file.length) {
900
+ return;
901
+ }
902
+
903
+ switch (file.status) {
904
+ case plupload.DONE:
905
+ actionClass = 'plupload_done';
906
+ iconClass = 'plupload_action_icon ui-icon ui-icon-circle-check';
907
+ break;
908
+
909
+ case plupload.FAILED:
910
+ actionClass = 'ui-state-error plupload_failed';
911
+ iconClass = 'plupload_action_icon ui-icon ui-icon-alert';
912
+ break;
913
+
914
+ case plupload.QUEUED:
915
+ actionClass = 'plupload_delete';
916
+ iconClass = 'plupload_action_icon ui-icon ui-icon-circle-minus';
917
+ break;
918
+
919
+ case plupload.UPLOADING:
920
+ actionClass = 'ui-state-highlight plupload_uploading';
921
+ iconClass = 'plupload_action_icon ui-icon ui-icon-circle-arrow-w';
922
+
923
+ // scroll uploading file into the view if its bottom boundary is out of it
924
+ var scroller = $('.plupload_scroll', this.container)
925
+ , scrollTop = scroller.scrollTop()
926
+ , scrollerHeight = scroller.height()
927
+ , rowOffset = $file.position().top + $file.height()
928
+ ;
929
+
930
+ if (scrollerHeight < rowOffset) {
931
+ scroller.scrollTop(scrollTop + rowOffset - scrollerHeight);
932
+ }
933
+
934
+ // Set file specific progress
935
+ $file
936
+ .find('.plupload_file_percent')
937
+ .html(file.percent + '%')
938
+ .end()
939
+ .find('.plupload_file_progress')
940
+ .css('width', file.percent + '%')
941
+ .end()
942
+ .find('.plupload_file_size')
943
+ .html(plupload.formatSize(file.size));
944
+ break;
945
+ }
946
+ actionClass += ' ui-state-default plupload_file';
947
+
948
+ $file
949
+ .attr('class', actionClass)
950
+ .find('.plupload_action_icon')
951
+ .attr('class', iconClass);
952
+ },
953
+
954
+
955
+ _updateTotalProgress: function() {
956
+ var up = this.uploader;
957
+
958
+ // Scroll to end of file list
959
+ this.filelist[0].scrollTop = this.filelist[0].scrollHeight;
960
+
961
+ this.progressbar.progressbar('value', up.total.percent);
962
+
963
+ this.element
964
+ .find('.plupload_total_status')
965
+ .html(up.total.percent + '%')
966
+ .end()
967
+ .find('.plupload_total_file_size')
968
+ .html(plupload.formatSize(up.total.size))
969
+ .end()
970
+ .find('.plupload_upload_status')
971
+ .html(o.sprintf(_('Uploaded %d/%d files'), up.total.uploaded, up.files.length));
972
+ },
973
+
974
+
975
+ _displayThumbs: function() {
976
+ var self = this
977
+ , tw, th // thumb width/height
978
+ , cols
979
+ , num = 0 // number of simultaneously visible thumbs
980
+ , thumbs = [] // array of thumbs to preload at any given moment
981
+ , loading = false
982
+ ;
983
+
984
+ if (!this.options.views.thumbs) {
985
+ return;
986
+ }
987
+
988
+
989
+ function onLast(el, eventName, cb) {
990
+ var timer;
991
+
992
+ el.on(eventName, function() {
993
+ clearTimeout(timer);
994
+ timer = setTimeout(function() {
995
+ clearTimeout(timer);
996
+ cb();
997
+ }, 300);
998
+ });
999
+ }
1000
+
1001
+
1002
+ // calculate number of simultaneously visible thumbs
1003
+ function measure() {
1004
+ if (!tw || !th) {
1005
+ var wrapper = $('.plupload_file:eq(0)', self.filelist);
1006
+ tw = wrapper.outerWidth(true);
1007
+ th = wrapper.outerHeight(true);
1008
+ }
1009
+
1010
+ var aw = self.content.width(), ah = self.content.height();
1011
+ cols = Math.floor(aw / tw);
1012
+ num = cols * (Math.ceil(ah / th) + 1);
1013
+ }
1014
+
1015
+
1016
+ function pickThumbsToLoad() {
1017
+ // calculate index of virst visible thumb
1018
+ var startIdx = Math.floor(self.content.scrollTop() / th) * cols;
1019
+ // get potentially visible thumbs that are not yet visible
1020
+ thumbs = $('.plupload_file', self.filelist)
1021
+ .slice(startIdx, startIdx + num)
1022
+ .filter('.plupload_file_loading')
1023
+ .get();
1024
+ }
1025
+
1026
+
1027
+ function init() {
1028
+ function mpl() { // measure, pick, load
1029
+ if (self.view_mode !== 'thumbs') {
1030
+ return;
1031
+ }
1032
+ measure();
1033
+ pickThumbsToLoad();
1034
+ lazyLoad();
1035
+ }
1036
+
1037
+ if ($.fn.resizable) {
1038
+ onLast(self.container, 'resize', mpl);
1039
+ }
1040
+
1041
+ onLast(self.window, 'resize', mpl);
1042
+ onLast(self.content, 'scroll', mpl);
1043
+
1044
+ self.element.on('viewchanged selected', mpl);
1045
+
1046
+ mpl();
1047
+ }
1048
+
1049
+
1050
+ function preloadThumb(file, cb) {
1051
+ var img = new o.Image();
1052
+
1053
+ img.onload = function() {
1054
+ var thumb = $('#' + file.id + ' .plupload_file_thumb', self.filelist).html('');
1055
+ this.embed(thumb[0], {
1056
+ width:  self.options.thumb_width,
1057
+ height: self.options.thumb_height,
1058
+ crop: true,
1059
+ swf_url: o.resolveUrl(self.options.flash_swf_url),
1060
+ xap_url: o.resolveUrl(self.options.silverlight_xap_url)
1061
+ });
1062
+ };
1063
+
1064
+ img.bind("embedded error", function() {
1065
+ $('#' + file.id, self.filelist).removeClass('plupload_file_loading');
1066
+ this.destroy();
1067
+ setTimeout(cb, 1); // detach, otherwise ui might hang (in SilverLight for example)
1068
+ });
1069
+
1070
+ img.load(file.getSource());
1071
+ }
1072
+
1073
+
1074
+ function lazyLoad() {
1075
+ if (self.view_mode !== 'thumbs' || loading) {
1076
+ return;
1077
+ }
1078
+
1079
+ pickThumbsToLoad();
1080
+ if (!thumbs.length) {
1081
+ return;
1082
+ }
1083
+
1084
+ loading = true;
1085
+
1086
+ preloadThumb(self.getFile($(thumbs.shift()).attr('id')), function() {
1087
+ loading = false;
1088
+ lazyLoad();
1089
+ });
1090
+ }
1091
+
1092
+ // this has to run only once to measure structures and bind listeners
1093
+ this.element.on('selected', function onselected() {
1094
+ self.element.off('selected', onselected);
1095
+ init();
1096
+ });
1097
+ },
1098
+
1099
+
1100
+ _addFiles: function(files) {
1101
+ var self = this, file_html, html = '';
1102
+
1103
+ file_html = '<li class="plupload_file ui-state-default plupload_file_loading plupload_delete" id="%id%" style="width:%thumb_width%px;">' +
1104
+ '<div class="plupload_file_thumb" style="width:%thumb_width%px;height:%thumb_height%px;">' +
1105
+ '<div class="plupload_file_dummy ui-widget-content" style="line-height:%thumb_height%px;"><span class="ui-state-disabled">%ext% </span></div>' +
1106
+ '</div>' +
1107
+ '<div class="plupload_file_status">' +
1108
+ '<div class="plupload_file_progress ui-widget-header" style="width: 0%"> </div>' +
1109
+ '<span class="plupload_file_percent">%percent% </span>' +
1110
+ '</div>' +
1111
+ '<div class="plupload_file_name" title="%name%">' +
1112
+ '<span class="plupload_file_name_wrapper">%name% </span>' +
1113
+ '</div>' +
1114
+ '<div class="plupload_file_action">' +
1115
+ '<div class="plupload_action_icon ui-icon ui-icon-circle-minus"> </div>' +
1116
+ '</div>' +
1117
+ '<div class="plupload_file_size">%size% </div>' +
1118
+ '<div class="plupload_file_fields"> </div>' +
1119
+ '</li>';
1120
+
1121
+ if (plupload.typeOf(files) !== 'array') {
1122
+ files = [files];
1123
+ }
1124
+
1125
+ $.each(files, function(i, file) {
1126
+ var ext = o.Mime.getFileExtension(file.name) || 'none';
1127
+
1128
+ html += file_html.replace(/%(\w+)%/g, function($0, $1) {
1129
+ switch ($1) {
1130
+ case 'thumb_width':
1131
+ case 'thumb_height':
1132
+ return self.options[$1];
1133
+
1134
+ case 'size':
1135
+ return plupload.formatSize(file.size);
1136
+
1137
+ case 'ext':
1138
+ return ext;
1139
+
1140
+ default:
1141
+ return file[$1] || '';
1142
+ }
1143
+ });
1144
+ });
1145
+
1146
+ self.filelist.append(html);
1147
+ },
1148
+
1149
+
1150
+ _addFormFields: function() {
1151
+ var self = this;
1152
+
1153
+ // re-add from fresh
1154
+ $('.plupload_file_fields', this.filelist).html('');
1155
+
1156
+ plupload.each(this.uploader.files, function(file, count) {
1157
+ var fields = ''
1158
+ , id = self.id + '_' + count
1159
+ ;
1160
+
1161
+ if (file.target_name) {
1162
+ fields += '<input type="hidden" name="' + id + '_tmpname" value="'+plupload.xmlEncode(file.target_name)+'" />';
1163
+ }
1164
+ fields += '<input type="hidden" name="' + id + '_name" value="'+plupload.xmlEncode(file.name)+'" />';
1165
+ fields += '<input type="hidden" name="' + id + '_status" value="' + (file.status === plupload.DONE ? 'done' : 'failed') + '" />';
1166
+
1167
+ $('#' + file.id).find('.plupload_file_fields').html(fields);
1168
+ });
1169
+
1170
+ this.counter.val(this.uploader.files.length);
1171
+ },
1172
+
1173
+
1174
+ _viewChanged: function(view) {
1175
+ // update or write a new cookie
1176
+ if (this.options.views.remember && $.cookie) {
1177
+ $.cookie('plupload_ui_view', view, { expires: 7, path: '/' });
1178
+ }
1179
+
1180
+ // ugly fix for IE6 - make content area stretchable
1181
+ if (o.Env.browser === 'IE' && o.Env.version < 7) {
1182
+ this.content.attr('style', 'height:expression(document.getElementById("' + this.id + '_container' + '").clientHeight - ' + (view === 'list' ? 132 : 102) + ')');
1183
+ }
1184
+
1185
+ this.container.removeClass('plupload_view_list plupload_view_thumbs').addClass('plupload_view_' + view);
1186
+ this.view_mode = view;
1187
+ this._trigger('viewchanged', null, { view: view });
1188
+ },
1189
+
1190
+
1191
+ _enableViewSwitcher: function() {
1192
+ var self = this
1193
+ , view
1194
+ , switcher = $('.plupload_view_switch', this.container)
1195
+ , buttons
1196
+ , button
1197
+ ;
1198
+
1199
+ plupload.each(['list', 'thumbs'], function(view) {
1200
+ if (!self.options.views[view]) {
1201
+ switcher.find('[for="' + self.id + '_view_' + view + '"], #'+ self.id +'_view_' + view).remove();
1202
+ }
1203
+ });
1204
+
1205
+ // check if any visible left
1206
+ buttons = switcher.find('.plupload_button');
1207
+
1208
+ if (buttons.length === 1) {
1209
+ switcher.hide();
1210
+ view = buttons.eq(0).data('view');
1211
+ this._viewChanged(view);
1212
+ } else if ($.ui.button && buttons.length > 1) {
1213
+ if (this.options.views.remember && $.cookie) {
1214
+ view = $.cookie('plupload_ui_view');
1215
+ }
1216
+
1217
+ // if wierd case, bail out to default
1218
+ if (!~plupload.inArray(view, ['list', 'thumbs'])) {
1219
+ view = this.options.views.active;
1220
+ }
1221
+
1222
+ switcher
1223
+ .show()
1224
+ .buttonset()
1225
+ .find('.ui-button')
1226
+ .click(function(e) {
1227
+ view = $(this).data('view');
1228
+ self._viewChanged(view);
1229
+ e.preventDefault(); // avoid auto scrolling to widget in IE and FF (see #850)
1230
+ });
1231
+
1232
+ // if view not active - happens when switcher wasn't clicked manually
1233
+ button = switcher.find('[for="' + self.id + '_view_'+view+'"]');
1234
+ if (button.length) {
1235
+ button.trigger('click');
1236
+ }
1237
+ } else {
1238
+ switcher.show();
1239
+ this._viewChanged(this.options.views.active);
1240
+ }
1241
+
1242
+ // initialize thumb viewer if requested
1243
+ if (this.options.views.thumbs) {
1244
+ this._displayThumbs();
1245
+ }
1246
+ },
1247
+
1248
+
1249
+ _enableRenaming: function() {
1250
+ var self = this;
1251
+
1252
+ this.filelist.dblclick(function(e) {
1253
+ var nameSpan = $(e.target), nameInput, file, parts, name, ext = "";
1254
+
1255
+ if (!nameSpan.hasClass('plupload_file_name_wrapper')) {
1256
+ return;
1257
+ }
1258
+
1259
+ // Get file name and split out name and extension
1260
+ file = self.uploader.getFile(nameSpan.closest('.plupload_file')[0].id);
1261
+ name = file.name;
1262
+ parts = /^(.+)(\.[^.]+)$/.exec(name);
1263
+ if (parts) {
1264
+ name = parts[1];
1265
+ ext = parts[2];
1266
+ }
1267
+
1268
+ // Display input element
1269
+ nameInput = $('<input class="plupload_file_rename" type="text" />').width(nameSpan.width()).insertAfter(nameSpan.hide());
1270
+ nameInput.val(name).blur(function() {
1271
+ nameSpan.show().parent().scrollLeft(0).end().next().remove();
1272
+ }).keydown(function(e) {
1273
+ var nameInput = $(this);
1274
+
1275
+ if ($.inArray(e.keyCode, [13, 27]) !== -1) {
1276
+ e.preventDefault();
1277
+
1278
+ // Rename file and glue extension back on
1279
+ if (e.keyCode === 13) {
1280
+ file.name = nameInput.val() + ext;
1281
+ nameSpan.html(file.name);
1282
+ }
1283
+ nameInput.blur();
1284
+ }
1285
+ })[0].focus();
1286
+ });
1287
+ },
1288
+
1289
+
1290
+ _enableSortingList: function() {
1291
+ var self = this;
1292
+
1293
+ if ($('.plupload_file', this.filelist).length < 2) {
1294
+ return;
1295
+ }
1296
+
1297
+ // destroy sortable if enabled
1298
+ $('tbody', this.filelist).sortable('destroy');
1299
+
1300
+ // enable
1301
+ this.filelist.sortable({
1302
+ items: '.plupload_delete',
1303
+
1304
+ cancel: 'object, .plupload_clearer',
1305
+
1306
+ stop: function() {
1307
+ var files = [];
1308
+
1309
+ $.each($(this).sortable('toArray'), function(i, id) {
1310
+ files[files.length] = self.uploader.getFile(id);
1311
+ });
1312
+
1313
+ files.unshift(files.length);
1314
+ files.unshift(0);
1315
+
1316
+ // re-populate files array
1317
+ Array.prototype.splice.apply(self.uploader.files, files);
1318
+ }
1319
+ });
1320
+ }
1321
+ });
1322
+
1323
+ } (window, document, plupload, mOxie, jQuery));