rails_com 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/rails_com_manifest.js +3 -2
  3. data/app/assets/images/verification.jpg +0 -0
  4. data/app/assets/javascripts/rails_com/application.js +3 -0
  5. data/app/assets/stylesheets/rails_com/application.css +4 -0
  6. data/app/controllers/concerns/the_common_api.rb +20 -0
  7. data/app/controllers/the_guards_controller.rb +18 -0
  8. data/app/helpers/rails_com/active_helper.rb +18 -37
  9. data/app/helpers/rails_com_helper.rb +16 -0
  10. data/app/models/state_machine.rb +1 -1
  11. data/app/views/kaminari/_paginator.html.erb +1 -1
  12. data/app/views/layouts/rails_com/application.html.erb +17 -0
  13. data/app/views/the_guards/index.html.erb +18 -0
  14. data/config/locales/en.yml +7 -1
  15. data/config/routes.rb +3 -0
  16. data/lib/assets/javascripts/input-attachment.js +481 -0
  17. data/lib/assets/stylesheets/semantic.css +19466 -0
  18. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.eot +0 -0
  19. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.otf +0 -0
  20. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.svg +2671 -0
  21. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.ttf +0 -0
  22. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.woff +0 -0
  23. data/lib/nondigest_assets/fonts/themes/default/assets/fonts/icons.woff2 +0 -0
  24. data/lib/nondigest_assets/images/themes/default/assets/images/flags.png +0 -0
  25. data/lib/rails_com/controller_helper.rb +25 -0
  26. data/lib/rails_com/core_ext/hash.rb +1 -0
  27. data/lib/rails_com/core_ext/nil.rb +7 -0
  28. data/lib/rails_com/engine.rb +8 -0
  29. data/lib/rails_com/helpers/qiniu_helper.rb +21 -50
  30. data/lib/rails_com/sprockets/non_digest_assets.rb +34 -0
  31. data/lib/rails_com/sprockets/qiniu_exporter.rb +21 -0
  32. data/lib/rails_com/sprockets.rb +15 -0
  33. data/lib/rails_com/version.rb +1 -1
  34. data/lib/rails_com.rb +6 -4
  35. data/lib/templates/erb/scaffold/_form.html.erb +19 -0
  36. data/lib/templates/erb/scaffold/edit.html.erb +2 -0
  37. data/lib/templates/erb/scaffold/index.html.erb +36 -0
  38. data/lib/templates/erb/scaffold/new.html.erb +1 -0
  39. data/lib/templates/erb/scaffold/show.html.erb +13 -0
  40. data/lib/templates/rails/scaffold_controller/controller.rb +47 -0
  41. metadata +45 -7
  42. data/app/assets/config/qiniu.js +0 -23
  43. data/app/assets/config/qiniu1.js +0 -25
@@ -0,0 +1,481 @@
1
+ /* jslint newcap: true */
2
+ /* global XMLHttpRequest: false, FormData: false */
3
+
4
+ /*
5
+ * Input Field with Attachment
6
+ * Fork and Inspired by inlineAttachment(https://github.com/Rovak/InlineAttachment)
7
+ * Author: 覃明圆
8
+ * Contact: mingyuan0715@foxmail.com
9
+ */
10
+
11
+ (function(document, window) {
12
+ 'use strict';
13
+
14
+ var InputAttachment = function(options) {
15
+ this.settings = InputAttachment.util.merge(options, InputAttachment.defaults);
16
+ this.editor = InputAttachment.editors.initEditor(this.settings['editor']);
17
+ this.fileInput = InputAttachment.editors.initEditor(this.settings['fileInput']);
18
+ this.filenameTag = '{filename}';
19
+ this.lastValue = null;
20
+ };
21
+
22
+ /**
23
+ * Will holds the available editors
24
+ *
25
+ * @type {Object}
26
+ */
27
+ InputAttachment.editors = {
28
+
29
+ initEditor: function(input) {
30
+
31
+ return {
32
+ getValue: function() {
33
+ return input.value;
34
+ },
35
+
36
+ insertValue: function(val) {
37
+ InputAttachment.util.insertTextAtCursor(input, val);
38
+ },
39
+
40
+ setValue: function(val) {
41
+ input.value = val;
42
+ }
43
+ }
44
+ }
45
+ };
46
+
47
+ /**
48
+ * Utility functions
49
+ */
50
+ InputAttachment.util = {
51
+
52
+ /**
53
+ * Simple function to merge the given objects
54
+ *
55
+ * @param {Object[]} object Multiple object parameters
56
+ * @returns {Object}
57
+ */
58
+ merge: function() {
59
+ var result = {};
60
+ for (var i = arguments.length - 1; i >= 0; i--) {
61
+ var obj = arguments[i];
62
+ for (var k in obj) {
63
+ if (obj.hasOwnProperty(k)) {
64
+ result[k] = obj[k];
65
+ }
66
+ }
67
+ }
68
+ return result;
69
+ },
70
+
71
+ /**
72
+ * Append a line of text at the bottom, ensuring there aren't unnecessary newlines
73
+ *
74
+ * @param {String} appended Current content
75
+ * @param {String} previous Value which should be appended after the current content
76
+ */
77
+ appendInItsOwnLine: function(previous, appended) {
78
+ return (previous + "\n\n[[D]]" + appended)
79
+ .replace(/(\n{2,})\[\[D\]\]/, "\n\n")
80
+ .replace(/^(\n*)/, "");
81
+ },
82
+
83
+ /**
84
+ * Inserts the given value at the current cursor position of the textarea element
85
+ *
86
+ * @param {HtmlElement} el
87
+ * @param {String} value Text which will be inserted at the cursor position
88
+ */
89
+ insertTextAtCursor: function(el, text) {
90
+ var scrollPos = el.scrollTop,
91
+ strPos = 0,
92
+ browser = false,
93
+ range;
94
+
95
+ if ((el.selectionStart || el.selectionStart === '0')) {
96
+ browser = "ff";
97
+ } else if (document.selection) {
98
+ browser = "ie";
99
+ }
100
+
101
+ if (browser === "ie") {
102
+ el.focus();
103
+ range = document.selection.createRange();
104
+ range.moveStart('character', -el.value.length);
105
+ strPos = range.text.length;
106
+ } else if (browser === "ff") {
107
+ strPos = el.selectionStart;
108
+ }
109
+
110
+ var front = (el.value).substring(0, strPos);
111
+ var back = (el.value).substring(strPos, el.value.length);
112
+ el.value = front + text + back;
113
+ strPos = strPos + text.length;
114
+ if (browser === "ie") {
115
+ el.focus();
116
+ range = document.selection.createRange();
117
+ range.moveStart('character', -el.value.length);
118
+ range.moveStart('character', strPos);
119
+ range.moveEnd('character', 0);
120
+ range.select();
121
+ } else if (browser === "ff") {
122
+ el.selectionStart = strPos;
123
+ el.selectionEnd = strPos;
124
+ el.focus();
125
+ }
126
+ el.scrollTop = scrollPos;
127
+ }
128
+ };
129
+
130
+ /**
131
+ * Default configuration options
132
+ *
133
+ * @type {Object}
134
+ */
135
+ InputAttachment.defaults = {
136
+ /**
137
+ * URL where the file will be send
138
+ */
139
+ uploadUrl: 'upload_attachment.php',
140
+
141
+ /**
142
+ * Which method will be used to send the file to the upload URL
143
+ */
144
+ uploadMethod: 'POST',
145
+
146
+ /**
147
+ * Name in which the file will be placed
148
+ */
149
+ uploadFieldName: 'file',
150
+
151
+ uploadFileInput: '',
152
+
153
+ /**
154
+ * Extension which will be used when a file extension could not
155
+ * be detected
156
+ */
157
+ defaultExtension: 'png',
158
+
159
+ /**
160
+ * JSON field which refers to the uploaded file URL
161
+ */
162
+ jsonFieldName: 'filename',
163
+
164
+ /**
165
+ * Allowed MIME types
166
+ */
167
+ allowedTypes: [
168
+ 'image/jpeg',
169
+ 'image/png',
170
+ 'image/jpg',
171
+ 'image/gif'
172
+ ],
173
+
174
+ /**
175
+ * Text which will be inserted when dropping or pasting a file.
176
+ * Acts as a placeholder which will be replaced when the file is done with uploading
177
+ */
178
+ progressText: '![Uploading file...]()',
179
+
180
+ /**
181
+ * When a file has successfully been uploaded the progressText
182
+ * will be replaced by the urlText, the {filename} tag will be replaced
183
+ * by the filename that has been returned by the server
184
+ */
185
+ urlText: "![file]({filename})",
186
+
187
+ /**
188
+ * Text which will be used when uploading has failed
189
+ */
190
+ errorText: "Error uploading file",
191
+
192
+ /**
193
+ * Extra parameters which will be send when uploading a file
194
+ */
195
+ extraParams: {},
196
+
197
+ /**
198
+ * Extra headers which will be send when uploading a file
199
+ */
200
+ extraHeaders: {},
201
+
202
+ /**
203
+ * Before the file is send
204
+ */
205
+ beforeFileUpload: function() {
206
+ return true;
207
+ },
208
+
209
+ /**
210
+ * Triggers when a file is dropped or pasted
211
+ */
212
+ onFileReceived: function() {},
213
+
214
+ /**
215
+ * Custom upload handler
216
+ *
217
+ * @return {Boolean} when false is returned it will prevent default upload behavior
218
+ */
219
+ onFileUploadResponse: function() {
220
+ return true;
221
+ },
222
+
223
+ /**
224
+ * Custom error handler. Runs after removing the placeholder text and before the alert().
225
+ * Return false from this function to prevent the alert dialog.
226
+ *
227
+ * @return {Boolean} when false is returned it will prevent default error behavior
228
+ */
229
+ onFileUploadError: function() {
230
+ return true;
231
+ },
232
+
233
+ /**
234
+ * When a file has succesfully been uploaded
235
+ */
236
+ onFileUploaded: function() {}
237
+ };
238
+
239
+ /**
240
+ * Uploads the blob
241
+ *
242
+ * @param {Blob} file blob data received from event.dataTransfer object
243
+ * @return {XMLHttpRequest} request object which sends the file
244
+ */
245
+ InputAttachment.prototype.uploadFile = function(file) {
246
+ var me = this,
247
+ formData = new FormData(),
248
+ xhr = new XMLHttpRequest(),
249
+ settings = this.settings,
250
+ extension = settings.defaultExtension || settings.defualtExtension;
251
+
252
+ if (typeof settings.setupFormData === 'function') {
253
+ settings.setupFormData(formData, file);
254
+ }
255
+
256
+ // Attach the file. If coming from clipboard, add a default filename (only works in Chrome for now)
257
+ // http://stackoverflow.com/questions/6664967/how-to-give-a-blob-uploaded-as-formdata-a-file-name
258
+ if (file.name) {
259
+ var fileNameMatches = file.name.match(/\.(.+)$/);
260
+ if (fileNameMatches) {
261
+ extension = fileNameMatches[1];
262
+ }
263
+ }
264
+
265
+ var remoteFilename = "image-" + Date.now() + "." + extension;
266
+ if (typeof settings.remoteFilename === 'function') {
267
+ remoteFilename = settings.remoteFilename(file);
268
+ }
269
+
270
+ formData.append(settings.uploadFieldName, file, remoteFilename);
271
+
272
+ // Append the extra parameters to the formdata
273
+ if (typeof settings.extraParams === "object") {
274
+ for (var key in settings.extraParams) {
275
+ if (settings.extraParams.hasOwnProperty(key)) {
276
+ formData.append(key, settings.extraParams[key]);
277
+ }
278
+ }
279
+ }
280
+
281
+ xhr.open('POST', settings.uploadUrl);
282
+
283
+ // Add any available extra headers
284
+ if (typeof settings.extraHeaders === "object") {
285
+ for (var header in settings.extraHeaders) {
286
+ if (settings.extraHeaders.hasOwnProperty(header)) {
287
+ xhr.setRequestHeader(header, settings.extraHeaders[header]);
288
+ }
289
+ }
290
+ }
291
+
292
+ xhr.onload = function() {
293
+ // If HTTP status is OK or Created
294
+ if (xhr.status === 200 || xhr.status === 201) {
295
+ me.onFileUploadResponse(xhr);
296
+ } else {
297
+ me.onFileUploadError(xhr);
298
+ }
299
+ };
300
+ if (settings.beforeFileUpload(xhr) !== false) {
301
+ xhr.send(formData);
302
+ }
303
+ return xhr;
304
+ };
305
+
306
+ /**
307
+ * Returns if the given file is allowed to handle
308
+ *
309
+ * @param {File} clipboard data file
310
+ */
311
+ InputAttachment.prototype.isFileAllowed = function(file) {
312
+ if (file.kind === 'string') { return false; }
313
+ if (this.settings.allowedTypes.indexOf('*') === 0){
314
+ return true;
315
+ } else {
316
+ return this.settings.allowedTypes.indexOf(file.type) >= 0;
317
+ }
318
+ };
319
+
320
+ /**
321
+ * Handles upload response
322
+ *
323
+ * @param {XMLHttpRequest} xhr
324
+ * @return {Void}
325
+ */
326
+ InputAttachment.prototype.onFileUploadResponse = function(xhr) {
327
+ if (this.settings.onFileUploadResponse.call(this, xhr) !== false) {
328
+ var result = JSON.parse(xhr.responseText),
329
+ filename = result[this.settings.jsonFieldName];
330
+
331
+ if (result && filename) {
332
+ var newValue;
333
+ if (typeof this.settings.urlText === 'function') {
334
+ newValue = this.settings.urlText.call(this, filename, result);
335
+ } else {
336
+ newValue = this.settings.urlText.replace(this.filenameTag, filename);
337
+ }
338
+ var text = this.editor.getValue().replace(this.lastValue, newValue);
339
+ this.editor.setValue(text);
340
+ this.settings.onFileUploaded.call(this, filename);
341
+ }
342
+ }
343
+ };
344
+
345
+
346
+ /**
347
+ * Called when a file has failed to upload
348
+ *
349
+ * @param {XMLHttpRequest} xhr
350
+ * @return {Void}
351
+ */
352
+ InputAttachment.prototype.onFileUploadError = function(xhr) {
353
+ if (this.settings.onFileUploadError.call(this, xhr) !== false) {
354
+ var text = this.editor.getValue().replace(this.lastValue, "");
355
+ this.editor.setValue(text);
356
+ }
357
+ };
358
+
359
+ /**
360
+ * Called when a file has been inserted, either by drop or paste
361
+ *
362
+ * @param {File} file
363
+ * @return {Void}
364
+ */
365
+ InputAttachment.prototype.onFileInserted = function(file) {
366
+ if (this.settings.onFileReceived.call(this, file) !== false) {
367
+ this.lastValue = this.settings.progressText;
368
+ this.editor.insertValue(this.lastValue);
369
+ }
370
+ };
371
+
372
+
373
+ /**
374
+ * Called when a paste event occured
375
+ * @param {Event} e
376
+ * @return {Boolean} if the event was handled
377
+ */
378
+ InputAttachment.prototype.onPaste = function(e) {
379
+ var result = false,
380
+ clipboardData = e.clipboardData,
381
+ items;
382
+
383
+ if (typeof clipboardData === "object") {
384
+ items = clipboardData.items || clipboardData.files || [];
385
+
386
+ for (var i = 0; i < items.length; i++) {
387
+ var item = items[i];
388
+ if (this.isFileAllowed(item)) {
389
+ result = true;
390
+ this.onFileInserted(item.getAsFile());
391
+ this.uploadFile(item.getAsFile());
392
+ }
393
+ }
394
+ }
395
+
396
+ if (result) { e.preventDefault(); }
397
+
398
+ return result;
399
+ };
400
+
401
+ /**
402
+ * Called when a drop event occurs
403
+ * @param {Event} e
404
+ * @return {Boolean} if the event was handled
405
+ */
406
+ InputAttachment.prototype.onDrop = function(e) {
407
+ var result = false;
408
+ for (var i = 0; i < e.dataTransfer.files.length; i++) {
409
+ var file = e.dataTransfer.files[i];
410
+ if (this.isFileAllowed(file)) {
411
+ result = true;
412
+ this.onFileInserted(file);
413
+ this.uploadFile(file);
414
+ }
415
+ }
416
+
417
+ return result;
418
+ };
419
+
420
+ InputAttachment.prototype.onFileInputChange = function(e) {
421
+ var result = false;
422
+ for (var i = 0; i < e.target.files.length; i++) {
423
+ var file = e.target.files[i];
424
+ if (this.isFileAllowed(file)) {
425
+ result = true;
426
+ this.uploadFile(file);
427
+ }
428
+ }
429
+
430
+ return result;
431
+ };
432
+
433
+ InputAttachment.prototype.onFileInputClick = function(e) {
434
+ console.log('fileInputClick', e)
435
+ };
436
+
437
+ window.InputAttachment = InputAttachment;
438
+
439
+ function attachToInput(options) {
440
+ options = options || {};
441
+ var input = document.getElementById(options['input']);
442
+ var fileInput = document.getElementById(options['fileInput']);
443
+ options['editor'] = input;
444
+ options['fileInput'] = fileInput;
445
+ var inlineattach = new InputAttachment(options);
446
+
447
+ if (input) {
448
+ input.addEventListener('paste', function(e) {
449
+ inlineattach.onPaste(e);
450
+ }, false);
451
+
452
+ input.addEventListener('drop', function(e) {
453
+ e.stopPropagation();
454
+ e.preventDefault();
455
+ inlineattach.onDrop(e);
456
+ }, false);
457
+
458
+ input.addEventListener('dragenter', function(e) {
459
+ e.stopPropagation();
460
+ e.preventDefault();
461
+ }, false);
462
+
463
+ input.addEventListener('dragover', function(e) {
464
+ e.stopPropagation();
465
+ e.preventDefault();
466
+ }, false);
467
+ }
468
+ if (fileInput) {
469
+ fileInput.addEventListener('click', function(e) {
470
+ inlineattach.onFileInputClick(e)
471
+ }, false);
472
+
473
+ fileInput.addEventListener('change', function(e) {
474
+ inlineattach.onFileInputChange(e)
475
+ }, false);
476
+ }
477
+ }
478
+
479
+ window.attachToInput = attachToInput;
480
+
481
+ })(document, window);