qor_layout 0.0.1
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.
- data/.gitignore +4 -0
- data/Gemfile +9 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +29 -0
- data/Rakefile +1 -0
- data/VERSION +1 -0
- data/app/assets/javascripts/qor/layout.js +117 -0
- data/app/assets/stylesheets/qor/layout.css +3 -0
- data/app/controllers/qor/layout/settings_controller.rb +36 -0
- data/app/helpers/qor/layout/layout_helper.rb +22 -0
- data/app/models/qor/layout/asset.rb +22 -0
- data/app/models/qor/layout/layout.rb +19 -0
- data/app/models/qor/layout/setting.rb +154 -0
- data/app/views/resources/qor_layout/edit.html.erb +27 -0
- data/app/views/resources/qor_layout/index.html.erb +35 -0
- data/config/routes.rb +9 -0
- data/lib/qor/layout/action.rb +11 -0
- data/lib/qor/layout/configuration.rb +145 -0
- data/lib/qor/layout.rb +9 -0
- data/lib/qor/rails.rb +13 -0
- data/lib/qor/tasks.rb +36 -0
- data/lib/qor_layout.rb +1 -0
- data/qor_layout.gemspec +19 -0
- metadata +69 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2010 YOURNAME
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
= Layout
|
|
2
|
+
|
|
3
|
+
Easily to make your own layout.
|
|
4
|
+
|
|
5
|
+
== Architecture
|
|
6
|
+
QLayout::Configuration
|
|
7
|
+
QLayout::Action
|
|
8
|
+
= detect_action(app)
|
|
9
|
+
QLayout::Layout
|
|
10
|
+
name
|
|
11
|
+
action_name
|
|
12
|
+
|
|
13
|
+
- render -> settings.render
|
|
14
|
+
= detect_layout(name, app)
|
|
15
|
+
|
|
16
|
+
QLayout::Setting settings[] { image, text, link }
|
|
17
|
+
name
|
|
18
|
+
parent_id
|
|
19
|
+
layout_id
|
|
20
|
+
value {image: QLayout::Asset(11), text: text, link: google.com}
|
|
21
|
+
|
|
22
|
+
- children
|
|
23
|
+
- render
|
|
24
|
+
|
|
25
|
+
QLayout::Asset
|
|
26
|
+
data
|
|
27
|
+
|
|
28
|
+
== Author
|
|
29
|
+
Jinzhu - wosmvp@gmail.com
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.1
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
var qLayout = (function() {
|
|
2
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
3
|
+
// Drag Events
|
|
4
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
function handleDragStart(e) {
|
|
6
|
+
e.dataTransfer.start_position = {x: e.pageX, y: e.pageY};
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function handleDragOver(e) {
|
|
10
|
+
if (e.preventDefault) { e.preventDefault(); }
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function handleDragEnter(e) {
|
|
15
|
+
doHoverAction(e);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function handleDragLeave(e) {
|
|
19
|
+
doNormalAction(e);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function handleDrop(e) {
|
|
23
|
+
if (e.stopPropagation) { e.stopPropagation(); } // stops the browser from redirecting.
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function handleDragEnd(e) {
|
|
28
|
+
var start_position = e.dataTransfer.start_position;
|
|
29
|
+
this.style.left = parseInt(this.style.left) + (e.pageX - start_position.x) + 'px'
|
|
30
|
+
this.style.top = parseInt(this.style.top) + (e.pageY - start_position.y) + 'px';
|
|
31
|
+
|
|
32
|
+
var setting_id = this.getAttribute('qor_layout_elements')
|
|
33
|
+
var data = {setting : {style_attributes : {left: this.style.left, top: this.style.top}}}
|
|
34
|
+
|
|
35
|
+
$.ajax({
|
|
36
|
+
type: "PUT",
|
|
37
|
+
url: "/qor/layout/settings/" + setting_id,
|
|
38
|
+
data: data,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
43
|
+
// Element Actions
|
|
44
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
45
|
+
function doAction(e, action) {
|
|
46
|
+
var elem = (e instanceof HTMLElement) ? e : e.target;
|
|
47
|
+
elem.setAttribute("data-qlayout-action", action);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function doHoverAction(e) {
|
|
51
|
+
doAction(e, 'hover');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function doMoveAction(e) {
|
|
55
|
+
doAction(e, 'move');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function doNormalAction(e) {
|
|
59
|
+
doAction(e, 'normal');
|
|
60
|
+
}
|
|
61
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
62
|
+
|
|
63
|
+
function registerAsDarggable(dom, root) {
|
|
64
|
+
dom.setAttribute('draggable', true);
|
|
65
|
+
|
|
66
|
+
dom.addEventListener('mouseover', doHoverAction, false);
|
|
67
|
+
dom.addEventListener('mouseout', doNormalAction, false);
|
|
68
|
+
|
|
69
|
+
dom.addEventListener('dragstart', handleDragStart, false);
|
|
70
|
+
dom.addEventListener('dragenter', handleDragEnter, false);
|
|
71
|
+
dom.addEventListener('dragover', handleDragOver, false);
|
|
72
|
+
dom.addEventListener('dragleave', handleDragLeave, false);
|
|
73
|
+
dom.addEventListener('drop', handleDrop, false);
|
|
74
|
+
dom.addEventListener('dragend', handleDragEnd, false);
|
|
75
|
+
|
|
76
|
+
var layout_parents = $(dom).parents('[qor_layout_elements]');
|
|
77
|
+
var parent = layout_parents.length > 0 ? layout_parents[0] : root;
|
|
78
|
+
|
|
79
|
+
var old_position = dom.getBoundingClientRect();
|
|
80
|
+
var parent_position = parent.getBoundingClientRect();
|
|
81
|
+
dom.style.left = (old_position.left - parent_position.left) + "px";
|
|
82
|
+
dom.style.top = (old_position.top - parent_position.top) + "px";
|
|
83
|
+
dom.style.float = 'none';
|
|
84
|
+
dom.style.position = 'absolute';
|
|
85
|
+
|
|
86
|
+
dom.setAttribute("data-qlayout-element", true);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function init(root) {
|
|
90
|
+
function refresh() {
|
|
91
|
+
var children = root.querySelectorAll('[qor_layout_draggable_elements]');
|
|
92
|
+
for (var i=0; i < children.length; i++) {
|
|
93
|
+
registerAsDarggable(children[i], root);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function add(elem) {
|
|
98
|
+
registerAsDarggable(elem, root);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function html(value) {
|
|
102
|
+
if (value) { root.innerHTML = value; refresh(); }
|
|
103
|
+
return root.innerHTML;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
refresh();
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
add : add,
|
|
110
|
+
html : html
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
init : init
|
|
116
|
+
}
|
|
117
|
+
})();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Qor
|
|
2
|
+
module Layout
|
|
3
|
+
class SettingsController < ApplicationController
|
|
4
|
+
layout false
|
|
5
|
+
|
|
6
|
+
def toggle
|
|
7
|
+
inline_editing_qor_layout? ? disable_editing_qor_layout : enable_editing_qor_layout
|
|
8
|
+
redirect_to params[:back] || :back
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def update
|
|
12
|
+
@resource = Qor::Layout::Setting.find_by_id(params[:id])
|
|
13
|
+
@resource.update_attributes(params[:setting])
|
|
14
|
+
|
|
15
|
+
if request.xhr?
|
|
16
|
+
render :text => 'ok'
|
|
17
|
+
else
|
|
18
|
+
redirect_to params[:back] || :back
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
def inline_editing_qor_layout?
|
|
24
|
+
session[:layout_editing]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def disable_editing_qor_layout
|
|
28
|
+
session.delete(:layout_editing)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def enable_editing_qor_layout
|
|
32
|
+
session[:layout_editing] = 1
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Qor
|
|
2
|
+
module Layout
|
|
3
|
+
module LayoutHelper
|
|
4
|
+
def render_layout(name)
|
|
5
|
+
html = Qor::Layout::Layout.detect_layout(name, self).try(:render, session[:layout_editing]).to_s
|
|
6
|
+
|
|
7
|
+
if session[:layout_editing]
|
|
8
|
+
html += <<-STRING
|
|
9
|
+
<script class='qor_layout_script'>
|
|
10
|
+
$(document).ready(function() {
|
|
11
|
+
qlayout = qLayout.init($('script.qor_layout_script').parent()[0]);
|
|
12
|
+
});
|
|
13
|
+
</script>
|
|
14
|
+
STRING
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
html.html_safe
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Qor
|
|
2
|
+
module Layout
|
|
3
|
+
class Asset < ::ActiveRecord::Base
|
|
4
|
+
self.table_name = 'qor_layout_assets'
|
|
5
|
+
has_drafts(:shadow_id => false) if respond_to?(:has_drafts)
|
|
6
|
+
|
|
7
|
+
paperclip_config = Qor::Layout.paperclip_config || {
|
|
8
|
+
:image_path => ":rails_root/public/system/qor_layout_assets/:id/:style.:extension",
|
|
9
|
+
:image_url => "/system/qor_layout_assets/:id/:style.:extension",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
has_attached_file :data, {:path => paperclip_config[:image_path], :url => paperclip_config[:image_url]}.merge(paperclip_config)
|
|
13
|
+
|
|
14
|
+
def method_missing(method_sym, *args, &block)
|
|
15
|
+
if data.respond_to?(method_sym)
|
|
16
|
+
return data.send(method_sym, *args)
|
|
17
|
+
end
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Qor
|
|
2
|
+
module Layout
|
|
3
|
+
class Layout < ::ActiveRecord::Base
|
|
4
|
+
self.table_name = 'qor_layout_layouts'
|
|
5
|
+
|
|
6
|
+
has_many :settings, :class_name => "Qor::Layout::Setting"
|
|
7
|
+
|
|
8
|
+
def self.detect_layout(name, app=nil)
|
|
9
|
+
scope = where(:name => name)
|
|
10
|
+
action = Qor::Layout::Action.detect_action(app)
|
|
11
|
+
scope.where(:action_name => action.try(:name)).first || scope.first
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render(edit_mode=false)
|
|
15
|
+
settings.map {|setting| setting.render(edit_mode) }.join("")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
module Qor
|
|
2
|
+
module Layout
|
|
3
|
+
class Setting < ::ActiveRecord::Base
|
|
4
|
+
self.table_name = 'qor_layout_settings'
|
|
5
|
+
attr_accessor :destroy_value_attributes
|
|
6
|
+
|
|
7
|
+
has_drafts :custom_associations => :related_records if respond_to?(:has_drafts)
|
|
8
|
+
|
|
9
|
+
serialize :value
|
|
10
|
+
serialize :style
|
|
11
|
+
|
|
12
|
+
default_values :value => {}, :style => {:top => '1px', :left => '1px'}
|
|
13
|
+
|
|
14
|
+
belongs_to :layout, :class_name => "Qor::Layout::Layout"
|
|
15
|
+
belongs_to :parent, :class_name => "Qor::Layout::Setting"
|
|
16
|
+
has_many :children,:class_name => "Qor::Layout::Setting", :foreign_key => :parent_id
|
|
17
|
+
accepts_nested_attributes_for :children, :allow_destroy => true
|
|
18
|
+
|
|
19
|
+
before_save :assign_serialized_attributes
|
|
20
|
+
def assign_serialized_attributes
|
|
21
|
+
self.value = @value_attributes unless @value_attributes.nil?
|
|
22
|
+
self.style = @style_attributes unless @style_attributes.nil?
|
|
23
|
+
|
|
24
|
+
new_value = self.value
|
|
25
|
+
(self.destroy_value_attributes || {}).map do |key, value|
|
|
26
|
+
new_value = new_value.reject {|k,v| k.to_s == key.to_s } if value == "1"
|
|
27
|
+
end
|
|
28
|
+
self.value = new_value
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def values(name, for_setting=false)
|
|
32
|
+
stored_value = (value || {}).with_indifferent_access[name]
|
|
33
|
+
gadget_setting = gadget_settings[name]
|
|
34
|
+
|
|
35
|
+
if stored_value =~ /^([\w:]+)\((\d+)\)$/
|
|
36
|
+
return ($1.constantize.find_by_id($2) rescue stored_value)
|
|
37
|
+
elsif gadget_setting && (gadget_setting[:type].to_s == 'gadget')
|
|
38
|
+
gadget_name = gadget_setting[:name] || name
|
|
39
|
+
gadgets = children.where(:name => gadget_name)
|
|
40
|
+
return (for_setting ? gadgets.map(&:settings) : gadgets)
|
|
41
|
+
else
|
|
42
|
+
return stored_value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def meta_settings
|
|
47
|
+
gadget_settings.inject({}) do |s, setting|
|
|
48
|
+
key = setting[0]
|
|
49
|
+
value = values(key, true)
|
|
50
|
+
s.merge({key => value})
|
|
51
|
+
end.with_indifferent_access
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def related_records
|
|
55
|
+
settings.respond_to?(:values) ? settings.values.select {|x| x.is_a? ActiveRecord::Base } : []
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def value_attributes=(attrs)
|
|
59
|
+
attrs = attrs.with_indifferent_access
|
|
60
|
+
value_attrs = {}
|
|
61
|
+
gadget_settings.map do |key, value|
|
|
62
|
+
if value[:type].to_s =~ /image|file|media/
|
|
63
|
+
if self.value && (self.value[key] =~ /^([\w:]+)\((\d+)\)$/)
|
|
64
|
+
asset = $1.constantize.find_by_id($2).update_attribute(:data, attrs[key]) if attrs[key]
|
|
65
|
+
value_attrs.update({key => self.value[key]})
|
|
66
|
+
elsif attrs[key]
|
|
67
|
+
asset = Qor::Layout::Asset.create(:data => attrs[key])
|
|
68
|
+
value_attrs.update({key => "Qor::Layout::Asset(#{asset.id})"})
|
|
69
|
+
end
|
|
70
|
+
elsif attrs[key]
|
|
71
|
+
value_attrs.update({key => attrs[key]})
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
old_value = (self.value || {}).symbolize_keys
|
|
75
|
+
@value_attributes = old_value.merge(value_attrs.symbolize_keys)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def style_attributes=(attrs)
|
|
79
|
+
old_style = self.style.symbolize_keys
|
|
80
|
+
new_style = old_style.merge(attrs.symbolize_keys || {})
|
|
81
|
+
@style_attributes = new_style
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def children_attributes=(attrs)
|
|
85
|
+
attrs.map do |key, atts|
|
|
86
|
+
child = children.find_by_id(atts.delete("id"))
|
|
87
|
+
if atts.delete("_destroy").to_s == "1"
|
|
88
|
+
child.try(:destroy)
|
|
89
|
+
elsif child
|
|
90
|
+
child.update_attributes(atts)
|
|
91
|
+
else
|
|
92
|
+
child_attrs = atts['value_attributes']
|
|
93
|
+
children.new(atts) if child_attrs.keys.any? {|k| child_attrs[k].present? }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def settings
|
|
99
|
+
if gadget.try(:context_blk)
|
|
100
|
+
self.instance_eval &gadget.try(:context_blk)
|
|
101
|
+
else
|
|
102
|
+
meta_settings
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def resource_attributes_for_settings
|
|
107
|
+
attrs = []
|
|
108
|
+
(gadget.try(:settings) || {}).map do |key, value|
|
|
109
|
+
attr_show = !value[:hidden]
|
|
110
|
+
attrs << Qor::ResourceAttribute.new("value_attributes[#{key}]", gadget_settings[key]) if attr_show
|
|
111
|
+
end
|
|
112
|
+
attrs
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def render_without_style
|
|
116
|
+
::Mustache.render(gadget.try(:template).to_s, settings)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def render(edit_mode=false)
|
|
120
|
+
parse_content = Nokogiri::HTML::DocumentFragment.parse(render_without_style)
|
|
121
|
+
old_style_css = parse_content.xpath('*').first.attribute("style").to_s
|
|
122
|
+
old_style = old_style_css.split(";").inject({}) {|s, v| s.merge(Hash[*v.split(":").map(&:strip)]) }
|
|
123
|
+
new_style = old_style.merge(style)
|
|
124
|
+
style_css = new_style.map {|k,v| "#{k}: #{v}"}.join("; ")
|
|
125
|
+
|
|
126
|
+
parse_content.xpath('*').first.set_attribute("qor_layout_elements", id.to_s)
|
|
127
|
+
parse_content.xpath('*').first.set_attribute("qor_layout_draggable_elements", id.to_s) if gadget.respond_to?(:floating) && gadget.floating
|
|
128
|
+
parse_content.xpath('*').first.set_attribute("style", style_css)
|
|
129
|
+
extra = edit_mode ? "<div for_qor_layout_elements='#{id}'><a href='/admin/layout_settings/#{id}/edit'><img src='/qor_widget/images/settings.png'/></a></div>" : ""
|
|
130
|
+
|
|
131
|
+
parse_content.to_xhtml + extra
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def gadget
|
|
135
|
+
Qor::Layout::Configuration.gadgets.with_indifferent_access[name]
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def gadget_settings
|
|
139
|
+
(gadget.try(:settings) || {}).with_indifferent_access
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def gadget_children_settings
|
|
143
|
+
gadget_settings.select {|k,v| v[:type].to_s == 'gadget'}
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def method_missing(method_sym, *args, &block)
|
|
147
|
+
if method_sym.to_s =~ /^value_attributes\[(\w+)\]$/
|
|
148
|
+
return self.values($1)
|
|
149
|
+
end
|
|
150
|
+
super
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<% is_partent_url = (request.referer.to_s =~ Regexp.new([request.host_with_port, request.path.gsub(/^(\/\w+).*?$/) { $1 }].join(""))) %>
|
|
2
|
+
<% url = resource_path(@resource, :redirect_to => is_partent_url ? request.path : request.referer) -%>
|
|
3
|
+
<%= semantic_form_for(@resource, :url => url, :html => {:multipart => true}) do |f| %>
|
|
4
|
+
<div class="mainTitle">
|
|
5
|
+
<%= render_with_fallback_themes "page_header", :page_title_tkey => "cms_admin.Editing %s" % @resource_title_name %>
|
|
6
|
+
<% if has_permission(:update) %>
|
|
7
|
+
<div class="formSubmit sticky">
|
|
8
|
+
<%= render_with_fallback_themes "save_button", :submit_text => rt("Update") %>
|
|
9
|
+
</div>
|
|
10
|
+
<%= render_with_fallback_themes "publish_hint" %>
|
|
11
|
+
<script type="text/javascript" charset="utf-8">
|
|
12
|
+
$('.sticky').make_sticky();
|
|
13
|
+
</script>
|
|
14
|
+
<% end %>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<%= render_with_fallback_themes "all_error_messages" %>
|
|
18
|
+
<%= render_with_fallback_themes "form", :form => f, :attributes => @resource.resource_attributes_for_settings %>
|
|
19
|
+
|
|
20
|
+
<%= render_with_fallback_themes "after_form", :form => f %>
|
|
21
|
+
|
|
22
|
+
<% if has_permission(:update) %>
|
|
23
|
+
<div class="bottom-buttons clearfix">
|
|
24
|
+
<%= render_with_fallback_themes "save_button", :submit_text => rt("Update") %>
|
|
25
|
+
</div>
|
|
26
|
+
<% end %>
|
|
27
|
+
<% end %>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<%= render_with_fallback_themes "screen_option" if @screen_option_key %>
|
|
2
|
+
<div class="clear"></div>
|
|
3
|
+
<div class="mainTitle">
|
|
4
|
+
<%= render_with_fallback_themes "page_header" %>
|
|
5
|
+
|
|
6
|
+
<%= render_with_fallback_themes "filters" %>
|
|
7
|
+
<%= render_with_fallback_themes "search" if @resource_config.attributes(:search).size > 0 %>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<%= render_with_fallback_themes "above_table" %>
|
|
11
|
+
|
|
12
|
+
<div class="mainContent">
|
|
13
|
+
<%= semantic_form_for(@resource_class.new, :url => bulk_resources_path(@resource_name, request_query_hash), :html => {:method => :put, :multipart => true}) do |f| %>
|
|
14
|
+
|
|
15
|
+
<%= render_with_fallback_themes "operations", :f => f %>
|
|
16
|
+
|
|
17
|
+
<% attrs = index_list_attributes %>
|
|
18
|
+
<% if attrs.size > 0 %>
|
|
19
|
+
<div class="mainTable <%= @resource_class.model_name.collection %>_table">
|
|
20
|
+
<%= render_with_fallback_themes "pagination", :style => "tableHead" %>
|
|
21
|
+
<%= render_with_fallback_themes "table", :attrs => attrs %>
|
|
22
|
+
<%= render_with_fallback_themes "pagination", :style => "tableHead tableBottom" %>
|
|
23
|
+
</div>
|
|
24
|
+
<% end %>
|
|
25
|
+
|
|
26
|
+
<% end %>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<% if resource_sortable? %>
|
|
30
|
+
<script type="text/javascript">
|
|
31
|
+
$(function(){
|
|
32
|
+
$(".tableList tbody").make_table_sortable('<%= resources_path %>/update_positions');
|
|
33
|
+
})
|
|
34
|
+
</script>
|
|
35
|
+
<% end %>
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
module Qor
|
|
2
|
+
module Layout
|
|
3
|
+
module Configuration
|
|
4
|
+
class Inputs
|
|
5
|
+
include Qor::Extlib::Dsl::Configuration::InputMeta
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class RawData
|
|
9
|
+
include Qor::Extlib::Dsl::Configuration::RawData
|
|
10
|
+
attr_accessor :description, :description_blk, :meta_inputs, :template_blk, :context_blk, :detect_blk
|
|
11
|
+
|
|
12
|
+
def layout(name, options = {}, &blk)
|
|
13
|
+
Qor::Layout::Configuration::Layout.new(blk, self.owner, options.merge(:name => name))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def gadget(name, options = {}, &blk)
|
|
17
|
+
Qor::Layout::Configuration::Gadget.new(blk, self.owner, options.merge(:name => name))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def action(name, options = {}, &blk)
|
|
21
|
+
::Qor::Layout::Configuration::Action.new(blk, self.owner, options.merge(:name => name))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def gadgets(name, options = {}, &blk)
|
|
25
|
+
# TODO define gadgets for layout
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def settings(&blk)
|
|
29
|
+
self.meta_inputs = Inputs.new
|
|
30
|
+
self.meta_inputs.instance_eval(&blk)
|
|
31
|
+
self.meta_inputs
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def context(&blk)
|
|
35
|
+
self.context_blk = blk
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def template(&blk)
|
|
39
|
+
self.template_blk = blk
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def detect(&blk)
|
|
43
|
+
self.detect_blk = blk
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def desc(description = nil, &blk)
|
|
47
|
+
raise 'desc must be string or blcok' unless description.is_a?(String) || blk
|
|
48
|
+
self.description = description
|
|
49
|
+
self.description_blk = blk
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class Base
|
|
54
|
+
include Qor::Extlib::Dsl::Configuration::Base
|
|
55
|
+
attr_accessor :name, :floating
|
|
56
|
+
|
|
57
|
+
self.raw_data_klazz = ::Qor::Layout::Configuration::RawData
|
|
58
|
+
def initialize(*arguments)
|
|
59
|
+
super
|
|
60
|
+
|
|
61
|
+
root = arguments[1]
|
|
62
|
+
|
|
63
|
+
if root
|
|
64
|
+
root.group_children ||= {}
|
|
65
|
+
root.group_children[self.class.to_s] ||= {}
|
|
66
|
+
root.group_children[self.class.to_s][self.name.to_s] = self
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def child_key
|
|
71
|
+
File.join(self.class.to_s, self.name.to_s)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def description
|
|
75
|
+
self.raw_data.description || self.raw_data.description_blk.try(:call)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
class Root < Base
|
|
80
|
+
attr_accessor :group_children
|
|
81
|
+
|
|
82
|
+
def layouts(name=nil)
|
|
83
|
+
children = group_children[Layout.to_s]
|
|
84
|
+
children = children[name] if name.present?
|
|
85
|
+
children
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def gadgets(name=nil)
|
|
89
|
+
children = group_children[Gadget.to_s]
|
|
90
|
+
children = children[name] if name.present?
|
|
91
|
+
children
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def gadget_by_name(name)
|
|
95
|
+
Qor::Layout::Configuration.gadgets.with_indifferent_access[name]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def gadget_settings_by_name(name)
|
|
99
|
+
(gadget_by_name(name).try(:settings) || {}).with_indifferent_access
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def actions(name=nil)
|
|
103
|
+
children = group_children[Action.to_s]
|
|
104
|
+
children = children[name] if name.present?
|
|
105
|
+
children
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
class Layout < Base
|
|
110
|
+
end
|
|
111
|
+
class Gadget < Base
|
|
112
|
+
def settings
|
|
113
|
+
self.raw_data.meta_inputs.meta_hash.inject({}) do |s, v|
|
|
114
|
+
s.update({v[0] => {:label => (v[1].with_indifferent_access[:name] || v[0]).to_s}.merge(v[1])})
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def context_blk
|
|
119
|
+
self.raw_data.context_blk
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def template
|
|
123
|
+
self.raw_data.template_blk.call
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
class Action < Base
|
|
127
|
+
def detect_blk
|
|
128
|
+
self.raw_data.detect_blk
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
class << self
|
|
133
|
+
def load(path="config/layout.rb")
|
|
134
|
+
@root = Qor::Extlib::Dsl::Configuration.load(::Qor::Layout::Configuration::Root, path)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def root
|
|
138
|
+
@root ||= load
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
delegate :layouts, :gadgets, :actions, :gadget_by_name, :gadget_settings_by_name, :to => :root
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
data/lib/qor/layout.rb
ADDED
data/lib/qor/rails.rb
ADDED
data/lib/qor/tasks.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
namespace :qor do
|
|
2
|
+
namespace :layout do
|
|
3
|
+
desc "add columns to tables"
|
|
4
|
+
task :migrate => :environment do
|
|
5
|
+
ActiveRecord::Migration.upgrade_table Qor::Layout::Layout.table_name do |t|
|
|
6
|
+
t.string :name
|
|
7
|
+
t.string :action_name
|
|
8
|
+
|
|
9
|
+
t.datetime :deleted_at
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
ActiveRecord::Migration.upgrade_table Qor::Layout::Setting.table_name do |t|
|
|
14
|
+
t.string :name
|
|
15
|
+
t.integer :parent_id
|
|
16
|
+
t.integer :layout_id
|
|
17
|
+
t.text :value, :limit => 2147483647
|
|
18
|
+
t.text :style, :limit => 2147483647
|
|
19
|
+
|
|
20
|
+
t.datetime :deleted_at
|
|
21
|
+
t.timestamps
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
ActiveRecord::Migration.upgrade_table Qor::Layout::Asset.table_name do |t|
|
|
25
|
+
t.string :data_file_name
|
|
26
|
+
t.string :data_content_type
|
|
27
|
+
t.string :data_file_size
|
|
28
|
+
t.string :data_updated_at
|
|
29
|
+
t.string :data_coordinates, :limit => 1024
|
|
30
|
+
|
|
31
|
+
t.datetime :deleted_at
|
|
32
|
+
t.timestamps
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/qor_layout.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
['qor/layout', 'qor/rails'].map {|x| require File.join(File.dirname(__FILE__), x)}
|
data/qor_layout.gemspec
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = "qor_layout"
|
|
6
|
+
s.version = File.read('VERSION')
|
|
7
|
+
s.authors = ["Jinzhu"]
|
|
8
|
+
s.email = ["wosmvp@gmail.com"]
|
|
9
|
+
s.homepage = ""
|
|
10
|
+
s.summary = %q{Easily to make your own layout}
|
|
11
|
+
s.description = %q{Easily to make your own layout}
|
|
12
|
+
|
|
13
|
+
s.rubyforge_project = "qor_layout"
|
|
14
|
+
|
|
15
|
+
s.files = `git ls-files`.split("\n")
|
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
18
|
+
s.require_paths = ["lib"]
|
|
19
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: qor_layout
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Jinzhu
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-09-13 00:00:00.000000000 Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: Easily to make your own layout
|
|
15
|
+
email:
|
|
16
|
+
- wosmvp@gmail.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- .gitignore
|
|
22
|
+
- Gemfile
|
|
23
|
+
- MIT-LICENSE
|
|
24
|
+
- README.rdoc
|
|
25
|
+
- Rakefile
|
|
26
|
+
- VERSION
|
|
27
|
+
- app/assets/javascripts/qor/layout.js
|
|
28
|
+
- app/assets/stylesheets/qor/layout.css
|
|
29
|
+
- app/controllers/qor/layout/settings_controller.rb
|
|
30
|
+
- app/helpers/qor/layout/layout_helper.rb
|
|
31
|
+
- app/models/qor/layout/asset.rb
|
|
32
|
+
- app/models/qor/layout/layout.rb
|
|
33
|
+
- app/models/qor/layout/setting.rb
|
|
34
|
+
- app/views/resources/qor_layout/edit.html.erb
|
|
35
|
+
- app/views/resources/qor_layout/index.html.erb
|
|
36
|
+
- config/routes.rb
|
|
37
|
+
- lib/qor/layout.rb
|
|
38
|
+
- lib/qor/layout/action.rb
|
|
39
|
+
- lib/qor/layout/configuration.rb
|
|
40
|
+
- lib/qor/rails.rb
|
|
41
|
+
- lib/qor/tasks.rb
|
|
42
|
+
- lib/qor_layout.rb
|
|
43
|
+
- qor_layout.gemspec
|
|
44
|
+
homepage: ''
|
|
45
|
+
licenses: []
|
|
46
|
+
post_install_message:
|
|
47
|
+
rdoc_options: []
|
|
48
|
+
require_paths:
|
|
49
|
+
- lib
|
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
|
+
none: false
|
|
52
|
+
requirements:
|
|
53
|
+
- - ! '>='
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0'
|
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
requirements: []
|
|
63
|
+
rubyforge_project: qor_layout
|
|
64
|
+
rubygems_version: 1.8.24
|
|
65
|
+
signing_key:
|
|
66
|
+
specification_version: 3
|
|
67
|
+
summary: Easily to make your own layout
|
|
68
|
+
test_files: []
|
|
69
|
+
has_rdoc:
|