Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 02e706521408f8516aadff6ce2b3521908f7c8ad Devin Torres committed Apr 8, 2010
Showing with 2,823 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +11 −0 .gitmodules
  3. +10 −0 Buildfile
  4. +32 −0 README.md
  5. +4 −0 apps/fotofoo/Buildfile
  6. +18 −0 apps/fotofoo/controllers/file.js
  7. +20 −0 apps/fotofoo/controllers/files.js
  8. +18 −0 apps/fotofoo/controllers/folder.js
  9. +60 −0 apps/fotofoo/controllers/folders.js
  10. +65 −0 apps/fotofoo/core.js
  11. +128 −0 apps/fotofoo/data_sources/media.js
  12. +74 −0 apps/fotofoo/fixtures/file.js
  13. +67 −0 apps/fotofoo/fixtures/folder.js
  14. +34 −0 apps/fotofoo/main.js
  15. +53 −0 apps/fotofoo/mixins/commit_after_editing.js
  16. +37 −0 apps/fotofoo/models/file.js
  17. +44 −0 apps/fotofoo/models/folder.js
  18. +9 −0 apps/fotofoo/resources/loading.rhtml
  19. +61 −0 apps/fotofoo/resources/main_page.css
  20. +190 −0 apps/fotofoo/resources/main_page.js
  21. +32 −0 apps/fotofoo/resources/strings.js
  22. +52 −0 apps/fotofoo/responders/library.js
  23. +58 −0 apps/fotofoo/responders/preview.js
  24. +83 −0 apps/fotofoo/responders/upload.js
  25. +15 −0 apps/fotofoo/tests/controllers/file.js
  26. +15 −0 apps/fotofoo/tests/controllers/files.js
  27. +15 −0 apps/fotofoo/tests/controllers/folder.js
  28. +15 −0 apps/fotofoo/tests/controllers/folders.js
  29. +15 −0 apps/fotofoo/tests/controllers/preview.js
  30. +15 −0 apps/fotofoo/tests/models/file.js
  31. +15 −0 apps/fotofoo/tests/models/folder.js
  32. +15 −0 apps/fotofoo/tests/views/file_name.js
  33. +15 −0 apps/fotofoo/tests/views/folder.js
  34. +15 −0 apps/fotofoo/tests/views/inline_text_field.js
  35. +15 −0 apps/fotofoo/tests/views/library.js
  36. +15 −0 apps/fotofoo/tests/views/preview.js
  37. +15 −0 apps/fotofoo/tests/views/thumbnail.js
  38. +15 −0 apps/fotofoo/tests/views/upload.js
  39. +35 −0 apps/fotofoo/validators/file_name.js
  40. +24 −0 apps/fotofoo/views/file_name.js
  41. +176 −0 apps/fotofoo/views/folder.js
  42. +28 −0 apps/fotofoo/views/inline_text_field.js
  43. +84 −0 apps/fotofoo/views/library.js
  44. +41 −0 apps/fotofoo/views/preview.js
  45. +145 −0 apps/fotofoo/views/thumbnail.js
  46. +24 −0 apps/fotofoo/views/upload.js
  47. +1 −0 frameworks/scui
  48. +1 −0 frameworks/sproutcore
  49. BIN server/ROOT/January 2010/beach.jpg
  50. BIN server/ROOT/January 2010/blue-tit.jpg
  51. BIN server/ROOT/January 2010/butterfly.jpg
  52. BIN server/ROOT/January 2010/flower.jpg
  53. BIN server/ROOT/January 2010/lake.jpg
  54. BIN server/ROOT/January 2010/trees.jpg
  55. BIN server/ROOT/Trash/anonymous.jpg
  56. BIN server/ROOT/Trash/graffiti.jpg
  57. +1 −0 server/deps/node-router
  58. +263 −0 server/fotofoo.js
  59. +55 −0 server/lib/lrucache.js
  60. +40 −0 server/lib/magick.js
  61. +437 −0 server/lib/multipart.js
  62. +26 −0 server/lib/natsort.js
  63. +36 −0 server/tests/test-lrucache.js
  64. +34 −0 server/tests/test-magick.js
  65. BIN server/tests/test.jpg
  66. BIN server/tests/test_copy.jpg
@@ -0,0 +1,2 @@
+.DS_Store
+tmp/
@@ -0,0 +1,11 @@
+[submodule "sproutcore"]
+ path = frameworks/sproutcore
+ url = git://github.com/sproutit/sproutcore.git
+
+[submodule "scui"]
+ path = frameworks/scui
+ url = git://github.com/etgryphon/sproutcore-ui.git
+
+[submodule "node-router"]
+ path = server/deps/node-router
+ url = git://github.com/creationix/node-router.git
@@ -0,0 +1,10 @@
+# ===========================================================================
+# Project: Fotofoo
+# Copyright: ©2010 Devin Torres
+# ===========================================================================
+
+# Add initial buildfile information here
+config :all, :required => :sproutcore
+config :fotofoo, :theme => :'sproutcore/sc_ace'
+
+proxy '/_media/', :to => 'localhost:8080', :url => '/'
@@ -0,0 +1,32 @@
+Fotofoo - SproutCore foto foolery
+=================================
+
+## Installing
+ $ git clone git://github.com/devinus/fotofoo.git
+ $ cd fotofoo
+ $ git submodule init
+ $ git submodule update
+
+## Running
+ $ sudo port install GraphicsMagick # or apt-get
+ $ git clone git://github.com/ry/node.git
+ $ cd node
+ $ ./configure
+ $ make
+ $ sudo make install
+ $ cd /path/to/fotofoo
+ # cd server
+ $ node fotofoo.js
+
+Then, in a new console:
+ $ cd /path/to/fotofoo
+ $ sc-server
+
+## Viewing
+Now navigate your web browser to `http://127.0.0.1:4020/fotofoo`
+
+## TODO
+- Dragging and dropping of folders (commented out for now)
+- Deleting folders/files (already have this in an older internal revision)
+- Warn when file by the same name already exists in destination folder
+- More image manipulation features, such as cropping
@@ -0,0 +1,4 @@
+config :fotofoo, :required => [
+ :sproutcore,
+ :'scui/foundation'
+]
@@ -0,0 +1,18 @@
+// ==========================================================================
+// Project: Fotofoo.fileController
+// Copyright: ©2010 Devin Torres
+// ==========================================================================
+/*globals Fotofoo */
+
+/** @class
+
+ (Document Your Controller Here)
+
+ @extends SC.Object
+*/
+Fotofoo.fileController = SC.ObjectController.create(
+/** @scope Fotofoo.fileController.prototype */ {
+
+ contentBinding: SC.Binding.from('Fotofoo.filesController.selection').single()
+
+}) ;
@@ -0,0 +1,20 @@
+// ==========================================================================
+// Project: Fotofoo.filesController
+// Copyright: ©2010 Devin Torres
+// ==========================================================================
+/*globals Fotofoo */
+
+Fotofoo.MAX_THUMBNAIL_SIZE = 250;
+
+/** @class
+
+ (Document Your Controller Here)
+
+ @extends SC.Object
+*/
+Fotofoo.filesController = SC.ArrayController.create(
+/** @scope Fotofoo.filesController.prototype */ {
+
+ contentBinding: 'Fotofoo.folderController.files'
+
+}) ;
@@ -0,0 +1,18 @@
+// ==========================================================================
+// Project: Fotofoo.folderController
+// Copyright: ©2010 Devin Torres
+// ==========================================================================
+/*globals Fotofoo */
+
+/** @class
+
+ (Document Your Controller Here)
+
+ @extends SC.Object
+*/
+Fotofoo.folderController = SC.ObjectController.create(
+/** @scope Fotofoo.folderController.prototype */ {
+
+ contentBinding: SC.Binding.from('Fotofoo.foldersController.selection').single()
+
+}) ;
@@ -0,0 +1,60 @@
+// ==========================================================================
+// Project: Fotofoo.foldersController
+// Copyright: ©2010 Devin Torres
+// ==========================================================================
+/*globals Fotofoo */
+
+/** @class
+
+ (Document Your Controller Here)
+
+ @extends SC.Object
+*/
+Fotofoo.foldersController = SC.TreeController.create(
+/** @scope Fotofoo.foldersController.prototype */ {
+
+ treeItemIsGrouped: YES,
+
+ newFolder: function() {
+ var sel = this.getPath('selection.firstObject'),
+ useSelectionAsParent = sel ? !sel.get('isTrash') : NO,
+ root = this.getPath('content.treeItemChildren.firstObject'),
+ parentFolder = useSelectionAsParent ? sel.get('guid') || '/' : '/',
+ newFolder = Fotofoo.store.createRecord(Fotofoo.Folder, {
+ type: 'Folder',
+ guid: (parentFolder === '/' ? '' : parentFolder + '/') + SC.generateGuid(),
+ parentFolder: parentFolder
+ });
+
+ var $this = this;
+ newFolder.addObserver('status', newFolder, function() {
+ var status = this.get('status');
+ if (status && status & SC.Record.READY_CLEAN) {
+ this.removeObserver('status', this, arguments.callee);
+
+ try {
+ if (useSelectionAsParent) sel.get('childFolders').pushObject(this);
+ else Fotofoo.getPath('rootFolder.childFolders').pushObject(this);
+ } catch (e) {}
+
+ if (useSelectionAsParent) {
+ var folderView = Fotofoo.foldersView.itemViewForContentObject(sel),
+ idx = folderView.get('contentIndex'),
+ set = (!SC.none(idx)) ? SC.IndexSet.create(idx) : null,
+ del = folderView.get('displayDelegate');
+
+ if (set && del && del.expand) del.expand(set);
+ else folderView.set('disclosureState', SC.BRANCH_OPEN);
+ folderView.displayDidChange();
+ }
+
+ $this.selectObject(this);
+ Fotofoo.foldersView.itemViewForContentObject(this).beginEditing();
+ }
+ });
+
+ newFolder.commitRecord();
+ return YES;
+ }
+
+}) ;
@@ -0,0 +1,65 @@
+// ==========================================================================
+// Project: Fotofoo
+// Copyright: ©2010 Devin Torres
+// ==========================================================================
+/*globals Fotofoo */
+
+/** @namespace
+
+ My cool new app. Describe your application.
+
+ @extends SC.Object
+*/
+Fotofoo = SC.Application.create(
+ /** @scope Fotofoo.prototype */ {
+
+ NAMESPACE: 'Fotofoo',
+ VERSION: '0.1.0',
+
+ // This is your application store. You will use this store to access all
+ // of your model data. You can also set a data source on this store to
+ // connect to a backend server. The default setup below connects the store
+ // to any fixtures you define.
+ // store: SC.Store.create().from(SC.Record.fixtures),
+ store: SC.Store.create().from('Fotofoo.MediaDataSource'),
+
+ // TODO: Add global constants or singleton objects needed by your app here.
+ ROOT_MEDIA_URL: '/_media/',
+ nowShowing: 'master',
+ rootFolder: null,
+ state: null,
+
+ _SLASH_RE: /\//g,
+ _ENCODED_PIPE_RE: /%7C/g,
+ _MULTIPLE_SLASHES_RE: /\/+/g,
+ _SURROUNDING_WHITESPACE_RE: /^\s+|\s+$/g,
+
+ encodeGuid: function(guid) {
+ var encoded = encodeURIComponent(guid.replace(this._SLASH_RE, '|'));
+ return encoded.replace(this._ENCODED_PIPE_RE, '/');
+ },
+
+ urlJoin: function() {
+ var joined = Array.prototype.join.call(arguments, '/');
+ return joined.replace(this._MULTIPLE_SLASHES_RE, '/');
+ },
+
+ trim: function (str) {
+ return String.prototype.trim ? String.prototype.trim.apply(str)
+ : str.replace(this._SURROUNDING_WHITESPACE_RE, '');
+ },
+
+ _lastStateObserved: null,
+
+ _stateDidChange: function() {
+ var state = this.get('state');
+ if (SC.typeOf(state) === SC.T_STRING) state = this.get(state);
+
+ if (state !== this._lastStateObserved) {
+ this._lastStateObserved = state;
+ state.set('responderContext', this);
+ this.makeFirstResponder(state);
+ }
+ }.observes('state')
+
+}) ;
@@ -0,0 +1,128 @@
+// ==========================================================================
+// Project: Fotofoo.MediaDataSource
+// Copyright: ©2010 Devin Torres
+// ==========================================================================
+/*globals Fotofoo */
+
+/** @class
+
+ (Document Your Data Source Here)
+
+ @extends SC.DataSource
+*/
+Fotofoo.MediaDataSource = SC.DataSource.extend(
+/** @scope Fotofoo.MediaDataSource.prototype */ {
+
+ // ..........................................................
+ // QUERY SUPPORT
+ //
+
+ fetch: function(store, query) {
+ if (query.get('isLocal')) return NO;
+
+ SC.Request.getUrl(Fotofoo.ROOT_MEDIA_URL)
+ .set('isJSON', YES)
+ .notify(this, this._didFetch, { query: query, store: store })
+ .send();
+
+ return YES;
+ },
+
+ _didFetch: function(request, params) {
+ var store = params.store,
+ query = params.query,
+ response = request.get('response');
+
+ if (SC.$ok(response)) {
+ var storeKey = store.loadRecord(Fotofoo.Folder, response);
+ store.loadQueryResults(query, [storeKey]);
+ store.dataSourceDidFetchQuery(query);
+ } else store.dataSourceDidErrorQuery(query, response);
+ },
+
+ // ..........................................................
+ // RECORD SUPPORT
+ //
+
+ retrieveRecord: function(store, storeKey) {
+ var id = store.idFor(storeKey),
+ params = { store: store, storeKey: storeKey },
+ safeId = Fotofoo.encodeGuid(id),
+ url = Fotofoo.urlJoin(Fotofoo.ROOT_MEDIA_URL, safeId);
+
+ SC.Request.getUrl(url)
+ .set('isJSON', YES)
+ .notify(this, this._didRetrieveRecord, params)
+ .send();
+
+ return YES;
+ },
+
+ _didRetrieveRecord: function(request, params) {
+ var store = params.store,
+ storeKey = params.storeKey,
+ response = request.get('response');
+
+ if (SC.$ok(response)) {
+ store.dataSourceDidComplete(storeKey, response);
+ } else store.dataSourceDidError(storeKey, response);
+ },
+
+ createRecord: function(store, storeKey) {
+ var id = store.idFor(storeKey),
+ recordType = store.recordTypeFor(storeKey),
+ data = store.readDataHash(storeKey),
+ params = { store: store, storeKey: storeKey },
+ safeId = Fotofoo.encodeGuid(id),
+ url = Fotofoo.urlJoin(Fotofoo.ROOT_MEDIA_URL, safeId);
+
+ if (recordType === Fotofoo.File) return NO;
+
+ SC.Request.postUrl(url)
+ .set('isJSON', YES)
+ .notify(this, this._didCreateRecord, params)
+ .send(data);
+
+ return YES;
+ },
+
+ _didCreateRecord: function(request, params) {
+ var store = params.store,
+ storeKey = params.storeKey,
+ response = request.get('response');
+
+ if (SC.$ok(response)) {
+ store.dataSourceDidComplete(storeKey, response, response.guid);
+ } else store.dataSourceDidError(storeKey, response);
+ },
+
+ updateRecord: function(store, storeKey) {
+ var id = store.idFor(storeKey),
+ data = store.readDataHash(storeKey),
+ params = { store: store, storeKey: storeKey },
+ safeId = Fotofoo.encodeGuid(id),
+ url = Fotofoo.urlJoin(Fotofoo.ROOT_MEDIA_URL, safeId);
+
+ SC.Request.putUrl(url)
+ .set('isJSON', YES)
+ .notify(this, this._didUpdateRecord, params)
+ .send(data);
+
+ return YES;
+ },
+
+ _didUpdateRecord: function(request, params) {
+ var store = params.store,
+ storeKey = params.storeKey,
+ response = request.get('response');
+
+ if (SC.$ok(response)) {
+ store.dataSourceDidComplete(storeKey, response, response.guid);
+ } else store.dataSourceDidError(storeKey, response);
+ },
+
+ destroyRecord: function(store, storeKey) {
+ return NO;
+ }
+
+}) ;
Oops, something went wrong.

0 comments on commit 02e7065

Please sign in to comment.