From 7b01f17149813000d3c67f5a0a88f2b98f42b5f1 Mon Sep 17 00:00:00 2001 From: Itai Benari Date: Mon, 26 May 2014 18:03:52 +0300 Subject: [PATCH] initial commit: 0.1.0 --- .gitignore | 4 + README.md | 83 ++++++++++++ bower.json | 12 ++ js/angular.cloudinary.js | 114 +++++++++++++++++ samples/photo_album/README.md | 55 ++++++++ samples/photo_album/app/css/.gitkeep | 0 samples/photo_album/app/css/animations.css | 97 ++++++++++++++ samples/photo_album/app/css/app.css | 90 +++++++++++++ samples/photo_album/app/index.html | 37 ++++++ samples/photo_album/app/js/animations.js | 52 ++++++++ samples/photo_album/app/js/app.js | 38 ++++++ samples/photo_album/app/js/config.js.sample | 2 + samples/photo_album/app/js/controllers.js | 47 +++++++ samples/photo_album/app/js/services.js | 13 ++ samples/photo_album/app/partials/.gitkeep | 0 .../photo_album/app/partials/photo-list.html | 118 ++++++++++++++++++ .../app/partials/photo-upload.html | 40 ++++++ samples/photo_album/bower.json | 15 +++ samples/photo_album/package.json | 17 +++ 19 files changed, 834 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 bower.json create mode 100644 js/angular.cloudinary.js create mode 100644 samples/photo_album/README.md create mode 100644 samples/photo_album/app/css/.gitkeep create mode 100644 samples/photo_album/app/css/animations.css create mode 100644 samples/photo_album/app/css/app.css create mode 100644 samples/photo_album/app/index.html create mode 100644 samples/photo_album/app/js/animations.js create mode 100644 samples/photo_album/app/js/app.js create mode 100644 samples/photo_album/app/js/config.js.sample create mode 100644 samples/photo_album/app/js/controllers.js create mode 100644 samples/photo_album/app/js/services.js create mode 100644 samples/photo_album/app/partials/.gitkeep create mode 100644 samples/photo_album/app/partials/photo-list.html create mode 100644 samples/photo_album/app/partials/photo-upload.html create mode 100644 samples/photo_album/bower.json create mode 100644 samples/photo_album/package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aff53a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules +bower_components +config.js +*.log \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..cfaa953 --- /dev/null +++ b/README.md @@ -0,0 +1,83 @@ +Cloudinary +========== + +Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline. + +Easily upload images to the cloud. Automatically perform smart image resizing, cropping and conversion without installing any complex software. Integrate Facebook or Twitter profile image extraction in a snap, in any dimension and style to match your website’s graphics requirements. Images are seamlessly delivered through a fast CDN, and much much more. + +Cloudinary offers comprehensive APIs and administration capabilities and is easy to integrate with any web application, existing or new. + +Cloudinary provides URL and HTTP based APIs that can be easily integrated with any Web development framework. + +For AngularJS, Cloudinary provides a plugin for simplifying the integration even further. The plugin serves as a layer on top the [Cloudinary jQuery plugin](http://cloudinary.com/documentation/jquery_integration#installation) + +## Setup ###################################################################### + +Follow the setup procedure described in the [Cloudinary jQuery plugin](https://github.com/cloudinary/cloudinary_js#setup) setup procedure. The sample project contained in this repository can serve as an example. + + +## Usage ###################################################################### + +The plugin provides two angular directives. URL directive and image tag directive. + +### Image tag generation directive - cl-image ################################## + +Similarly to the above this directive will generate an image tag with requested transformation, type, and format. The image tag can contain transformation tags that will be used as piped transformations: + + + + + +Will be translated to: + + + +For a complete list of image manipulation options see [this reference](http://cloudinary.com/documentation/image_transformations#reference). + +### Manipulation URL generation directives - cl-src, cl-href, cl-srcset ####### + +These directives transform the given URI to a cloudinary URL. For example: + + + +Will be transformed to: + + + + +### Uploading images + +You can upload image sdirectly from the browser using Cloudinaty's jQuery plugin from you AngularJS app. See the sample [photo album app](https://github.com/cloudinary/cloudinary_angular/tree/master/samples/photo_album) for a usage example. + + +## Samples + +You can find our simple and ready-to-use samples projects, along with documentation in the [samples folder](https://github.com/cloudinary/cloudinary_angular/tree/master/samples/photo_album). +Please consult with the [README file](https://github.com/cloudinary/cloudinary_angular/blob/master/samples/photo_album/README.md), for usage and explanations. + + +## Additional resources ########################################################## + +Additional resources are available at: + +* [Website](http://cloudinary.com) +* [Documentation](http://cloudinary.com/documentation) +* [Knowledge Base](http://support.cloudinary.com/forums) +* [Documentation for jQuery integration](http://cloudinary.com/documentation/jquery_integration) +* [Image upload documentation](http://cloudinary.com/documentation/upload_images) +* [Image transformations documentation](http://cloudinary.com/documentation/image_transformations) + +## Support + +You can [open an issue through GitHub](https://github.com/cloudinary/cloudinary_gem/issues). + +Contact us [http://cloudinary.com/contact](http://cloudinary.com/contact) + +Stay tuned for updates, tips and tutorials: [Blog](http://cloudinary.com/blog), [Twitter](https://twitter.com/cloudinary), [Facebook](http://www.facebook.com/Cloudinary). + + +## License ####################################################################### + +Released under the MIT license. \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..c71f104 --- /dev/null +++ b/bower.json @@ -0,0 +1,12 @@ +{ + "name": "cloudinary_ng", + "description": "A set of AngularJS directives/helpers for using Cloudinary with AngularJS", + "version": "0.1.0", + "homepage": "https://github.com/cloudinary/cloudinary_agular", + "license": "MIT", + "private": true, + "dependencies": { + "angular": "1.2.x", + "cloudinary_js": ">=1.0.16" + } +} diff --git a/js/angular.cloudinary.js b/js/angular.cloudinary.js new file mode 100644 index 0000000..fe3742c --- /dev/null +++ b/js/angular.cloudinary.js @@ -0,0 +1,114 @@ +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery.cloudinary', + 'angular' + ], factory); + } else { + // Browser globals: + factory(window.jQuery, angular); + } +}(function ($, angular) { + + var angularModule = angular.module('cloudinary', []); + + var cloudinaryAttr = function(attr){ + if (attr.match(/cl[A-Z]/)) attr = attr.substring(2); + return attr.replace(/([a-z])([A-Z])/g,'$1_$2').toLowerCase(); + }; + + + ['Src', 'Srcset', 'Href'].forEach(function(attrName) { + var normalized = 'cl' + attrName; + attrName = attrName.toLowerCase(); + angularModule.directive(normalized, function($sniffer) { + return { + priority: 99, // it needs to run after the attributes are interpolated + link: function(scope, element, attr) { + var propName = attrName, + name = attrName; + + if (attrName === 'href' && + toString.call(element.prop('href')) === '[object SVGAnimatedString]') { + name = 'xlinkHref'; + attr.$attr[name] = 'xlink:href'; + propName = null; + } + + attr.$observe(normalized, function(value) { + if (!value) + return; + + var attributes = {} + $.each(element[0].attributes, function(){attributes[cloudinaryAttr(this.name)] = this.value}); + value = $.cloudinary.url(value, attributes); + attr.$set(name, value); + + // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist + // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need + // to set the property as well to achieve the desired effect. + // we use attr[attrName] value since $set can sanitize the url. + if ($sniffer.msie && propName) element.prop(propName, attr[name]); + }); + } + }; + }); + }); + + angularModule.directive('clTransformation', function() { + return { + restrict : 'E', + transclude : false, + require: '^clImage', + link : function (scope, element, attrs, clImageCtrl) { + var attributes = {}; + $.each(attrs, function(name,value){ + if (name[0] !== '$') { + attributes[cloudinaryAttr(name)] = value; + } + }); + clImageCtrl.addTransformation(attributes); + } + } + }); + + angularModule.directive('clImage', function() { + return { + restrict : 'E', + replace: true, + transclude : true, + template: "", + scope: {}, + controller: function($scope) { + this.addTransformation = function(ts){ + $scope.transformations = $scope.transformations || []; + $scope.transformations.push(ts); + } + }, + // The linking function will add behavior to the template + link : function(scope, element, attrs) { + var attributes = {}; + $.each(attrs, function(name, value){attributes[cloudinaryAttr(name)] = value}); + + if (scope.transformations) { + attributes.transformation = scope.transformations; + } + + var url = $.cloudinary.url(attrs.publicId, attributes); + element.attr('src', url); + if (attrs.htmlWidth) { + element.attr("width", attrs.htmlWidth); + } else { + element.removeAttr("width"); + } + if (attrs.htmlHeight) { + element.attr("height", attrs.htmlHeight); + } else { + element.removeAttr("height"); + } + } + }; + }); +})); \ No newline at end of file diff --git a/samples/photo_album/README.md b/samples/photo_album/README.md new file mode 100644 index 0000000..9eb22f9 --- /dev/null +++ b/samples/photo_album/README.md @@ -0,0 +1,55 @@ +Cloudinary AngularJS Photo Album Sample +======================================= + +This sample project shows: + +1. How to use the Cloudinary AngularJS directives. +2. How to upload files in an unsigned manner, using an upload preset, to Cloudinary. +3. How to use the dynamic list resource in order to maintain short list of resources aggregated by tags. + +## Configuration ## + +There are 2 settings you need to change for this demo to work. Copy or rename `app/js/config.js.sample` to `app/js/config.js` and edit the following: + +1. **cloud_name** - Should be change to the cloud name you received when you registered for a Cloudinary account. +2. **upload_preset** - You should first "Enable unsigned uploads" in the ["Upload Settings"](https://cloudinary.com/console/settings/upload) of your Cloudinary console and assign the resulting preset name to that field. Note, you may want to tweak and modify the upload preset's parameters. + +## Setup ## + +This sample uses Node's "http-server" to serve as simple http server. No other server components are required. For client side package management Bower is used. + +## Running ## + + npm start + +Then go to + + http://localhost:8000/app + +## Internals ## + +### Directives ### + +The `index.html` page and the `photo-upload.html` partial give some examples of both the URL directive and Image directive. + +### Unsignd Upload ### + +In order to add images to our photo album that would later be rettrievable from the Cloudinary service we must select a tag which will serve as our source for the list. In this case `myphotoalbum`. While this can tag can actually be set in the upload preset and be hidden from the client side, in this sample we included it in the request itself to make this sample work without fursther configuration steps. + +The `photoUploadCtrl` uses the Cloudinary JQuery library in order to configure the direct upload widget. Notice that changes to the title field are propagated to the `formData` being sent in the upload request. This is meant to illustrate the possiblity of attaching extra meta-data to each upload image. + +Also note, this upload widget uses the `upload_preset` we configured in Configuration step. This uses the settings defined on Cloudinary side to process the uploaded file. + +### List Resource ### + +Cloudinary supports a JSON list resource. This list represents all resources marked with a specific tag during upload (or later through other APIs). Whenever one a new resource is tagged or an existing resource already tagged is deleted the list is recomputed. This enables you to group a limited quantity of resources (100 currently) and make them retrievable for client only applications. + +The list retrieval is done here in this sample using the Angular's service using `myphotoalbum` as the seed tag. + +Notes: + +1. Currently the list is cached for 1 minute in the CDN. +2. As mentioned above the maximum number of returned resources in the list 100 + + +### diff --git a/samples/photo_album/app/css/.gitkeep b/samples/photo_album/app/css/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/samples/photo_album/app/css/animations.css b/samples/photo_album/app/css/animations.css new file mode 100644 index 0000000..a525e9d --- /dev/null +++ b/samples/photo_album/app/css/animations.css @@ -0,0 +1,97 @@ +/* + * animations css stylesheet + */ + +/* animate ngRepeat in photo listing */ + +.photo-listing.ng-enter, +.photo-listing.ng-leave, +.photo-listing.ng-move { + -webkit-transition: 0.5s linear all; + -moz-transition: 0.5s linear all; + -o-transition: 0.5s linear all; + transition: 0.5s linear all; +} + +.photo-listing.ng-enter, +.photo-listing.ng-move { + opacity: 0; + height: 0; + overflow: hidden; +} + +.photo-listing.ng-move.ng-move-active, +.photo-listing.ng-enter.ng-enter-active { + opacity: 1; + height: 120px; +} + +.photo-listing.ng-leave { + opacity: 1; + overflow: hidden; +} + +.photo-listing.ng-leave.ng-leave-active { + opacity: 0; + height: 0; + padding-top: 0; + padding-bottom: 0; +} + +/* cross fading between routes with ngView */ + +.view-container { + position: relative; +} + +.view-frame.ng-enter, +.view-frame.ng-leave { + background: white; + position: absolute; + top: 0; + left: 0; + right: 0; +} + +.view-frame.ng-enter { + -webkit-animation: 0.5s fade-in; + -moz-animation: 0.5s fade-in; + -o-animation: 0.5s fade-in; + animation: 0.5s fade-in; + z-index: 100; +} + +.view-frame.ng-leave { + -webkit-animation: 0.5s fade-out; + -moz-animation: 0.5s fade-out; + -o-animation: 0.5s fade-out; + animation: 0.5s fade-out; + z-index: 99; +} + +@keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} +@-moz-keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} +@-webkit-keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes fade-out { + from { opacity: 1; } + to { opacity: 0; } +} +@-moz-keyframes fade-out { + from { opacity: 1; } + to { opacity: 0; } +} +@-webkit-keyframes fade-out { + from { opacity: 1; } + to { opacity: 0; } +} + diff --git a/samples/photo_album/app/css/app.css b/samples/photo_album/app/css/app.css new file mode 100644 index 0000000..a4fac58 --- /dev/null +++ b/samples/photo_album/app/css/app.css @@ -0,0 +1,90 @@ +body { font-family: Helvetica, Arial, sans-serif; color: #333; margin: 10px; width: 960px; word-wrap: break-word; } +#posterframe { position: absolute; right: 10px; top: 10px; } +h1 { color: #0e2953; font-size: 18px; } +h2 { color: #666; font-size: 16px; } +p { font-size: 14px; line-height: 18px; } +#logo { height: 51px; width: 241px; } +a { color: #0b63b6 } + +.actions { margin: 20px 0; } +.upload_link { color: #000; border: 1px solid #aaa; background-color: #e0e0e0; + font-size: 18px; padding: 5px 10px; width: 250px; margin: 10px 0 20px 0; + font-weight: bold; text-align: center; text-decoration: none; margin: 5px; } + +.photo { margin: 10px; padding: 10px; border-top: 2px solid #ccc; } +.photo .thumbnail { margin-top: 10px; display: block; max-width: 200px; border: none; } +.toggle_info { margin-top: 10px; font-weight: bold; color: #e62401; display: block; } +.thumbnail_holder { height: 182px; margin-bottom: 5px; margin-right: 10px; } +.info td, .uploaded_info td { font-size: 12px } +.note { margin: 20px 0} + +.inline { display: inline-block; } +td { vertical-align: top; padding-right: 5px; } + +#backend_upload, #direct_upload { padding: 20px 20px; margin: 20px 0; + border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; } + +#backend_upload h1, #direct_upload h1 { margin: 0 0 15px 0; } + +.back_link { font-weight: bold; display: block; font-size: 16px; margin: 10px 0; } + +form { border: 1px solid #ddd; margin: 15px 0; padding: 15px 0; border-radius: 4px; } +form .form_line { margin-bottom: 20px; } +form .form_controls { margin-left: 180px; } +form label { float: left; width: 160px; padding-top: 3px; text-align: right; } +form .error { color: #c55; margin: 0 10px; } + +#direct_upload { border: 4px dashed #ccc; } + +.upload_details { font-size: 12px; margin: 20px; border-top: 1px solid #ccc; word-wrap: break-word; } + +.upload_button_holder { + position: relative; + display: inline-block; + overflow: hidden; +} + +.upload_button_holder .upload_button { + display: block; + position: relative; + font-weight: bold; + font-size: 14px; + background-color: rgb(15, 97, 172); + color: #fff; + padding: 5px 0; + border: 1px solid #000; + border-radius: 4px; + width: 100px; + height: 18px; + text-decoration: none; + text-align: center; + cursor: pointer; +} + +.upload_button_holder:hover .upload_button { + background-color: rgb(17, 133, 240); +} + +.upload_button_holder .cloudinary_fileupload { + opacity: 0; + filter: alpha(opacity=0); + cursor: pointer; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + border: none; +} +.progress-bar{ + width: 100px; + position: relative; + height: 4px; +} +.progress-bar .progress{ + height: 4px; + background-color: #ff0000; + width: 0%; +} \ No newline at end of file diff --git a/samples/photo_album/app/index.html b/samples/photo_album/app/index.html new file mode 100644 index 0000000..f4f4c5c --- /dev/null +++ b/samples/photo_album/app/index.html @@ -0,0 +1,37 @@ + + + + + Photo Album + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + diff --git a/samples/photo_album/app/js/animations.js b/samples/photo_album/app/js/animations.js new file mode 100644 index 0000000..8ff1a6f --- /dev/null +++ b/samples/photo_album/app/js/animations.js @@ -0,0 +1,52 @@ +var photoAlbumAnimations = angular.module('photoAlbumAnimations', ['ngAnimate']); + +photoAlbumAnimations.animation('.photo', function() { + + var animateUp = function(element, className, done) { + if(className != 'active') { + return; + } + element.css({ + position: 'absolute', + top: 500, + left: 0, + display: 'block' + }); + + jQuery(element).animate({ + top: 0 + }, done); + + return function(cancel) { + if(cancel) { + element.stop(); + } + }; + } + + var animateDown = function(element, className, done) { + if(className != 'active') { + return; + } + element.css({ + position: 'absolute', + left: 0, + top: 0 + }); + + jQuery(element).animate({ + top: -500 + }, done); + + return function(cancel) { + if(cancel) { + element.stop(); + } + }; + } + + return { + addClass: animateUp, + removeClass: animateDown + }; +}); diff --git a/samples/photo_album/app/js/app.js b/samples/photo_album/app/js/app.js new file mode 100644 index 0000000..4e5b6e4 --- /dev/null +++ b/samples/photo_album/app/js/app.js @@ -0,0 +1,38 @@ +'use strict'; + +/* App Module */ +var photoAlbumApp = angular.module('photoAlbumApp', [ + 'ngRoute', + 'cloudinary', + 'photoAlbumAnimations', + 'photoAlbumControllers', + 'photoAlbumServices' +]); + +photoAlbumApp.config(['$routeProvider', + function($routeProvider) { + $routeProvider. + when('/photos', { + templateUrl: 'partials/photo-list.html', + resolve: { + photoList: function($q, $rootScope, album) { + if (!$rootScope.serviceCalled) { + return album.photos({}, function(v){ + $rootScope.serviceCalled = true; + $rootScope.photos = v.resources; + }); + } else { + return $q.when(true); + } + } + } + }). + when('/photos/new', { + templateUrl: 'partials/photo-upload.html', + controller: 'photoUploadCtrl' + }). + otherwise({ + redirectTo: '/photos' + }); + }]); + diff --git a/samples/photo_album/app/js/config.js.sample b/samples/photo_album/app/js/config.js.sample new file mode 100644 index 0000000..0d48a8a --- /dev/null +++ b/samples/photo_album/app/js/config.js.sample @@ -0,0 +1,2 @@ +$.cloudinary.config().cloud_name = 'XXXXXXXXX'; +$.cloudinary.config().upload_preset = 'YYYYYYYY'; \ No newline at end of file diff --git a/samples/photo_album/app/js/controllers.js b/samples/photo_album/app/js/controllers.js new file mode 100644 index 0000000..983b0e7 --- /dev/null +++ b/samples/photo_album/app/js/controllers.js @@ -0,0 +1,47 @@ +'use strict'; + +/* Controllers */ + +var photoAlbumControllers = angular.module('photoAlbumControllers', []); + +photoAlbumControllers.controller('photoUploadCtrl', ['$scope', '$rootScope', '$routeParams', '$location', + function($scope, $rootScope, $routeParams, $location) { + + $scope.updateTitle = function(){ + var uploadParams = $scope.widget.fileupload('option', 'formData'); + uploadParams["context"] = "photo=" + $scope.title; + $scope.widget.fileupload('option', 'formData', uploadParams); + }; + + $scope.widget = $(".cloudinary_fileupload") + .unsigned_cloudinary_upload($.cloudinary.config().upload_preset, {tags: 'myphotoalbum', context:'photo='}, { + // Uncomment the following lines to enable client side image resizing and valiation. + // Make sure cloudinary/processing is included the js file + //disableImageResize: false, + //imageMaxWidth: 800, + //imageMaxHeight: 600, + //acceptFileTypes: /(\.|\/)(gif|jpe?g|png|bmp|ico)$/i, + //maxFileSize: 20000000, // 20MB + dropZone: "#direct_upload", + start: function (e) { + $scope.status = "Starting upload..."; + $scope.$apply(); + }, + fail: function (e, data) { + $scope.status = "Upload failed"; + $scope.$apply(); + } + }) + .on("cloudinaryprogressall", function (e, data) { + $scope.progress = Math.round((data.loaded * 100.0) / data.total); + $scope.status = "Uploading... " + $scope.progress + "%"; + $scope.$apply(); + }) + .on("cloudinarydone", function (e, data) { + $rootScope.photos = $rootScope.photos || []; + data.result.context = {custom: {photo: $scope.title}}; + $scope.result = data.result; + $rootScope.photos.push(data.result); + $scope.$apply(); + }); + }]); \ No newline at end of file diff --git a/samples/photo_album/app/js/services.js b/samples/photo_album/app/js/services.js new file mode 100644 index 0000000..ba649b4 --- /dev/null +++ b/samples/photo_album/app/js/services.js @@ -0,0 +1,13 @@ +'use strict'; + +var photoAlbumServices = angular.module('photoAlbumServices', ['ngResource']); + +photoAlbumServices.factory('album', ['$rootScope', '$resource', + function($rootScope, $resource){ + var url = $.cloudinary.url('myphotoalbum', {format: 'json', type: 'list'}); + //cache bust + url = url + "?" + Math.ceil(new Date().getTime()/1000); + return $resource(url, {}, { + photos: {method:'GET', isArray:false} + }); + }]); \ No newline at end of file diff --git a/samples/photo_album/app/partials/.gitkeep b/samples/photo_album/app/partials/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/samples/photo_album/app/partials/photo-list.html b/samples/photo_album/app/partials/photo-list.html new file mode 100644 index 0000000..ea9a631 --- /dev/null +++ b/samples/photo_album/app/partials/photo-list.html @@ -0,0 +1,118 @@ +
+ + + + +
+ +

Welcome!

+ +

+ This is the main demo page of the PhotoAlbum sample AngularJS application of Cloudinary.
+ Here you can see all images you have uploaded to this application and find some information on how + to implement your own AngularJS application storing, manipulating and serving your photos using Cloudinary! +

+ +

+ All of the images you see here are transformed and served by Cloudinary. + For instance, the logo and the poster frame. + They are both generated in the cloud using Cloudinary functions. + These two pictures weren't even have to be uploaded to Cloudinary, they are retrieved by the service, transformed, cached and distributed through a CDN. +

+ +

Your Photos

+ +
+ Add photo +
+ +
+

No photos were added yet.

+
+

{{photo.context.custom.photo}}

+ + + + +
+ +
+
+ + + + + + + + + +
+
+ +
+ + + + + +
cropfill
width150
height150
radius10
+
+
+
+ +
+ + + + +
cropscale
width150
height150
+
+
+
+ +
+ + + + +
cropfit
width150
height150
+
+
+
+ +
+ + + + + +
cropthumb
gravityface
width150
height150
+
+
+
+ + + +
+ + + + + + + + +
cropfill
effectsepia
gravitynorth
width150
height150
then
angle20
+
+
+
+
+
+ Take a look at our documentation of Image Transformations for a full list of supported transformations. +
+
+ + + diff --git a/samples/photo_album/app/partials/photo-upload.html b/samples/photo_album/app/partials/photo-upload.html new file mode 100644 index 0000000..8980ceb --- /dev/null +++ b/samples/photo_album/app/partials/photo-upload.html @@ -0,0 +1,40 @@ +
+

New Photo

+

Direct upload from the browser

+

You can also drag and drop an image file into the dashed area.

+
+
+ +
+ +
+
+
+ +
+
+ Upload + +
+
{{status}}
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + +
{{key}} {{ value }}
+
+
+ +Back to list diff --git a/samples/photo_album/bower.json b/samples/photo_album/bower.json new file mode 100644 index 0000000..ff8c49a --- /dev/null +++ b/samples/photo_album/bower.json @@ -0,0 +1,15 @@ +{ + "name": "cloudinary-photo-album", + "description": "A starter project for Cloudinary + AngularJS", + "version": "0.0.0", + "homepage": "https://github.com/angular/angular-seed", + "license": "MIT", + "private": true, + "dependencies": { + "angular": "1.2.x", + "angular-route": "~1.2.x", + "angular-resource": "~1.2.x", + "angular-animate": "~1.2.x", + "cloudinary_ng": ">=0.1.0" + } +} diff --git a/samples/photo_album/package.json b/samples/photo_album/package.json new file mode 100644 index 0000000..cd65436 --- /dev/null +++ b/samples/photo_album/package.json @@ -0,0 +1,17 @@ +{ + "version": "0.0.0", + "private": true, + "name": "angular-cloudinary-photo", + "description": "A tutorial application for AngularJS", + "repository": "https://github.com/angular/angular-phonecat", + "license": "MIT", + "devDependencies": { + "http-server": "^0.6.1", + "bower": "^1.3.1" + }, + "scripts": { + "postinstall": "bower install", + "prestart": "npm install", + "start": "http-server -p 8000" + } +}