qor_layout 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|