admin_it 1.2.6 → 1.2.7

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.
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