├── .npm └── package │ ├── .gitignore │ ├── npm-shrinkwrap.json │ └── README ├── autoform-cloudinary.css ├── package.js ├── README.md ├── autoform-cloudinary.html ├── autoform-cloudinary-server.js └── autoform-cloudinary.js /.npm/package/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /autoform-cloudinary.css: -------------------------------------------------------------------------------- 1 | .afCloudinary-thumbnail img { 2 | width: 200px; 3 | } 4 | -------------------------------------------------------------------------------- /.npm/package/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "cloudinary": { 4 | "version": "1.2.1", 5 | "dependencies": { 6 | "q": { 7 | "version": "1.4.1" 8 | }, 9 | "lodash": { 10 | "version": "3.6.0" 11 | } 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.npm/package/README: -------------------------------------------------------------------------------- 1 | This directory and the files immediately inside it are automatically generated 2 | when you change this package's NPM dependencies. Commit the files in this 3 | directory (npm-shrinkwrap.json, .gitignore, and this README) to source control 4 | so that others run the same versions of sub-dependencies. 5 | 6 | You should NOT check in the node_modules directory that Meteor automatically 7 | creates; if you are using git, the .gitignore file tells git to ignore it. 8 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: 'cosio55:autoform-cloudinary', 3 | git: 'https://github.com/cosio55/autoform-cloudinary.git', 4 | summary: 'Use Cloudinary with autoform/simpleschema to upload an image, and save the url on the collection.', 5 | version: '0.0.2' 6 | }); 7 | 8 | Package.onUse(function (api) { 9 | Npm.depends({ 10 | cloudinary: '1.2.1' 11 | }); 12 | 13 | api.versionsFrom('1.1.0.2'); 14 | 15 | api.use([ 16 | 'templating', 17 | 'reactive-var', 18 | 'underscore', 19 | 'check', 20 | 'nekojira:cloudinary-jquery-upload@0.1.0', 21 | 'aldeed:autoform@5.3.0' 22 | ], 'client'); 23 | 24 | api.addFiles([ 25 | 'autoform-cloudinary.html', 26 | 'autoform-cloudinary.css', 27 | 'autoform-cloudinary.js' 28 | ], 'client'); 29 | 30 | api.addFiles([ 31 | 'autoform-cloudinary-server.js' 32 | ], 'server'); 33 | }); 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | 4 | This package lets you use Cloudinary with autoform/simpleschema to easily upload an image to your Cloudinary account, and it automatically saves the url for the image using autoform. 5 | 6 | Usage 7 | ===== 8 | 9 | 1. `meteor add cosio55:autoform-cloudinary` 10 | 11 | 2. Set up settings.json file 12 | 13 | ```json 14 | { 15 | "public": { 16 | "CLOUDINARY_API_KEY": "[YOUR API KEY]", 17 | "CLOUDINARY_CLOUD_NAME": "[YOUR CLOUD NAME]" 18 | }, 19 | 20 | "CLOUDINARY_API_SECRET": "[YOUR API SECRET]" 21 | } 22 | ``` 23 | 24 | 3. Create collection and attach simple schema 25 | 26 | ```javascript 27 | Images = new Mongo.Collection('images'); 28 | 29 | Images.attachSchema(new SimpleSchema({ 30 | image: { 31 | type: String, 32 | autoform: { 33 | afFieldInput: { 34 | type: 'cloudinary' 35 | } 36 | } 37 | } 38 | })); 39 | ``` 40 | 41 | 4. Create quick form 42 | 43 | ```html 44 | 47 | ``` 48 | 49 | 5. Run meteor 50 | 51 | `meteor --settings settings.json` 52 | -------------------------------------------------------------------------------- /autoform-cloudinary.html: -------------------------------------------------------------------------------- 1 | 27 | 28 | 55 | -------------------------------------------------------------------------------- /autoform-cloudinary-server.js: -------------------------------------------------------------------------------- 1 | var cloudinary = Npm.require('cloudinary'); 2 | 3 | if (process.env.CLOUDINARY_URL) { 4 | var cloudinaryURL = new URI(process.env.CLOUDINARY_URL); 5 | } 6 | 7 | Meteor.methods({ 8 | afCloudinarySign: function (params) { 9 | check(params, Match.Optional(Object)); 10 | 11 | params = params || {}; 12 | params.timestamp = (new Date).getTime(); 13 | 14 | return cloudinary.utils.sign_request(params, { 15 | api_key: apiKey(), 16 | api_secret: apiSecret() 17 | }); 18 | }, 19 | publicCredentials: function() { 20 | if (cloudinaryURL) { 21 | return { 22 | cloudName: apiHost(), 23 | apiKey: apiKey() 24 | } 25 | } 26 | } 27 | }); 28 | 29 | apiHost = function() { 30 | if (cloudinaryURL) { 31 | return cloudinaryURL.hostname(); 32 | } 33 | }; 34 | 35 | apiKey = function () { 36 | if (cloudinaryURL) { 37 | return cloudinaryURL.username(); 38 | } 39 | 40 | if (! Meteor.settings || 41 | ! Meteor.settings.public || 42 | ! Meteor.settings.public.CLOUDINARY_API_KEY) { 43 | throw new Error('Meteor.settings.public.CLOUDINARY_API_KEY is undefined'); 44 | } 45 | 46 | return Meteor.settings.public.CLOUDINARY_API_KEY; 47 | }; 48 | 49 | apiSecret = function () { 50 | if (cloudinaryURL) { 51 | return cloudinaryURL.password(); 52 | } 53 | 54 | if (! Meteor.settings || 55 | ! Meteor.settings.CLOUDINARY_API_SECRET) { 56 | throw new Error('Meteor.settings.CLOUDINARY_API_SECRET is undefined'); 57 | } 58 | 59 | return Meteor.settings.CLOUDINARY_API_SECRET; 60 | }; 61 | -------------------------------------------------------------------------------- /autoform-cloudinary.js: -------------------------------------------------------------------------------- 1 | AutoForm.addInputType('cloudinary', { 2 | template: 'afCloudinary', 3 | 4 | valueOut: function () { 5 | return this.val(); 6 | } 7 | }); 8 | 9 | Meteor.startup(function () { 10 | Meteor.call('publicCredentials', function(err, res) { 11 | if (res) { 12 | $.cloudinary.config({ 13 | cloud_name: res.cloudName, 14 | api_key: res.apiKey 15 | }); 16 | } else { 17 | $.cloudinary.config({ 18 | cloud_name: Meteor.settings.public.CLOUDINARY_CLOUD_NAME, 19 | api_key: Meteor.settings.public.CLOUDINARY_API_KEY 20 | }); 21 | } 22 | }); 23 | }); 24 | 25 | var templates = ['afCloudinary', 'afCloudinary_bootstrap3']; 26 | 27 | _.each(templates, function (tmpl) { 28 | Template[tmpl].onCreated(function () { 29 | var self = this; 30 | 31 | self.url = new ReactiveVar(); 32 | 33 | self.initialValueChecked = false; 34 | self.checkInitialValue = function () { 35 | Tracker.nonreactive(function () { 36 | if (! self.initialValueChecked && ! self.url.get() && self.data.value) { 37 | self.url.set(self.data.value); 38 | self.initialValueChecked = true; 39 | } 40 | }); 41 | }; 42 | }); 43 | 44 | Template[tmpl].onRendered(function () { 45 | var self = this; 46 | 47 | Meteor.call('afCloudinarySign', function (err, res) { 48 | if (err) { 49 | return console.log(err); 50 | } 51 | 52 | self.$('input[name=file]').cloudinary_fileupload({ 53 | formData: res 54 | }); 55 | }); 56 | 57 | self.$('input[name=file]').on('fileuploaddone', function (e, data) { 58 | self.url.set(data.result.secure_url); 59 | Tracker.flush(); 60 | }); 61 | 62 | self.$(self.firstNode).closest('form').on('reset', function () { 63 | self.url.set(null); 64 | }); 65 | }); 66 | 67 | Template[tmpl].helpers({ 68 | url: function () { 69 | var t = Template.instance(); 70 | 71 | t.checkInitialValue(); 72 | return t.url.get(); 73 | }, 74 | 75 | accept: function () { 76 | return this.atts.accept || 'image/*'; 77 | } 78 | }); 79 | 80 | Template[tmpl].events({ 81 | 'click button': function (e, t) { 82 | t.$('input[name=file]').click(); 83 | }, 84 | 85 | 'click .js-remove': function (e, t) { 86 | e.preventDefault(); 87 | t.url.set(null); 88 | } 89 | }); 90 | }); 91 | --------------------------------------------------------------------------------