admin_it 1.2.6 → 1.2.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 59e741cf6aa0a6d0b798342724be6d44273202fa
4
- data.tar.gz: c2e371c65ed2f758a74f12c63ea7cb0af0835200
3
+ metadata.gz: 0c090fcc7e63225ac6601c85ac9deb4ef9a1f277
4
+ data.tar.gz: a9e2fe30ceb1589d9cdd7e2f791ce3f076549e6e
5
5
  SHA512:
6
- metadata.gz: c85697942c88f327fd1079832ccdb1314c87ff8ecdff949e86c814c042b544f9075bfb5b730b484a288fad7bee9c1e7072a79ea3cfedd4c46d9b7c0cf6f56760
7
- data.tar.gz: 61400cb10f7c364b000765ce7e3e393f641d01040ae068284adb37d076fade4a42cecd625a58457b127c8981c79b689e6104ef294b1988e9d5688e282c7ce907
6
+ metadata.gz: 7c2a43fc1579cf58eebdc0acbeb7e29bb6d2cc34475cd4e2bcf81a71f63177d7611a0865f40cbae032d3e656ab9c79b5dcd53d3d4ecb1945bb0e426c9b2b85c0
7
+ data.tar.gz: 747cbf4c44754ac86562595b339b0a02ad57f97b15e90394c0832b6b696114afc8662f873e544d44023f54b0955342c2b085e5c8a30f5aebfa8689229e573c71
data/.gitignore CHANGED
@@ -17,3 +17,4 @@ spec/reports
17
17
  test/tmp
18
18
  test/version_tmp
19
19
  tmp
20
+ client/components
data/README.md CHANGED
@@ -36,6 +36,9 @@ bundle install
36
36
 
37
37
  # Changes
38
38
 
39
+ `1.2.7`
40
+ * image uploads fixed
41
+
39
42
  `1.2.6`
40
43
  * added: geo location picker
41
44
 
@@ -18,7 +18,7 @@ module AdminIt
18
18
  def s3_upload_policy_document
19
19
  Base64.encode64(
20
20
  {
21
- expiration: 15.minutes.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z'),
21
+ expiration: 12.hours.from_now.utc.strftime('%Y-%m-%dT%H:%M:%S.000Z'),
22
22
  conditions: [
23
23
  { bucket: AdminIt.config.s3[:bucket] },
24
24
  { acl: 'public-read' },
@@ -31,9 +31,10 @@ module AdminIt
31
31
 
32
32
  # sign our request by Base64 encoding the policy document.
33
33
  def s3_upload_signature
34
+ puts AdminIt.config.s3
34
35
  Base64.encode64(
35
36
  OpenSSL::HMAC.digest(
36
- OpenSSL::Digest::Digest.new('sha1'),
37
+ OpenSSL::Digest.new('sha1'),
37
38
  AdminIt.config.s3[:secret_access_key],
38
39
  s3_upload_policy_document
39
40
  )
data/client/.bowerrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "directory": "components"
3
+ }
data/client/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gem 'thor'
3
+ gem 'slim'
data/client/bower.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "admin-it-client",
3
+ "version": "1.0.0",
4
+ "homepage": "https://github.com/cybernetlab/admin_it",
5
+ "authors": [
6
+ "Alexey Ovchinnikov <alexiss@cybernetlab.ru>"
7
+ ],
8
+ "main": "src/js/main.js",
9
+ "private": true,
10
+ "ignore": [
11
+ "components",
12
+ "dev",
13
+ "test",
14
+ "tests",
15
+ "**/*.txt"
16
+ ],
17
+ "dependencies": {
18
+ "requirejs": "latest",
19
+ "backbone": "latest",
20
+ "underscore": "latest"
21
+ },
22
+ "devDependencies": {
23
+ "mustache": "latest",
24
+ "bootstrap": "latest",
25
+ "fontawesome": "latest"
26
+ }
27
+ }
data/client/index.html ADDED
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html><html><head><title>AdminIt Client Test App</title><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" /><script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script><script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script><link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet" /><script data-main="src/js/main" src="components/requirejs/require.js"></script><script data-name="metadata" data-type="data" type="application/json">{
2
+ "resources": [
3
+ {
4
+ "id": "users",
5
+ "name": "Users",
6
+ "icon": "users"
7
+ },
8
+
9
+ {
10
+ "id": "roles",
11
+ "name": "Roles",
12
+ "icon": "lock"
13
+ }
14
+ ]
15
+ }
16
+ </script><script data-name="main_menu" data-type="template" type="application/mustache"><ul class="nav nav-pills nav-stacked">{{#items}}<li class="admin-it-main-menu-item" data-id="{{id}}"><a href="#">{{#icon}}{{>icon}} {{/icon}}{{name}}</a></li>{{/items}}</ul></script><script data-name="main_view" data-type="template" type="application/mustache"><div class="container-fluid"><div class="row"><div class="admin-it-main-menu col-md-2"></div><div class="admin-it-work-area col-md-10"></div></div></div></script></head><body></body></html>
@@ -0,0 +1,22 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title AdminIt Client Test App
5
+
6
+ / Bootstrap
7
+ link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet"
8
+ script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"
9
+ script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"
10
+
11
+ / Font-Awesome
12
+ link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet"
13
+
14
+ / AdminIt
15
+ script data-main="src/js/main" src="components/requirejs/require.js"
16
+
17
+ / data
18
+ script type="application/json" data-type="data" data-name="metadata"
19
+ == include File.join(pwd, 'metadata.json')
20
+ / bootstrap templates
21
+ == render 'bootstrap'
22
+ body
@@ -0,0 +1,332 @@
1
+ // Backbone.nestedTypes 0.2 (https://github.com/Volicon/backbone.nestedTypes)
2
+ // (c) 2014 Vlad Balin, may be freely distributed under the MIT license
3
+
4
+ ( function( root, factory ){
5
+ if( typeof define === 'function' && define.amd ) {
6
+ define( [ 'exports', 'backbone', 'underscore' ], factory );
7
+ }
8
+ else if( typeof exports !== 'undefined' ){
9
+ factory( exports, require( 'backbone' ), require( 'underscore' ) );
10
+ }
11
+ else{
12
+ root.NestedTypes = {};
13
+ factory( root.NestedTypes, root.Backbone, root._ );
14
+ }
15
+ }( this, function( exports, Backbone, _ ){
16
+ 'use strict';
17
+ var extend = Backbone.Model.extend;
18
+
19
+ function attachNativeProperties( This, properties, Base ){
20
+ _.each( properties, function( propDesc, name ){
21
+ var prop = typeof propDesc === 'function' ? {
22
+ get: propDesc,
23
+ enumerable: false
24
+ } : propDesc;
25
+
26
+ if( name in Base.prototype ){
27
+ throw new TypeError( 'extend: property ' + name + ' conflicts with base class members!' );
28
+ }
29
+
30
+ Object.defineProperty( This.prototype, name, prop );
31
+ });
32
+ }
33
+
34
+ function extendWithProperties( Base ){
35
+ return function( protoProps, staticProps ){
36
+ var This = extend.call( this, protoProps, staticProps );
37
+ attachNativeProperties( This, protoProps.properties, Base );
38
+ return This;
39
+ };
40
+ }
41
+
42
+ exports.Class = function(){
43
+ function Class(){
44
+ this.initialize.apply( this, arguments );
45
+ };
46
+
47
+ _.extend( Class.prototype, Backbone.Events, { initialize: function (){} } );
48
+ Class.extend = extendWithProperties( Class );
49
+
50
+ return Class;
51
+ }();
52
+
53
+ exports.Collection = function(){
54
+ var Collection,
55
+ CollectionProto = Backbone.Collection.prototype;
56
+
57
+ function wrapCall( func ){
58
+ return function(){
59
+ if( !this.__changing++ ){
60
+ this.trigger( 'before:change' );
61
+ }
62
+
63
+ func.apply( this, arguments );
64
+
65
+ if( !--this.__changing ){
66
+ this.trigger( 'after:change' );
67
+ }
68
+ };
69
+ }
70
+
71
+ Collection = Backbone.Collection.extend({
72
+ triggerWhenChanged: 'change add remove reset sort',
73
+
74
+ deepClone: function(){
75
+ var copy = CollectionProto.clone.call( this );
76
+
77
+ copy.reset( this.map( function( model ){
78
+ return model.deepClone();
79
+ } ) );
80
+
81
+ return copy;
82
+ },
83
+
84
+ __changing: 0,
85
+ set: wrapCall( CollectionProto.set ),
86
+ remove: wrapCall( CollectionProto.remove ),
87
+ add: wrapCall( CollectionProto.add ),
88
+ reset: wrapCall( CollectionProto.reset ),
89
+ sort: wrapCall( CollectionProto.sort )
90
+ });
91
+
92
+ Collection.extend = extendWithProperties( Collection );
93
+
94
+ return Collection;
95
+ }();
96
+
97
+ exports.Model = function(){
98
+ var extend = Backbone.Model.extend,
99
+ ModelProto = Backbone.Model.prototype;
100
+
101
+ function delegateEvents( name, oldValue, newValue ){
102
+ var replace = false;
103
+
104
+ if( _.isEqual( oldValue, newValue ) ){
105
+ return;
106
+ }
107
+
108
+ if( oldValue && oldValue.triggerWhenChanged ){
109
+ replace = true;
110
+ this.stopListening( oldValue );
111
+ }
112
+
113
+ if( newValue && newValue.triggerWhenChanged ){
114
+ replace = true;
115
+
116
+ this.listenTo( newValue, 'before:change', onEnter );
117
+ this.listenTo( newValue, 'after:change', onExit );
118
+
119
+ this.listenTo( newValue, newValue.triggerWhenChanged, function(){
120
+ var value = this.get( name );
121
+
122
+ if( this.__duringSet ){
123
+ this.__nestedChanges[ name ] = value;
124
+ }
125
+ else{
126
+ this.attributes[ name ] = null;
127
+ ModelProto.set.call( this, name, value );
128
+ }
129
+ } );
130
+
131
+ _.each( this.listening[ name ], function( handler, events ){
132
+ var callback = typeof handler === 'string' ? this[ handler ] : handler;
133
+ this.listenTo( newValue, events, callback );
134
+ }, this );
135
+ }
136
+
137
+ if( replace ){
138
+ this.trigger( 'replace:' + name, this, newValue, oldValue );
139
+ }
140
+ }
141
+
142
+ function typeCast( Ctor, name, value ){
143
+ var oldValue = this.attributes[ name ],
144
+ valueHasOtherType = ( value != null ) && !( value instanceof Ctor ),
145
+ newValue;
146
+
147
+ if( oldValue && oldValue.set && valueHasOtherType ){
148
+ oldValue.set( value );
149
+ newValue = oldValue;
150
+ }
151
+ else{
152
+ newValue = valueHasOtherType ? new Ctor( value ) : value;
153
+ delegateEvents.call( this, name, oldValue, newValue );
154
+ }
155
+
156
+ return newValue;
157
+ }
158
+
159
+ function onExit( a_attrs, options ){
160
+ var attrs = a_attrs || {};
161
+
162
+ if( !--this.__duringSet ){
163
+ _.each( this.__nestedChanges, function( value, name ){
164
+ if( !( name in attrs ) ){
165
+ attrs[ name ] = value;
166
+ }
167
+
168
+ if( attrs[ name ] === this.attributes[ name ] ){
169
+ this.attributes[ name ] = null;
170
+ }
171
+ }, this );
172
+
173
+ this.__nestedChanges = {};
174
+
175
+ ModelProto.set.call( this, attrs, options );
176
+ }
177
+ else if( a_attrs ){
178
+ ModelProto.set.call( this, a_attrs, options );
179
+ }
180
+ }
181
+
182
+ function onEnter(){
183
+ if( !this.__duringSet++ ){
184
+ this.__nestedChanges = {};
185
+ }
186
+ }
187
+
188
+ var Model = Backbone.Model.extend( {
189
+ triggerWhenChanged: 'change',
190
+ listening: {},
191
+ __duringSet: 0,
192
+ __defaults: {},
193
+ __types: {},
194
+
195
+ set: function( first, second, third ){
196
+ // handle different call options...
197
+ var attrs, options, types = this.__types;
198
+
199
+ if( typeof first === 'string' ){
200
+ ( attrs = {} )[ first ] = second;
201
+ options = third;
202
+ }
203
+ else{
204
+ attrs = first;
205
+ options = second;
206
+ }
207
+
208
+ onEnter.call( this );
209
+
210
+ // cast values to default types...
211
+ _.each( attrs, function( value, name ){
212
+ var Ctor = types[ name ];
213
+
214
+ if( Ctor ){
215
+ attrs[ name ] = typeCast.call( this, Ctor, name, value );
216
+ }
217
+ }, this );
218
+
219
+ // apply changes
220
+ onExit.call( this, attrs, options );
221
+
222
+ return this;
223
+ },
224
+
225
+ // Create deep copy for all nested objects...
226
+ deepClone: function(){
227
+ var copy = ModelProto.clone.call( this );
228
+
229
+ _.each( copy.attributes, function( value, key ){
230
+ if( value && value.deepClone ){
231
+ copy.set( key, value.deepClone() );
232
+ }
233
+ } );
234
+
235
+ return copy;
236
+ },
237
+
238
+ // Support for nested models and objects.
239
+ // Apply toJSON recursively to produce correct JSON.
240
+ toJSON: function(){
241
+ var res = ModelProto.toJSON.apply( this, arguments );
242
+
243
+ _.each( res, function( value, key ){
244
+ if( value && value.toJSON ){
245
+ res[ key ] = value.toJSON();
246
+ }
247
+ } );
248
+
249
+ return res;
250
+ },
251
+
252
+ _: _ // add underscore to be accessible in templates
253
+ } );
254
+
255
+ function parseDefaults( spec, Base ){
256
+ var defaults = _.defaults( spec.defaults || {}, Base.prototype.__defaults ),
257
+ fnames = _.functions( defaults ),
258
+ values = _.omit( defaults, fnames ),
259
+ types = _.pick( defaults, fnames );
260
+
261
+ return _.extend( {}, spec, {
262
+ defaults : createDefaults( values, types ),
263
+ __defaults : defaults,
264
+ __types : types
265
+ });
266
+ }
267
+
268
+ function createDefaults( values, ctors ){
269
+ return function(){
270
+ var defaults = _.clone( values );
271
+
272
+ _.each( ctors, function( Ctor, name ){
273
+ defaults[ name ] = new Ctor();
274
+ } );
275
+
276
+ return defaults;
277
+ };
278
+ }
279
+
280
+ function createAttrPropDesc( name ){
281
+ return {
282
+ get: function(){
283
+ return this.attributes[ name ];
284
+ },
285
+
286
+ set: function( val ){
287
+ this.set( name, val );
288
+ return val;
289
+ },
290
+
291
+ enumerable: false
292
+ };
293
+ }
294
+
295
+ function attachNativeProperties( This, spec ){
296
+ var properties = {};
297
+
298
+ if( spec.properties !== false ){
299
+ _.each( spec.defaults, function( notUsed, name ){
300
+ properties[ name ] = createAttrPropDesc( name );
301
+ } );
302
+
303
+ _.each( spec.properties, function( propDesc, name ){
304
+ properties[ name ] = typeof propDesc === 'function' ? {
305
+ get: propDesc,
306
+ enumerable: false
307
+ } : propDesc;
308
+ } );
309
+
310
+ _.each( properties, function( prop, name ){
311
+ if( name in ModelProto ||
312
+ name === 'cid' || name === 'id' || name === 'attributes' ){
313
+ throw new TypeError( 'extend: attribute ' + name + ' conflicts with Backbone.Model base class members!' );
314
+ }
315
+
316
+ Object.defineProperty( This.prototype, name, prop );
317
+ } );
318
+ }
319
+ }
320
+
321
+ Model.extend = function( protoProps, staticProps ){
322
+ var spec = parseDefaults( protoProps, this ),
323
+ This = extend.call( this, spec, staticProps );
324
+
325
+ attachNativeProperties( This, protoProps );
326
+
327
+ return This;
328
+ };
329
+
330
+ return Model;
331
+ }();
332
+ }));
@@ -0,0 +1,15 @@
1
+ {
2
+ "resources": [
3
+ {
4
+ "id": "users",
5
+ "name": "Users",
6
+ "icon": "users"
7
+ },
8
+
9
+ {
10
+ "id": "roles",
11
+ "name": "Roles",
12
+ "icon": "lock"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,188 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore', 'backbone',
4
+ 'admin_it/template', 'admin_it/icons',
5
+ 'admin_it/models/metadata', 'admin_it/views/main'],
6
+
7
+ // > Usefull services for debugging: http://ip.jsontest.com
8
+
9
+ function($, _, Backbone, Template, Icons, Metadata, MainView) {
10
+ 'use strict';
11
+
12
+ // loads and verifies user config
13
+ var checkConfig = function(options) {
14
+ var config = _.extend({
15
+ api_url: '/api',
16
+ template_url: '',
17
+ template: _.template,
18
+ metadata: 'metadata',
19
+ icons: 'glyphicon'
20
+ }, options);
21
+
22
+ if (!_.isString(config.api_url)) throw new Error('Wrong api_url option');
23
+ config.api_url = config.api_url.replace(/\/+$/, '');
24
+
25
+ if (!_.isString(config.template_url)) throw new Error('Wrong template_url option');
26
+ config.template_url = config.template_url.replace(/\/+$/, '');
27
+
28
+ if (_.isEmpty(config.container)) config.container = $('body').first();
29
+ if (_.isString(config.container)) config.container = $(config.container).first();
30
+ return config;
31
+ }
32
+
33
+ // loads resource
34
+ var loadResource = function(app, source, target) {
35
+ // for jQuery source return inner html
36
+ if (source instanceof $) return source.html();
37
+ if (_.isString(source)) {
38
+ if (/[{}<>]/.test(source)) {
39
+ // for strings, that contains JSON or HTML symbols return string itself
40
+ return source;
41
+ } else {
42
+ // for other strings assumes that string is jQuery selector or URI
43
+ if (source.indexOf('http') != 0 && source[0] != '/') {
44
+ var selector = '[data-name="' + source + '"][data-type="';
45
+ selector += (target == app.config.template) ? 'template"]' : 'data"]';
46
+ var jquery = $(selector);
47
+ if (jquery.length > 0) return jquery.first().html();
48
+ // source is relative URI - make URI absolute
49
+ if (target == app.config.template) {
50
+ source = app.config.template_url + '/' + source;
51
+ } else {
52
+ source = app.config.api_url + '/' + source;
53
+ }
54
+ }
55
+ if (target instanceof Backbone.Model) {
56
+ // if target is model set its urlRoot to source
57
+ if (_.isEmpty(target.urlRoot) && _.isEmpty(target.collection)) {
58
+ target.urlRoot = source;
59
+ }
60
+ return target.fetch();
61
+ } else if (target instanceof Backbone.Collection) {
62
+ // if target is collection set its url to source
63
+ if (_.isEmpty(target.url)) target.url = source;
64
+ return target.fetch();
65
+ }
66
+ return $.ajax({ url: source });
67
+ }
68
+ }
69
+ };
70
+
71
+ // creates resource after it loaded
72
+ var createResource = function(app, str, target) {
73
+ if (target instanceof Backbone.Model ||
74
+ target instanceof Backbone.Collection) {
75
+ if (_.isObject(str)) return target;
76
+ if (!_.isString(str)) return null;
77
+ str = str.replace(/[\t\n\r]/g, '');
78
+ str = $.parseJSON(str);
79
+ if (!_.isObject(str)) return null;
80
+ (target instanceof Backbone.Model) ? target.set(str) : target.reset(str);
81
+ return target;
82
+ } else if (target == app.config.template) {
83
+ return new target(str);
84
+ }
85
+ };
86
+
87
+ // loads resources from html
88
+ var loadLocals = function(deferred) {
89
+ var app = this;
90
+ $('[data-type][data-name]').each(function() {
91
+ var $this = $(this);
92
+ var data = $this.data();
93
+ if (data.type == 'template') {
94
+ app.templates[data.name] = new app.config.template($this.html());
95
+ } else if (data.type == 'data' || data.type == 'collection' || data.type == 'model') {
96
+ var Model = app.metadata.get(data.name);
97
+ if (!Model) return;
98
+ app.data[data.name] = new Model($.parseJSON($this.html));
99
+ }
100
+ });
101
+ _.each(app.config.template.defaults, function(template, name) {
102
+ if (!_.has(app.templates, name)) app.templates[name] = template;
103
+ });
104
+ deferred.resolve();
105
+ };
106
+
107
+ // creates main view
108
+ var loadMainView = function(template) {
109
+ this.mainView = new MainView({
110
+ app: this,
111
+ el: this.config.container,
112
+ template: template
113
+ });
114
+ };
115
+
116
+ var App = {
117
+ /**
118
+ * @brief starts admin application
119
+ * @details this is the main function for start admin application
120
+ *
121
+ * @param options application options
122
+ * @return jQuery deferred object that resolves when application is
123
+ * completele loaded.
124
+ */
125
+ initialize: function(options) {
126
+ this.config = checkConfig(options);
127
+ this.icons = new Icons(this.config.icons);
128
+ this.config.template = Template(this.config.template);
129
+ this.config.template.registerHelper('iconClass', _.bind(this.icons.htmlClass, this.icons));
130
+ this.metadata = new Metadata();
131
+ this.data = {};
132
+ this.templates = {};
133
+
134
+ var app = this;
135
+ var loadingLocals = $.Deferred();
136
+
137
+ // load main view
138
+ var loadingMain = this.load('main_view', this.config.template)
139
+ .done(_.bind(loadMainView, this));
140
+ // load metadata
141
+ this.load(this.config.metadata, this.metadata)
142
+ .done(_.bind(loadLocals, this, loadingLocals));
143
+
144
+ this.loading = $.when(loadingLocals, loadingMain)
145
+ .done(function() { app.trigger('loaded') });
146
+ },
147
+
148
+ /**
149
+ * @brief triggers application error
150
+ *
151
+ * @param msg error message
152
+ * @return null
153
+ */
154
+ error: function(msg) {
155
+ console.log('Error occured: ' + msg);
156
+ app.trigger('error', msg);
157
+ },
158
+
159
+ /**
160
+ * @brief loads application resource
161
+ * @details resource is a template or a data
162
+ *
163
+ * @param source source to load resource from. Can be a jQuery object or
164
+ * a string that can be a jQuery selector or an url
165
+ * @param target resource type. Can be a template class or Backbone
166
+ * model or collection
167
+ *
168
+ * @return jQuery deferred
169
+ */
170
+ load: function(source, target) {
171
+ var deferred = $.Deferred();
172
+ var app = this;
173
+ $.when(loadResource(this, source, target))
174
+ .done(function(str) {
175
+ deferred.resolve(createResource(app, str, target));
176
+ })
177
+ .fail(function() {
178
+ deferred.reject('while loading component');
179
+ app.error('while loading component');
180
+ });
181
+ return deferred;
182
+ }
183
+ }
184
+
185
+ _.extend(App, Backbone.Events);
186
+
187
+ return App;
188
+ });
@@ -0,0 +1,14 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore', 'nestedtypes',
4
+ 'admin_it/models/resource'],
5
+
6
+ function($, _, Backbone, Resource) {
7
+ 'use strict';
8
+
9
+ var Resources = Backbone.Collection.extend({
10
+ model: Resource
11
+ });
12
+
13
+ return Resources;
14
+ });
@@ -0,0 +1,28 @@
1
+ define(
2
+
3
+ function() {
4
+ 'use strict';
5
+
6
+ var iconSets = {
7
+ fa: {},
8
+ glyphicon: { users: 'user' }
9
+ }
10
+
11
+ function Icons(iconSet) {
12
+ var set = iconSets[iconSet];
13
+ this.icons = (set) ? set : {};
14
+ this.set = iconSet;
15
+ };
16
+
17
+ Icons.prototype.get = function(name) {
18
+ var icon = this.icons[name];
19
+ return (icon) ? icon : name;
20
+ };
21
+
22
+ Icons.prototype.htmlClass = function(name) {
23
+ console.log(this, name);
24
+ return this.set + ' ' + this.set + '-' + this.get(name);
25
+ }
26
+
27
+ return Icons
28
+ });
@@ -0,0 +1,21 @@
1
+ requirejs.config({
2
+ baseUrl: 'src/js',
3
+ paths: {
4
+ admin_it: './',
5
+ jquery: '../../components/jquery/dist/jquery',
6
+ underscore: '../../components/underscore/underscore',
7
+ backbone: '../../components/backbone/backbone',
8
+ mustache: '../../components/mustache/mustache',
9
+ nestedtypes: '../../lib/nestedtypes'
10
+ }
11
+ });
12
+
13
+ require(
14
+
15
+ ['jquery', 'admin_it/app', 'mustache'],
16
+
17
+ function($, App, Mustache) {
18
+ 'use strict';
19
+
20
+ App.initialize({ template: Mustache, icons: 'fa' });
21
+ });
@@ -0,0 +1,12 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore', 'nestedtypes'],
4
+
5
+ function($, _, Backbone) {
6
+ 'use strict';
7
+
8
+ var Base = Backbone.Model.extend({
9
+ });
10
+
11
+ return Base
12
+ });
@@ -0,0 +1,16 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore', 'nestedtypes',
4
+ 'admin_it/collections/resources'],
5
+
6
+ function($, _, Backbone, Resources) {
7
+ 'use strict';
8
+
9
+ var Metadata = Backbone.Model.extend({
10
+ defaults: {
11
+ resources: Resources
12
+ }
13
+ });
14
+
15
+ return Metadata
16
+ });
@@ -0,0 +1,12 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore', 'nestedtypes'],
4
+
5
+ function($, _, Backbone) {
6
+ 'use strict';
7
+
8
+ var Resource = Backbone.Model.extend({
9
+ });
10
+
11
+ return Resource
12
+ });
@@ -0,0 +1,102 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore'],
4
+
5
+ function($, _) {
6
+ 'use strict';
7
+
8
+ function Template() {
9
+ this.initialize.apply(this, arguments);
10
+ }
11
+
12
+ Template.globals = {};
13
+ Template.helpers = {};
14
+
15
+ return function(engine) {
16
+ if (_.isFunction(engine)) {
17
+ // underscore or other function-like template
18
+ Template.registerHelper = function(name, func) {
19
+ Template.helpers[name] = func;
20
+ };
21
+
22
+ Template.prototype.initialize = function(template) {
23
+ this.engine = engine
24
+ this.template = template;
25
+ };
26
+
27
+ Template.prototype.render = function(data, partials) {
28
+ if (!_.isEmpty(partials)) {
29
+ data.partial = function(k, d) {
30
+ var v = partials[k];
31
+ if (!v) return '';
32
+ if (v instanceof Template) return v.render(d, partials);
33
+ return v;
34
+ };
35
+ }
36
+ data = _.extend({}, this.helpers, Template.globals, data);
37
+ return this.engine(this.template, data);
38
+ };
39
+
40
+ Template.defaults = {
41
+ icon: new Template('<i class="<%-iconClass(icon)"></i>'),
42
+ button: new Template('<div class="btn<%if(type) print(" "+type%>"><%partial("icon",{icon:icon})%><%=content%></div>')
43
+ };
44
+
45
+ } else if (_.isObject(engine)) {
46
+
47
+ if (engine.name == 'mustache.js') {
48
+ // Mustache template
49
+ Template.registerHelper = function(name, func) {
50
+ Template.helpers[name] = function() { return function(text, render) {
51
+ return func(render(text));
52
+ }};
53
+ };
54
+
55
+ Template.prototype.initialize = function(template) {
56
+ this.engine = engine;
57
+ this.template = template;
58
+ this.engine.parse(template);
59
+ };
60
+
61
+ Template.prototype.render = function(data, partials) {
62
+ _.each(partials, function(v, k) {
63
+ if (v instanceof Template) partials[k] = v.template;
64
+ });
65
+ data = _.extend({}, Template.helpers, Template.globals, data);
66
+ return this.engine.render(this.template, data, partials);
67
+ };
68
+ } else if (_.isFunction(engine.compile) &&
69
+ _.isFunction(engine.registerHelper)) {
70
+ // Handlebars template
71
+ Template.registerHelper = function(name, func) {
72
+ engine.registerHelper(name, func);
73
+ };
74
+
75
+ Template.prototype.initialize = function(template) {
76
+ this.engine = engine;
77
+ this.template = this.engine.compile(template);
78
+ };
79
+
80
+ Template.prototype.render = function(data, partials) {
81
+ _.each(partials, function(v, k) {
82
+ if (v instanceof Template) v = v.template;
83
+ this.engine.registerPartial(k, v)
84
+ });
85
+ data = _.extend({}, Template.globals, data);
86
+ return this.template(data);
87
+ };
88
+ } else {
89
+ throw new Error('Unsupported template engine');
90
+ }
91
+
92
+ Template.defaults = {
93
+ icon: new Template('<i class="{{#iconClass}}{{icon}}{{/iconClass}}"></i>'),
94
+ button: new Template('<div class="btn{{#type}} {{.}}{{/type}}">{{>icon}}{{content}}</div>')
95
+ };
96
+ } else {
97
+ throw new Error('Wrong template engine');
98
+ }
99
+
100
+ return Template;
101
+ }
102
+ });
@@ -0,0 +1,16 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore', 'backbone'],
4
+
5
+ function($, _, Backbone) {
6
+ 'use strict';
7
+
8
+ var Base = Backbone.View.extend({
9
+ initialize: function(opts) {
10
+ this.template = opts.template;
11
+ this.app = opts.app;
12
+ }
13
+ });
14
+
15
+ return Base
16
+ });
@@ -0,0 +1,34 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore', 'backbone',
4
+ 'admin_it/views/base', 'admin_it/views/menu'],
5
+
6
+ function($, _, Backbone, Base, Menu) {
7
+ 'use strict';
8
+
9
+ var appLoaded = function() {
10
+ this.render();
11
+ this.menu = new Menu({
12
+ app: this.app,
13
+ template: this.app.templates['main_menu'],
14
+ collection: this.app.metadata.resources,
15
+ el: this.$('.admin-it-main-menu')
16
+ });
17
+ this.menu.render();
18
+ this.menu.select();
19
+ };
20
+
21
+ var Main = Base.extend({
22
+ initialize: function(opts) {
23
+ Base.prototype.initialize.apply(this, arguments);
24
+ this.listenTo(this.app, 'loaded', appLoaded);
25
+ },
26
+
27
+ render: function() {
28
+ this.$el.html(this.template.render());
29
+ return this;
30
+ }
31
+ });
32
+
33
+ return Main
34
+ });
@@ -0,0 +1,51 @@
1
+ define(
2
+
3
+ ['jquery', 'underscore', 'backbone',
4
+ 'admin_it/views/base'],
5
+
6
+ function($, _, Backbone, Base) {
7
+ 'use strict';
8
+
9
+ var Menu = Base.extend({
10
+ events: {
11
+ 'click .admin-it-main-menu-item': 'select'
12
+ },
13
+
14
+ initialize: function(opts) {
15
+ Base.prototype.initialize.apply(this, arguments);
16
+ this.selected = null;
17
+ this.listenTo(this.collection, 'reset add change', this.render);
18
+ },
19
+
20
+ render: function() {
21
+ if (!this.el) return this;
22
+ this.$el.html(this.template.render(
23
+ { items: this.collection.toJSON() },
24
+ { icon: this.app.templates.icon }
25
+ ));
26
+ return this;
27
+ },
28
+
29
+ select: function(index) {
30
+ if (!index) index = 0;
31
+ var model = null;
32
+ if (index instanceof $.Event) {
33
+ index.preventDefault();
34
+ index = $(index.currentTarget).data('id');
35
+ }
36
+ if (_.isNumber(index)) {
37
+ if (index < 0 || index >= this.collection.length) index = 0;
38
+ model = this.collection.at(index);
39
+ } else if (_.isString(index)) {
40
+ model = this.collection.get(index);
41
+ }
42
+ if (!model) return;
43
+ console.log(this);
44
+ this.$('.active').removeClass('active');
45
+ this.$('[data-id="' + model.id + '"]').addClass('active');
46
+ this.trigger('selected', model);
47
+ }
48
+ });
49
+
50
+ return Menu
51
+ });
@@ -0,0 +1 @@
1
+ <ul class="nav nav-pills nav-stacked">{{#items}}<li class="admin-it-main-menu-item" data-id="{{id}}"><a href="#">{{#icon}}{{>icon}} {{/icon}}{{name}}</a></li>{{/items}}</ul>
@@ -0,0 +1,5 @@
1
+ ul.nav.nav-pills.nav-stacked
2
+ | {{#items}}
3
+ li.admin-it-main-menu-item data-id="{{id}}": a href="#"
4
+ | {{#icon}}{{>icon}} {{/icon}}{{name}}
5
+ | {{/items}}
@@ -0,0 +1 @@
1
+ <div class="container-fluid"><div class="row"><div class="admin-it-main-menu col-md-2"></div><div class="admin-it-work-area col-md-10"></div></div></div>
@@ -0,0 +1,4 @@
1
+ .container-fluid
2
+ .row
3
+ .admin-it-main-menu.col-md-2
4
+ .admin-it-work-area.col-md-10
@@ -0,0 +1 @@
1
+ <script data-name="main_menu" data-type="template" type="application/mustache"><ul class="nav nav-pills nav-stacked">{{#items}}<li class="admin-it-main-menu-item" data-id="{{id}}"><a href="#">{{#icon}}{{>icon}} {{/icon}}{{name}}</a></li>{{/items}}</ul></script><script data-name="main_view" data-type="template" type="application/mustache"><div class="container-fluid"><div class="row"><div class="admin-it-main-menu col-md-2"></div><div class="admin-it-work-area col-md-10"></div></div></div></script>
@@ -0,0 +1,3 @@
1
+ - render_each File.join(pwd, 'bootstrap') do |name, content|
2
+ script type="application/mustache" data-type="template" data-name=name.split('/').last
3
+ == content
@@ -0,0 +1,51 @@
1
+ require 'thor'
2
+ require 'tilt'
3
+
4
+ # project compilation
5
+ class Compile < Thor
6
+ FOLDERS = [File.join(Dir.pwd, 'src', 'templates')]
7
+
8
+ # context
9
+ class Context
10
+ attr_reader :pwd
11
+
12
+ def render_each(folder)
13
+ return unless File.directory?(folder)
14
+ Dir[File.join(folder, '**', '*.html.*')].each do |file|
15
+ name = file.split('.')[0..-3].join('.')
16
+ yield name, render(name)
17
+ end
18
+ end
19
+
20
+ def include(name)
21
+ FOLDERS.each do |folder|
22
+ files = Dir[File.absolute_path(name, folder)]
23
+ files.each { |file| return File.read(file) }
24
+ end
25
+ fail "Couldn't include #{name}"
26
+ end
27
+
28
+ def render(name)
29
+ FOLDERS.each do |folder|
30
+ files = Dir[File.absolute_path("#{name}.html.*", folder)]
31
+ files.each do |file|
32
+ @pwd = File.dirname(file)
33
+ return Tilt.new(file).render(self)
34
+ end
35
+ end
36
+ fail "Couldn't render #{name}"
37
+ end
38
+ end
39
+
40
+ desc 'templates', 'compile templates'
41
+ def templates
42
+ files = Dir[File.join(Dir.pwd, '*.html.*')]
43
+ FOLDERS.each { |folder| files += Dir[File.join(folder, '**', '*.html.*')] }
44
+ context = Context.new
45
+ files.each do |file|
46
+ name = file.split('.')[0..-3].join('.')
47
+ output = "#{name}.html"
48
+ File.write(output, context.render(name))
49
+ end
50
+ end
51
+ end
data/config/routes.rb CHANGED
@@ -20,5 +20,5 @@ AdminIt::Engine.routes.draw do
20
20
  end
21
21
 
22
22
  # generates signed urls for S3
23
- resources :signed_url, only: :index
23
+ resources :signed_url, only: :index, controller: 'admin_it/signed_url'
24
24
  end
@@ -1,5 +1,5 @@
1
1
  #
2
2
  module AdminIt
3
3
  # Current gem version
4
- VERSION = '1.2.6'
4
+ VERSION = '1.2.7'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: admin_it
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.6
4
+ version: 1.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey Ovchinnikov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-10 00:00:00.000000000 Z
11
+ date: 2014-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -284,6 +284,31 @@ files:
284
284
  - app/views/admin_it/tiles.html.slim
285
285
  - app/views/layouts/admin_it.html.slim
286
286
  - app/views/layouts/admin_it_dialog.html.slim
287
+ - client/.bowerrc
288
+ - client/Gemfile
289
+ - client/bower.json
290
+ - client/index.html
291
+ - client/index.html.slim
292
+ - client/lib/nestedtypes.js
293
+ - client/metadata.json
294
+ - client/src/js/app.js
295
+ - client/src/js/collections/resources.js
296
+ - client/src/js/icons.js
297
+ - client/src/js/main.js
298
+ - client/src/js/models/base.js
299
+ - client/src/js/models/metadata.js
300
+ - client/src/js/models/resource.js
301
+ - client/src/js/template.js
302
+ - client/src/js/views/base.js
303
+ - client/src/js/views/main.js
304
+ - client/src/js/views/menu.js
305
+ - client/src/templates/bootstrap.html
306
+ - client/src/templates/bootstrap.html.slim
307
+ - client/src/templates/bootstrap/main_menu.html
308
+ - client/src/templates/bootstrap/main_menu.html.slim
309
+ - client/src/templates/bootstrap/main_view.html
310
+ - client/src/templates/bootstrap/main_view.html.slim
311
+ - client/tasks/compile.thor
287
312
  - config.ru
288
313
  - config/routes.rb
289
314
  - lib/admin_it.rb