type_station 0.0.1.pre → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/type_station/application.js +13 -1
- data/app/assets/javascripts/type_station/editables/admin_bar.js.coffee +32 -0
- data/app/assets/javascripts/type_station/editables/file.js.coffee +55 -0
- data/app/assets/javascripts/type_station/editables/image.js.coffee +56 -0
- data/app/assets/javascripts/type_station/editables/new_model.js.coffee +72 -0
- data/app/assets/javascripts/type_station/editables/text_html.js.coffee +38 -0
- data/app/assets/javascripts/type_station/init.js.coffee +26 -0
- data/app/assets/javascripts/type_station/lib/models.js.coffee +25 -0
- data/app/assets/javascripts/type_station/lib/ts.js.coffee +1 -0
- data/app/assets/stylesheets/type_station/admin_bar.css.scss +84 -0
- data/app/assets/stylesheets/type_station/application.css +3 -0
- data/app/assets/stylesheets/type_station/base.css.scss +42 -0
- data/app/controllers/type_station/admin/pages_controller.rb +16 -1
- data/app/presenters/type_station/content_presenter.rb +0 -27
- data/app/presenters/type_station/page_presenter.rb +1 -5
- data/app/views/type_station/toolbars/_admin_bar.html.haml +29 -0
- data/config/routes.rb +1 -1
- data/lib/type_station/version.rb +1 -1
- data/lib/type_station/view_helpers.rb +63 -14
- metadata +43 -6
- data/app/assets/javascripts/type_station/editable_text.js.coffee +0 -54
- data/app/views/type_station/toolbars/_text.html.haml +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 211c046817891ef530fb8e52497e2b362ddf34b3
|
4
|
+
data.tar.gz: 1cb1804ecbddf73afa4cbdf17e940f6587ca3cb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87545439337fea12d9ebc0e4c173a25c22fdb320d0d7d42e0a1c5817297ebf64391fad4c4f43df09f5d822e2394d315c02d68ccdf16ef961e051dccd1e4b5200
|
7
|
+
data.tar.gz: 7eca9bd8e7233dfec78f9e334d5f8539ccc6addd61e002216766cd1ad6dcb020515f2dda75ed55252a943a3dda8588173b7514b43eba3263fe9479dc0ee25aef
|
@@ -10,5 +10,17 @@
|
|
10
10
|
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
11
|
// about supported directives.
|
12
12
|
//
|
13
|
+
//= require jquery-fileupload/basic
|
14
|
+
//= require jquery.cloudinary
|
13
15
|
//= require medium-editor
|
14
|
-
//= require
|
16
|
+
//= require drop
|
17
|
+
//= require vex.combined.min
|
18
|
+
//= require type_station/lib/ts
|
19
|
+
//= require type_station/lib/models
|
20
|
+
//= require_tree ./editables
|
21
|
+
//= require type_station/init
|
22
|
+
//= require_self
|
23
|
+
|
24
|
+
jQuery(function(){
|
25
|
+
window.TS.init();
|
26
|
+
});
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class window.TS.AdminBar
|
2
|
+
constructor: (@element) ->
|
3
|
+
template = @element.html()
|
4
|
+
$('body').append(template)
|
5
|
+
|
6
|
+
$('#ts-admin-bar-edit').on 'click', ->
|
7
|
+
$('#ts-admin-bar').removeClass('ts-hidden')
|
8
|
+
$('#ts-admin-bar-edit').addClass('ts-hidden')
|
9
|
+
window.TS.enable()
|
10
|
+
|
11
|
+
$('#ts-admin-bar-cancel').on 'click', ->
|
12
|
+
$('#ts-admin-bar').addClass('ts-hidden')
|
13
|
+
$('#ts-admin-bar-edit').removeClass('ts-hidden')
|
14
|
+
window.TS.disable()
|
15
|
+
|
16
|
+
$('#ts-admin-bar-save').on 'click', ->
|
17
|
+
window.TS.save()
|
18
|
+
|
19
|
+
$('#ts-admin-bar input').on 'change', ->
|
20
|
+
model = window.TS.getModel $(@).data('ts-edit-url')
|
21
|
+
model.set($(@).data('ts-field'), { field: $(@).data('ts-field'), value: $(@).val(), type: 'text' })
|
22
|
+
|
23
|
+
drop = new Drop
|
24
|
+
target: $('#ts-admin-bar .ts-options i')[0]
|
25
|
+
content: $('#ts-admin-bar-options')[0]
|
26
|
+
position: 'bottom center'
|
27
|
+
openOn: 'click'
|
28
|
+
classes: 'drop-theme-arrows-bounce-dark'
|
29
|
+
|
30
|
+
enable: ->
|
31
|
+
|
32
|
+
disable: ->
|
@@ -0,0 +1,55 @@
|
|
1
|
+
buildUploader = (element, data)->
|
2
|
+
elementId = $(element).attr('id')
|
3
|
+
$input = $('<input/>')
|
4
|
+
$input
|
5
|
+
.attr({type: "file", name: "file", class: 'ts-editable-file-input', 'data-form-data': JSON.stringify(data), 'data-element-id': elementId})
|
6
|
+
.cloudinary_fileupload()
|
7
|
+
.bind 'cloudinaryprogress', (e, data) ->
|
8
|
+
$('.ts-progress-bar').css('width', Math.round((data.loaded * 100.0) / data.total) + '%')
|
9
|
+
.bind 'cloudinarystart', (e, data) ->
|
10
|
+
$(this).prop('disabled', true)
|
11
|
+
$('body').append($('<div>').addClass('ts-progress-bar'))
|
12
|
+
.bind 'cloudinarydone', (e, data) ->
|
13
|
+
$element = $("##{$(this).data('elementId')}")
|
14
|
+
for imageTag in $('.ts-editable-link-tag', $element)
|
15
|
+
$(imageTag).attr('href', $.cloudinary.url(data.result.public_id, {}))
|
16
|
+
$element.data('drop').close()
|
17
|
+
$(this).prop('disabled', false)
|
18
|
+
$('.ts-progress-bar').remove()
|
19
|
+
|
20
|
+
model = window.TS.getModel $element.data('ts-edit-url')
|
21
|
+
model.set($element.data('ts-field'), { field: $element.data('ts-field'), value: {identifier: data.result.public_id}, type: 'file' })
|
22
|
+
$input
|
23
|
+
|
24
|
+
setUpDrops = (elements)->
|
25
|
+
drops = []
|
26
|
+
|
27
|
+
for element in elements
|
28
|
+
tsData = $(element).data('tsData')
|
29
|
+
drop = new Drop
|
30
|
+
target: $('.ts-editable-button', element)[0]
|
31
|
+
content: buildUploader(element, tsData)[0]
|
32
|
+
position: 'bottom center'
|
33
|
+
openOn: 'click'
|
34
|
+
classes: 'drop-theme-arrows-bounce-dark'
|
35
|
+
$(element).data('drop', drop)
|
36
|
+
drops.push drop
|
37
|
+
|
38
|
+
drops
|
39
|
+
|
40
|
+
class window.TS.EditableFile
|
41
|
+
constructor: (@elements) ->
|
42
|
+
@drops = []
|
43
|
+
for element in elements
|
44
|
+
$(element).append($('<div>').addClass('ts-editable-button').addClass('ts-button').html("<i class='ion-ios-compose-outline'></i>"))
|
45
|
+
|
46
|
+
enable: ->
|
47
|
+
@disable()
|
48
|
+
@drops = setUpDrops(@elements)
|
49
|
+
|
50
|
+
disable: ->
|
51
|
+
for drop in @drops
|
52
|
+
drop.close()
|
53
|
+
drop.remove()
|
54
|
+
drop.destroy()
|
55
|
+
@drops = []
|
@@ -0,0 +1,56 @@
|
|
1
|
+
buildUploader = (element, data)->
|
2
|
+
elementId = $(element).attr('id')
|
3
|
+
$input = $('<input/>')
|
4
|
+
$input
|
5
|
+
.attr({type: "file", name: "file", class: 'ts-editable-image-input', 'data-form-data': JSON.stringify(data), 'data-element-id': elementId})
|
6
|
+
.cloudinary_fileupload()
|
7
|
+
.bind 'cloudinaryprogress', (e, data) ->
|
8
|
+
$('.ts-progress-bar').css('width', Math.round((data.loaded * 100.0) / data.total) + '%')
|
9
|
+
.bind 'cloudinarystart', (e, data) ->
|
10
|
+
$(this).prop('disabled', true)
|
11
|
+
$('body').append($('<div>').addClass('ts-progress-bar'))
|
12
|
+
.bind 'cloudinarydone', (e, data) ->
|
13
|
+
$element = $("##{$(this).data('elementId')}")
|
14
|
+
for imageTag in $('.ts-editable-image-tag', $element)
|
15
|
+
$(imageTag).attr('src', $.cloudinary.url(data.result.public_id, $(imageTag).data()))
|
16
|
+
$element.data('drop').close()
|
17
|
+
$(this).prop('disabled', false)
|
18
|
+
$('.ts-progress-bar').remove()
|
19
|
+
|
20
|
+
model = window.TS.getModel $element.data('ts-edit-url')
|
21
|
+
model.set($element.data('ts-field'), { field: $element.data('ts-field'), value: {identifier: data.result.public_id}, type: 'image' })
|
22
|
+
|
23
|
+
$input
|
24
|
+
|
25
|
+
setUpDrops = (elements)->
|
26
|
+
drops = []
|
27
|
+
|
28
|
+
for element in elements
|
29
|
+
tsData = $(element).data('tsData')
|
30
|
+
drop = new Drop
|
31
|
+
target: $('.ts-editable-button', element)[0]
|
32
|
+
content: buildUploader(element, tsData)[0]
|
33
|
+
position: 'bottom center'
|
34
|
+
openOn: 'click'
|
35
|
+
classes: 'drop-theme-arrows-bounce-dark'
|
36
|
+
$(element).data('drop', drop)
|
37
|
+
drops.push drop
|
38
|
+
|
39
|
+
drops
|
40
|
+
|
41
|
+
class window.TS.EditableImage
|
42
|
+
constructor: (@elements) ->
|
43
|
+
@drops = []
|
44
|
+
for element in elements
|
45
|
+
$(element).append($('<div>').addClass('ts-editable-button').addClass('ts-button').html("<i class='ion-ios-compose-outline'></i>"))
|
46
|
+
|
47
|
+
enable: ->
|
48
|
+
@disable()
|
49
|
+
@drops = setUpDrops(@elements)
|
50
|
+
|
51
|
+
disable: ->
|
52
|
+
for drop in @drops
|
53
|
+
drop.close()
|
54
|
+
drop.remove()
|
55
|
+
drop.destroy()
|
56
|
+
@drops = []
|
@@ -0,0 +1,72 @@
|
|
1
|
+
buildFields = (element) ->
|
2
|
+
$element = $(element)
|
3
|
+
$ul = $('<ul/>')
|
4
|
+
tsFields = $element.data('tsFields')
|
5
|
+
tsNewUrl = $element.data('tsNewUrl')
|
6
|
+
tsParentId = $element.data('tsParentId')
|
7
|
+
|
8
|
+
for field in tsFields
|
9
|
+
$li = $('<li/>')
|
10
|
+
$input = $('<input/>')
|
11
|
+
|
12
|
+
$input
|
13
|
+
.attr({type: "text", name: "text", placeholder: field})
|
14
|
+
.data({'ts-field': field, 'ts-new-url': tsNewUrl})
|
15
|
+
.on 'change', (e) ->
|
16
|
+
$(@).parent().parent().data($(@).data('ts-field'), $(@).val())
|
17
|
+
.appendTo($li)
|
18
|
+
|
19
|
+
$li.appendTo($ul)
|
20
|
+
|
21
|
+
$li = $('<li/>')
|
22
|
+
$button = $('<button/>')
|
23
|
+
$button
|
24
|
+
.html('<i class="ion-ios-checkmark-outline"></i>')
|
25
|
+
.addClass('ts-button')
|
26
|
+
.addClass('ts-button-primary')
|
27
|
+
.data({'ts-field': field, 'ts-new-url': tsNewUrl, 'ts-parent-id': tsParentId})
|
28
|
+
.on 'click', ->
|
29
|
+
data = {}
|
30
|
+
data[$(@).data('ts-field')] = $(@).parent().parent().data($(@).data('ts-field'))
|
31
|
+
data['parent_id'] = $(@).data('ts-parent-id') if $(@).data('ts-parent-id')
|
32
|
+
console.log data
|
33
|
+
$.ajax
|
34
|
+
type: "POST"
|
35
|
+
url: $(@).data('ts-new-url')
|
36
|
+
dataType: 'json'
|
37
|
+
contentType: 'application/json'
|
38
|
+
data: JSON.stringify(data)
|
39
|
+
success: (data, status) -> window.location.reload()
|
40
|
+
.appendTo($li)
|
41
|
+
$li.appendTo($ul)
|
42
|
+
|
43
|
+
$ul
|
44
|
+
|
45
|
+
setUpDrops = (elements)->
|
46
|
+
drops = []
|
47
|
+
for element in elements
|
48
|
+
drop = new Drop
|
49
|
+
target: $(element)[0]
|
50
|
+
content: buildFields(element)[0]
|
51
|
+
position: 'bottom center'
|
52
|
+
openOn: 'click'
|
53
|
+
classes: 'drop-theme-arrows-bounce-dark'
|
54
|
+
$(element).data('drop', drop)
|
55
|
+
drops.push drop
|
56
|
+
|
57
|
+
drops
|
58
|
+
|
59
|
+
class window.TS.NewModel
|
60
|
+
constructor: (@elements) ->
|
61
|
+
@drops = []
|
62
|
+
|
63
|
+
enable: ->
|
64
|
+
@disable()
|
65
|
+
@drops = setUpDrops(@elements)
|
66
|
+
|
67
|
+
disable: ->
|
68
|
+
for drop in @drops
|
69
|
+
drop.close()
|
70
|
+
drop.remove()
|
71
|
+
drop.destroy()
|
72
|
+
@drops = []
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class window.TS.EditableText
|
2
|
+
constructor: (@elements) ->
|
3
|
+
@editor = new MediumEditor @elements,
|
4
|
+
disableReturn: true
|
5
|
+
buttons: ['bold', 'italic', 'underline', 'anchor']
|
6
|
+
@editor.deactivate()
|
7
|
+
|
8
|
+
enable: ->
|
9
|
+
@editor.activate()
|
10
|
+
@elements.on 'input', ->
|
11
|
+
model = window.TS.getModel $(@).data('ts-edit-url')
|
12
|
+
if $(@).is(':input')
|
13
|
+
model.set($(@).data('ts-field'), { field: $(@).data('ts-field'), value: $(@).val(), type: 'text' })
|
14
|
+
else
|
15
|
+
model.set($(@).data('ts-field'), { field: $(@).data('ts-field'), value: $(@).html(), type: 'text' })
|
16
|
+
|
17
|
+
disable: ->
|
18
|
+
@editor.deactivate()
|
19
|
+
@elements.off 'input'
|
20
|
+
|
21
|
+
|
22
|
+
class window.TS.EditableHtml
|
23
|
+
constructor: (@elements) ->
|
24
|
+
@editor = new MediumEditor @elements,
|
25
|
+
buttons: ['bold', 'italic', 'underline', 'anchor', 'header1', 'header2', 'unorderedlist', 'orderedlist', 'justifyLeft', 'justifyFull', 'justifyCenter', 'justifyRight']
|
26
|
+
@editor.deactivate()
|
27
|
+
|
28
|
+
enable: ->
|
29
|
+
@editor.activate()
|
30
|
+
@elements.on 'input', ->
|
31
|
+
model = window.TS.getModel $(@).data('ts-edit-url')
|
32
|
+
if $(@).is(':input')
|
33
|
+
model.set($(@).data('ts-field'), { field: $(@).data('ts-field'), value: $(@).val(), type: 'html' })
|
34
|
+
else
|
35
|
+
model.set($(@).data('ts-field'), { field: $(@).data('ts-field'), value: $(@).html(), type: 'html' })
|
36
|
+
disable: ->
|
37
|
+
@editor.deactivate()
|
38
|
+
@elements.off 'input'
|
@@ -0,0 +1,26 @@
|
|
1
|
+
window.TS.models = new window.TS.Store
|
2
|
+
window.TS.editors = new window.TS.Store
|
3
|
+
|
4
|
+
window.TS.getModel = (url) ->
|
5
|
+
model = @models.get url
|
6
|
+
unless model
|
7
|
+
model = new window.TS.Model url
|
8
|
+
@models.set url, model
|
9
|
+
model
|
10
|
+
|
11
|
+
window.TS.enable = ->
|
12
|
+
@editors.each (id, editor) -> editor.enable()
|
13
|
+
|
14
|
+
window.TS.disable = ->
|
15
|
+
@editors.each (id, editor) -> editor.disable()
|
16
|
+
|
17
|
+
window.TS.save = ->
|
18
|
+
@models.each (id, model) -> model.save()
|
19
|
+
|
20
|
+
window.TS.init = ->
|
21
|
+
@editors.set 'ts-admin-bar', new window.TS.AdminBar $('#ts-admin-bar-template')
|
22
|
+
@editors.set 'ts-editable-text', new window.TS.EditableText $('span.ts-editable-text')
|
23
|
+
@editors.set 'ts-editable-html', new window.TS.EditableHtml $('.ts-editable-html')
|
24
|
+
@editors.set 'ts-editable-image', new window.TS.EditableImage $('.ts-editable-image')
|
25
|
+
@editors.set 'ts-editable-file', new window.TS.EditableFile $('.ts-editable-file')
|
26
|
+
@editors.set 'ts-new-model', new window.TS.NewModel $('.ts-new-model')
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class window.TS.Store
|
2
|
+
constructor: (@id = null) ->
|
3
|
+
@STORE = {}
|
4
|
+
get: (key) -> @STORE[key]
|
5
|
+
set: (key, value) -> @STORE[key] = value
|
6
|
+
|
7
|
+
each: (callback) ->
|
8
|
+
for key, value of @STORE
|
9
|
+
callback?(key, value)
|
10
|
+
|
11
|
+
class window.TS.Model extends window.TS.Store
|
12
|
+
save: (callback = ->) ->
|
13
|
+
self = @
|
14
|
+
data = []
|
15
|
+
|
16
|
+
for key, value of @STORE
|
17
|
+
data.push(value)
|
18
|
+
|
19
|
+
$.ajax
|
20
|
+
type: "PATCH"
|
21
|
+
url: self.id
|
22
|
+
dataType: 'json'
|
23
|
+
contentType: 'application/json'
|
24
|
+
data: JSON.stringify({contents: data})
|
25
|
+
success: (data) -> callback(data)
|
@@ -0,0 +1 @@
|
|
1
|
+
window.TS = {}
|
@@ -0,0 +1,84 @@
|
|
1
|
+
body {
|
2
|
+
padding-bottom: 50px;
|
3
|
+
}
|
4
|
+
|
5
|
+
|
6
|
+
#ts-admin-bar-edit {
|
7
|
+
position: fixed;
|
8
|
+
left: 5px;
|
9
|
+
bottom: 5px;
|
10
|
+
width: 100px;
|
11
|
+
button {
|
12
|
+
line-height: 1.5em;
|
13
|
+
padding: 0px 10px;
|
14
|
+
i {
|
15
|
+
font-size: 2em;
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
#ts-admin-bar {
|
21
|
+
position: fixed;
|
22
|
+
background: #fff;
|
23
|
+
border-top: 3px solid #ccc;
|
24
|
+
bottom: 0px;
|
25
|
+
left: 0px;
|
26
|
+
right: 0px;
|
27
|
+
padding: 0px;
|
28
|
+
margin: 0px;
|
29
|
+
font-family: Tahoma, Geneva, sans-serif;
|
30
|
+
|
31
|
+
ul {
|
32
|
+
display: table;
|
33
|
+
width: 100%;
|
34
|
+
padding: 0px;
|
35
|
+
margin: 0px;
|
36
|
+
padding: 0px;
|
37
|
+
li {
|
38
|
+
display: table-cell;
|
39
|
+
margin: 0px;
|
40
|
+
padding: 0px;
|
41
|
+
vertical-align: middle;
|
42
|
+
|
43
|
+
&.ts-brand {
|
44
|
+
background: #57ad68;
|
45
|
+
color: #fff;
|
46
|
+
text-align: center;
|
47
|
+
text-transform: uppercase;
|
48
|
+
}
|
49
|
+
|
50
|
+
&.ts-title {
|
51
|
+
width: 78%;
|
52
|
+
input {
|
53
|
+
display: block;
|
54
|
+
width: 100%;
|
55
|
+
border: 0px;
|
56
|
+
outline: none;
|
57
|
+
padding: 7px 15px;
|
58
|
+
font-size: 1.4em;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
&.ts-actions {
|
63
|
+
width: 15%;
|
64
|
+
|
65
|
+
.ts-button-group {
|
66
|
+
width: 100%;
|
67
|
+
}
|
68
|
+
|
69
|
+
button {
|
70
|
+
width: 30%;
|
71
|
+
line-height: 1.5em;
|
72
|
+
i {
|
73
|
+
font-size: 2em;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
.ts-button-primary {
|
78
|
+
width: 40%;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
}
|
84
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
.ts-button-group {
|
2
|
+
display: table;
|
3
|
+
button {
|
4
|
+
display: table-cell;
|
5
|
+
}
|
6
|
+
}
|
7
|
+
|
8
|
+
.ts-hidden {
|
9
|
+
display: none;
|
10
|
+
}
|
11
|
+
|
12
|
+
.ts-button {
|
13
|
+
font-size: 1em;
|
14
|
+
background: #eee;
|
15
|
+
color: #444;
|
16
|
+
border: 0px;
|
17
|
+
padding: 7px 5px;
|
18
|
+
margin: 0px;
|
19
|
+
outline: none;
|
20
|
+
font-family: Tahoma, Geneva, sans-serif;
|
21
|
+
}
|
22
|
+
|
23
|
+
.ts-button-primary {
|
24
|
+
background: #57ad68;
|
25
|
+
color: #fff;
|
26
|
+
}
|
27
|
+
|
28
|
+
.ts-progress-bar {
|
29
|
+
width: 0;
|
30
|
+
height: 5px;
|
31
|
+
background: #57ad68;
|
32
|
+
position: fixed;
|
33
|
+
top: 0px;
|
34
|
+
left: 0px;
|
35
|
+
}
|
36
|
+
|
37
|
+
.ts-editable-image, .ts-editable-file { position: relative;}
|
38
|
+
.ts-editable-button {
|
39
|
+
position: absolute;
|
40
|
+
top:0px;
|
41
|
+
right: 0px;
|
42
|
+
}
|
@@ -1,6 +1,21 @@
|
|
1
1
|
module TypeStation
|
2
2
|
module Admin
|
3
3
|
class PagesController < ::TypeStation::AdminController
|
4
|
+
|
5
|
+
def create
|
6
|
+
@page = TypeStation::Page.new(title: params[:title])
|
7
|
+
|
8
|
+
if params[:parent_id]
|
9
|
+
parent_page = TypeStation::Page.find(params[:parent_id])
|
10
|
+
@page.parent = parent_page
|
11
|
+
end
|
12
|
+
|
13
|
+
if @page.save
|
14
|
+
render json: { status: :success, url: @page.path }, status: :ok
|
15
|
+
else
|
16
|
+
render json: @page.errors, status: :unprocessable_entity
|
17
|
+
end
|
18
|
+
end
|
4
19
|
|
5
20
|
def update
|
6
21
|
@page = TypeStation::Page.find(params[:id])
|
@@ -15,7 +30,7 @@ module TypeStation
|
|
15
30
|
private
|
16
31
|
|
17
32
|
def contents
|
18
|
-
[params[:contents]].flatten
|
33
|
+
[params[:contents]].compact.flatten
|
19
34
|
end
|
20
35
|
|
21
36
|
end
|
@@ -6,32 +6,5 @@ module TypeStation
|
|
6
6
|
content.get
|
7
7
|
end
|
8
8
|
|
9
|
-
def call(&block)
|
10
|
-
case content.type
|
11
|
-
when :image, :file
|
12
|
-
block.call(OpenStruct.new(content.get))
|
13
|
-
when :multiple_select
|
14
|
-
block.call(content.get)
|
15
|
-
when :html
|
16
|
-
content.get.html_safe
|
17
|
-
else
|
18
|
-
content.get
|
19
|
-
end.to_s
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def image_struct
|
25
|
-
OpenStruct.new({url: content.get, alt: ''})
|
26
|
-
end
|
27
|
-
|
28
|
-
def image_struct
|
29
|
-
OpenStruct.new({url: '', alt: ''})
|
30
|
-
end
|
31
|
-
|
32
|
-
def select_struct
|
33
|
-
OpenStruct.new({value: content.get, values: content.get })
|
34
|
-
end
|
35
|
-
|
36
9
|
end
|
37
10
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module TypeStation
|
2
2
|
class PagePresenter < BasePresenter
|
3
3
|
presents :page
|
4
|
-
delegate :to_param, :path, :slug, :template_name, :template_name?, :redirect_to, :redirect?, to: :page
|
4
|
+
delegate :to_param, :title, :path, :slug, :template_name, :template_name?, :redirect_to, :redirect?, to: :page
|
5
5
|
|
6
6
|
def initialize(object, template)
|
7
7
|
super(object, template)
|
@@ -12,10 +12,6 @@ module TypeStation
|
|
12
12
|
h.type_station.admin_page_url(page)
|
13
13
|
end
|
14
14
|
|
15
|
-
def title
|
16
|
-
ContentPresenter.new(OpenStruct.new({type: :text, get: page.title}), @template)
|
17
|
-
end
|
18
|
-
|
19
15
|
def children
|
20
16
|
@children ||= page.children.map {|p| PagePresenter.new(p, @template)}
|
21
17
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#ts-admin-bar-edit
|
2
|
+
%button.ts-button.ts-button-primary
|
3
|
+
%i.ion-ios-compose-outline
|
4
|
+
|
5
|
+
#ts-admin-bar.ts-hidden
|
6
|
+
%ul
|
7
|
+
%li.ts-brand
|
8
|
+
ts
|
9
|
+
%li.ts-title
|
10
|
+
= text_field_tag 'page_title', model.try(:title), data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: :title, ts_data: {}}
|
11
|
+
%li.ts-actions
|
12
|
+
.ts-button-group
|
13
|
+
%button.ts-button.ts-options
|
14
|
+
%i.ion-ios-gear
|
15
|
+
%button#ts-admin-bar-cancel.ts-button
|
16
|
+
%i.ion-ios-close-outline
|
17
|
+
%button#ts-admin-bar-save.ts-button.ts-button-primary
|
18
|
+
%i.ion-ios-checkmark-outline
|
19
|
+
|
20
|
+
#ts-admin-bar-options
|
21
|
+
%ul
|
22
|
+
%li
|
23
|
+
Options 1
|
24
|
+
%li
|
25
|
+
Options 2
|
26
|
+
%li
|
27
|
+
Options 3
|
28
|
+
%li
|
29
|
+
Options 4
|
data/config/routes.rb
CHANGED
data/lib/type_station/version.rb
CHANGED
@@ -5,9 +5,16 @@ module TypeStation
|
|
5
5
|
result = ''
|
6
6
|
presenter = model.try(key)
|
7
7
|
type = options[:type] || :text
|
8
|
+
id = options[:id] || "#{model.to_param}-#{key}-#{SecureRandom.hex(3)}"
|
9
|
+
data = options[:data] || {}
|
8
10
|
|
9
11
|
if presenter.present?
|
10
|
-
result +=
|
12
|
+
result += case type
|
13
|
+
when :image, :file
|
14
|
+
capture(OpenStruct.new(presenter.value), &block)
|
15
|
+
else
|
16
|
+
presenter.value
|
17
|
+
end
|
11
18
|
else
|
12
19
|
result += capture(OpenStruct.new({}), &block)
|
13
20
|
end
|
@@ -15,26 +22,68 @@ module TypeStation
|
|
15
22
|
if type_station_current_user
|
16
23
|
case type
|
17
24
|
when :text
|
18
|
-
content_tag(:span, result, class: 'ts-editable-text', id:
|
25
|
+
content_tag(:span, result.html_safe, class: 'ts-editable-text', id: id, data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key, ts_data: data})
|
19
26
|
when :html
|
20
|
-
content_tag(:div, result.html_safe, class: 'ts-editable-html', id:
|
21
|
-
when :image
|
22
|
-
|
27
|
+
content_tag(:div, result.html_safe, class: 'ts-editable-html', id: id, data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key, ts_data: data})
|
28
|
+
when :image, :file
|
29
|
+
data = Cloudinary::Utils.sign_request(Cloudinary::Uploader.build_upload_params({}), {}) rescue {}
|
30
|
+
content_tag(:div, result.html_safe, class: "ts-editable-#{type}", id: id, data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key, ts_data: data })
|
23
31
|
when :select
|
24
|
-
content_tag(:div, result, class: 'ts-editable-select', data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key})
|
32
|
+
content_tag(:div, result.html_safe, class: 'ts-editable-select', id: id, data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key, ts_data: data})
|
25
33
|
when :multiple_select
|
26
|
-
content_tag(:div, result, class: 'ts-editable-multiple-select', data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key})
|
34
|
+
content_tag(:div, result.html_safe, class: 'ts-editable-multiple-select', id: id, data: {ts_id: model.to_param, ts_edit_url: model.edit_url, ts_field: key, ts_data: data})
|
27
35
|
end
|
28
36
|
else
|
29
37
|
result
|
30
38
|
end
|
31
39
|
end
|
32
40
|
|
33
|
-
def
|
41
|
+
def ts_new(name_or_url, options = {}, &block)
|
42
|
+
content_tag = options[:content_tag] || :div
|
43
|
+
parent = options[:parent] || nil
|
44
|
+
fields = options[:fields] || ['title']
|
45
|
+
|
46
|
+
if parent.is_a?(String)
|
47
|
+
parent_id = parent
|
48
|
+
else
|
49
|
+
parent_id = parent.to_param
|
50
|
+
end
|
51
|
+
|
52
|
+
if name_or_url.is_a?(Symbol)
|
53
|
+
url = case name_or_url
|
54
|
+
when :page
|
55
|
+
type_station.admin_pages_url
|
56
|
+
end
|
57
|
+
else
|
58
|
+
url = name_or_url
|
59
|
+
end
|
60
|
+
|
61
|
+
result = capture(&block)
|
62
|
+
|
63
|
+
content_tag(content_tag, result.html_safe, class: 'ts-new-model', data: {ts_new_url: url, ts_parent_id: parent_id, ts_fields: fields})
|
64
|
+
end
|
65
|
+
|
66
|
+
def ts_image_tag(identifier, options = {})
|
67
|
+
css_class = options.delete(:class) if options.include?(:class)
|
68
|
+
cl_image_tag(identifier, options.merge({class: ['ts-editable-image-tag', css_class], data: options}))
|
69
|
+
end
|
70
|
+
|
71
|
+
def ts_link_to(identifier, html_options = nil, &block)
|
72
|
+
css_class = html_options.delete(:class) if html_options.include?(:class)
|
73
|
+
content_tag(:a, nil, html_options.merge({class: ['ts-editable-link-tag', css_class], href: cloudinary_url(identifier)}), &block)
|
74
|
+
end
|
75
|
+
|
76
|
+
def type_station_admin_toolbar(model)
|
77
|
+
type_station_toolbar('ts-admin-bar', model, 'admin_bar')
|
78
|
+
end
|
79
|
+
|
80
|
+
def type_station_init
|
34
81
|
result = ''.html_safe
|
35
82
|
if type_station_current_user
|
36
|
-
|
37
|
-
result <<
|
83
|
+
result << stylesheet_link_tag("//code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css")
|
84
|
+
result << stylesheet_link_tag("type_station/application", media: "all")
|
85
|
+
result << javascript_include_tag("type_station/application")
|
86
|
+
result << cloudinary_js_config
|
38
87
|
end
|
39
88
|
result
|
40
89
|
end
|
@@ -43,12 +92,12 @@ module TypeStation
|
|
43
92
|
instance_eval &TypeStation.config.current_user
|
44
93
|
end
|
45
94
|
|
46
|
-
def type_station_toolbar(id, partial_name
|
47
|
-
type_station_template(id, render(partial: "type_station/toolbars/#{partial_name}").html_safe)
|
95
|
+
def type_station_toolbar(id, model, partial_name)
|
96
|
+
type_station_template([id, 'template'].join('-'), render(partial: "type_station/toolbars/#{partial_name}", locals: {model: model}).html_safe)
|
48
97
|
end
|
49
98
|
|
50
|
-
def type_station_template(id, content)
|
51
|
-
content_tag :script, content, id: id, type:
|
99
|
+
def type_station_template(id, content, type = 'text/x-type-station-template')
|
100
|
+
content_tag :script, content, id: id, type: type
|
52
101
|
end
|
53
102
|
|
54
103
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: type_station
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Adams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 2.0.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: jquery-fileupload-rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: cloudinary
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: coffee-rails
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -161,8 +189,17 @@ files:
|
|
161
189
|
- README.md
|
162
190
|
- Rakefile
|
163
191
|
- app/assets/javascripts/type_station/application.js
|
164
|
-
- app/assets/javascripts/type_station/
|
192
|
+
- app/assets/javascripts/type_station/editables/admin_bar.js.coffee
|
193
|
+
- app/assets/javascripts/type_station/editables/file.js.coffee
|
194
|
+
- app/assets/javascripts/type_station/editables/image.js.coffee
|
195
|
+
- app/assets/javascripts/type_station/editables/new_model.js.coffee
|
196
|
+
- app/assets/javascripts/type_station/editables/text_html.js.coffee
|
197
|
+
- app/assets/javascripts/type_station/init.js.coffee
|
198
|
+
- app/assets/javascripts/type_station/lib/models.js.coffee
|
199
|
+
- app/assets/javascripts/type_station/lib/ts.js.coffee
|
200
|
+
- app/assets/stylesheets/type_station/admin_bar.css.scss
|
165
201
|
- app/assets/stylesheets/type_station/application.css
|
202
|
+
- app/assets/stylesheets/type_station/base.css.scss
|
166
203
|
- app/controllers/type_station/admin/pages_controller.rb
|
167
204
|
- app/controllers/type_station/admin_controller.rb
|
168
205
|
- app/controllers/type_station/application_controller.rb
|
@@ -174,7 +211,7 @@ files:
|
|
174
211
|
- app/presenters/type_station/content_presenter.rb
|
175
212
|
- app/presenters/type_station/page_presenter.rb
|
176
213
|
- app/views/layouts/type_station/application.html.erb
|
177
|
-
- app/views/type_station/toolbars/
|
214
|
+
- app/views/type_station/toolbars/_admin_bar.html.haml
|
178
215
|
- config/routes.rb
|
179
216
|
- lib/tasks/type_station_tasks.rake
|
180
217
|
- lib/type_station.rb
|
@@ -199,9 +236,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
199
236
|
version: '0'
|
200
237
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
238
|
requirements:
|
202
|
-
- - '
|
239
|
+
- - '>='
|
203
240
|
- !ruby/object:Gem::Version
|
204
|
-
version:
|
241
|
+
version: '0'
|
205
242
|
requirements: []
|
206
243
|
rubyforge_project:
|
207
244
|
rubygems_version: 2.2.2
|
@@ -1,54 +0,0 @@
|
|
1
|
-
jQuery ->
|
2
|
-
|
3
|
-
elements = document.querySelectorAll('.ts-editable-text')
|
4
|
-
window.t = editor = new MediumEditor elements,
|
5
|
-
disableReturn: true
|
6
|
-
buttons: ['bold', 'italic', 'underline', 'anchor']
|
7
|
-
|
8
|
-
|
9
|
-
elements = document.querySelectorAll('.ts-editable-html')
|
10
|
-
window.t = editor = new MediumEditor elements,
|
11
|
-
buttons: ['bold', 'italic', 'underline', 'anchor', 'header1', 'header2', 'unorderedlist', 'orderedlist', 'justifyLeft', 'justifyFull', 'justifyCenter', 'justifyRight']
|
12
|
-
|
13
|
-
$('.ts-editable-text').on 'input', ->
|
14
|
-
console.log this
|
15
|
-
|
16
|
-
# textParserRules =
|
17
|
-
# tags:
|
18
|
-
# strong: {}
|
19
|
-
# b: {}
|
20
|
-
# i: {}
|
21
|
-
# em: {}
|
22
|
-
# br: {}
|
23
|
-
# p:
|
24
|
-
# unwrap: 1
|
25
|
-
# div:
|
26
|
-
# unwrap: 1
|
27
|
-
# span:
|
28
|
-
# unwrap: 1
|
29
|
-
# ul:
|
30
|
-
# unwrap: 1
|
31
|
-
# ol:
|
32
|
-
# unwrap: 1
|
33
|
-
# li:
|
34
|
-
# unwrap: 1
|
35
|
-
# a:
|
36
|
-
# check_attributes:
|
37
|
-
# href: "url" # important to avoid XSS
|
38
|
-
|
39
|
-
# $('.ts-editable-text').each (i)->
|
40
|
-
# $this = $(@)
|
41
|
-
# data = $this.data()
|
42
|
-
# offset = $this.offset()
|
43
|
-
# console.log data
|
44
|
-
# #Set up ID
|
45
|
-
# toolbarId = "#{data.tsId}-#{i}-toolbar"
|
46
|
-
# $($('#ts-editable-text-toolbar').html())
|
47
|
-
# .attr('id', toolbarId)
|
48
|
-
# .css({ position: 'absolute', top: (offset.top - 20), left: offset.left})
|
49
|
-
# .appendTo('body')
|
50
|
-
|
51
|
-
# window.t = editor = new wysihtml5.Editor @,
|
52
|
-
# toolbar: toolbarId
|
53
|
-
# parserRules: textParserRules
|
54
|
-
# contentEditableMode: true
|