polishing the current site editing screen (wip)

This commit is contained in:
did 2011-11-29 02:24:02 +01:00
parent aebb4f74ec
commit 35012ca2b2
25 changed files with 392 additions and 61 deletions

View File

@ -7,9 +7,14 @@ class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.Form
el: '#content' el: '#content'
events:
'click .memberships a.remove': 'remove_membership'
initialize: -> initialize: ->
@model = new Locomotive.Models.CurrentSite(@options.site) @model = new Locomotive.Models.CurrentSite(@options.site)
Backbone.ModelBinding.bind @
window.foo = @model window.foo = @model
render: -> render: ->
@ -19,6 +24,8 @@ class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.Form
@enable_liquid_editing() @enable_liquid_editing()
@enable_ui_effects()
render_domain_entries: -> render_domain_entries: ->
@domains_view = new Locomotive.Views.Site.DomainsView model: @model, errors: @options.errors @domains_view = new Locomotive.Views.Site.DomainsView model: @model, errors: @options.errors
@ -35,5 +42,12 @@ class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.Form
theme: 'default' theme: 'default'
onChange: (editor) => @model.set(robots_txt: editor.getValue()) onChange: (editor) => @model.set(robots_txt: editor.getValue())
enable_ui_effects: ->
@$('#site_domains_input .domain input[type=text]').editableField()
@$('.memberships .entry .role select').editableField()
remove_membership: (event) ->
event.stopPropagation() & event.preventDefault()
entry = $(event.target).parents('.entry').hide()
entry.find('input[type=hidden]').val(1)

View File

@ -21,5 +21,6 @@ class Locomotive.Views.Site.DomainEntryView extends Backbone.View
remove: (event) -> remove: (event) ->
event.stopPropagation() & event.preventDefault() event.stopPropagation() & event.preventDefault()
@$('input[type=text]').editableField('destroy')
@options.parent_view.remove_entry(@model) @options.parent_view.remove_entry(@model)
super() super()

View File

@ -10,6 +10,7 @@ class Locomotive.Views.Site.DomainsView extends Backbone.View
events: events:
'click .new-entry a.add': 'add_entry' 'click .new-entry a.add': 'add_entry'
'keypress .new-entry input[type=text]': 'add_on_entry_from_enter'
render: -> render: ->
$(@el).html(ich.domains_list(@model.toJSON())) $(@el).html(ich.domains_list(@model.toJSON()))
@ -30,21 +31,32 @@ class Locomotive.Views.Site.DomainsView extends Backbone.View
@_insert_entry(domain) @_insert_entry(domain)
@$('ul li.domain:last input[type=text]').editableField()
@$('.empty').hide()
input.val('') # reset for further entries input.val('') # reset for further entries
add_on_entry_from_enter: (event) ->
return if event.keyCode != 13
@add_entry(event)
change_entry: (domain, value) -> change_entry: (domain, value) ->
domain.set name: value domain.set name: value
remove_entry: (domain) -> remove_entry: (domain) ->
list = _.reject @model.get('domains'), (_domain) => _domain == domain list = _.reject @model.get('domains'), (_domain) => _domain == domain
@model.set domains: list @model.set domains: list
@$('.empty').show() if @model.get('domains').length == 0
render_entries: -> render_entries: ->
_.each @model.get('domains'), (domain) => if @model.get('domains').length == 0
_.each @options.errors.domain || [], (message) => @$('.empty').show()
domain.error = message if message.test /^#{domain.get('name')} / else
_.each @model.get('domains'), (domain) =>
_.each @options.errors.domain || [], (message) =>
domain.error = message if message.test /^#{domain.get('name')} /
@_insert_entry(domain) @_insert_entry(domain)
_insert_entry: (domain) -> _insert_entry: (domain) ->
view = new Locomotive.Views.Site.DomainEntryView model: domain, parent_view: @ view = new Locomotive.Views.Site.DomainEntryView model: domain, parent_view: @
@ -55,3 +67,5 @@ class Locomotive.Views.Site.DomainsView extends Backbone.View

View File

@ -75,6 +75,7 @@
color: #8b8d9a; color: #8b8d9a;
text-decoration: none; text-decoration: none;
@include text-shadow(rgba(255, 255, 255, 0.8) 0px 1px 0px);
font-size: 11px; font-size: 11px;
margin-left: 10px; margin-left: 10px;

View File

@ -26,4 +26,32 @@
border: 1px solid #b5b7c4; border: 1px solid #b5b7c4;
@include background-image(linear-gradient(top, #f0f0f0, #f9f9f9 25%, #f9f9f9 25%, #ffffff 50%, #ffffff)); @include background-image(linear-gradient(top, #f0f0f0, #f9f9f9 25%, #f9f9f9 25%, #ffffff 50%, #ffffff));
} }
@mixin path-input-style {
background: transparent;
outline: none;
margin: 0 5px;
width: 30%;
border: none;
border-bottom: 1px solid #B5B7C4;
color: #787A89;
font-size: 14px;
}
@mixin editable {
padding: 2px 25px 2px 6px;
color: #1e1f26;
outline: none;
cursor: pointer;
&:hover {
text-decoration: none;
background: #fffbe5 image-url("locomotive/form/pen.png") no-repeat right 5px;
border-bottom: 1px dotted #efe4a5;
}
}

View File

@ -3,6 +3,7 @@
@import "compass/css3/images"; @import "compass/css3/images";
@import "compass/css3/text-shadow"; @import "compass/css3/text-shadow";
@import "helpers"; @import "helpers";
@import "buttons";
form.formtastic { form.formtastic {
@ -56,6 +57,93 @@ form.formtastic {
} }
} // .foldable } // .foldable
.list {
.empty {
text-align: left;
}
li, .entry, .new-entry {
position: relative;
margin-bottom: 10px;
height: 30px;
line-height: 30px;
padding: 0 10px;
background: #fff;
@include border-radius(16px);
@include box-shadow(rgba(0, 0, 0, 0.2) 0px 1px 0px 0px);
em {
color: #757575;
font-size: 11px;
font-weight: normal;
}
strong {
color: #17171D;
font-size: 14px;
font-weight: bold;
}
.editable {
@include editable;
padding-right: 6px;
&:hover {
background-image: none;
}
}
span.actions {
position: absolute;
top: 0px;
right: 10px;
a.add {
@include gray-button;
padding-left: 10px;
}
a.remove {
display: inline-block;
width: 16px;
height: 16px;
position: relative;
top: 4px;
outline: none;
background: transparent image-url("locomotive/list/icons/trash_off.png") repeat 0 0;
text-indent: -9999px;
&:hover {
background-image: image-url("locomotive/list/icons/trash.png");
}
}
}
&:last-child {
margin-bottom: 0px;
}
} // li
> hr {
margin: 10px 0px;
height: 1px;
line-height: 1px;
border: 0px;
border-top: 1px solid rgba(0, 0, 0, 0.2);
background: transparent;
}
.new-entry {
}
} // div.list
ol { ol {
margin-bottom: 0px; margin-bottom: 0px;
padding: 0px; padding: 0px;
@ -106,6 +194,10 @@ form.formtastic {
} }
} // p.inline-hints } // p.inline-hints
div.list {
margin-left: 160px;
}
div.inline-errors { div.inline-errors {
margin: 2px 0 0 160px; margin: 2px 0 0 160px;
padding: 8px 0 0 0; padding: 8px 0 0 0;
@ -125,12 +217,12 @@ form.formtastic {
} }
} // div.inline-errors } // div.inline-errors
&.string { &.string, &.password {
label { label {
padding-top: 2px; padding-top: 2px;
} }
input[type=text] { input[type=text], input[type=password] {
@include default-input-style; @include default-input-style;
width: 700px; width: 700px;
@ -189,11 +281,89 @@ form.formtastic {
background: transparent image-url("locomotive/icons/asset_add.png") no-repeat left 1px; background: transparent image-url("locomotive/icons/asset_add.png") no-repeat left 1px;
} }
} }
} // li.code }
} // li.code
} &.subdomain {
em {
color: #222;
}
input[type=text] {
@include path-input-style;
}
} // li.subdomain
&.empty {
.list {
em.editable {
font-size: 14px;
color: #17171D;
font-weight: bold;
}
input[type=text].path {
@include path-input-style;
}
}
} // li.empty
&.no-label {
padding-top: 6px;
.list {
margin-left: 0;
.entry {
margin-top: 10px;
margin-bottom: 0px;
}
&.memberships {
em.email {
margin-left: 10px;
}
.role {
position: absolute;
top: 0px;
right: 30px;
width: 170px;
line-height: 30px;
em {
padding-left: 17px;
margin-left: 0px;
background-repeat: no-repeat;
color: #757575;
font-size: 13px;
font-weight: normal;
&.locked {
background-image: image-url("locomotive/icons/membership_lock.png");
background-position: 1px 0px;
}
&.editable {
background-image: image-url("locomotive//icons/membership_edit.png");
background-position: 0px 3px;
}
}
}
} // li.no-label .list.memberships
}
} // li.no-label
} // > li } // > li
} //ol } //ol
} // fieldset } // fieldset
} }

View File

@ -115,15 +115,7 @@ body {
color: #1e1f26; color: #1e1f26;
a.editable { a.editable {
padding: 2px 25px 2px 6px; @include editable;
color: #1e1f26;
outline: none;
&:hover {
text-decoration: none;
background: #fffbe5 image-url("locomotive/form/pen.png") no-repeat right 5px;
border-bottom: 1px dotted #efe4a5;
}
} // h2 a.editable } // h2 a.editable
} // > div.inner h2 } // > div.inner h2

View File

@ -17,7 +17,7 @@ module Locomotive
before_filter :set_current_thread_variables before_filter :set_current_thread_variables
helper_method :sections, :current_site_url, :site_url, :public_page_url, :current_ability helper_method :sections, :current_site_public_url, :site_url, :public_page_url, :current_ability
# https://rails.lighthouseapp.com/projects/8994/tickets/1905-apphelpers-within-plugin-not-being-mixed-in # https://rails.lighthouseapp.com/projects/8994/tickets/1905-apphelpers-within-plugin-not-being-mixed-in
helper Locomotive::BaseHelper, Locomotive::ContentTypesHelper #, Locomotive::BoxHelper helper Locomotive::BaseHelper, Locomotive::ContentTypesHelper #, Locomotive::BoxHelper
@ -78,7 +78,7 @@ module Locomotive
# ___ site/page urls builder ___ # ___ site/page urls builder ___
def current_site_url def current_site_public_url
request.protocol + request.host_with_port request.protocol + request.host_with_port
end end
@ -95,9 +95,9 @@ module Locomotive
def public_page_url(page, options = {}) def public_page_url(page, options = {})
if content = options.delete(:content) if content = options.delete(:content)
File.join(current_site_url, page.fullpath.gsub('content_type_template', ''), content._slug) File.join(current_site_public_url, page.fullpath.gsub('content_type_template', ''), content._slug)
else else
File.join(current_site_url, page.fullpath) File.join(current_site_public_url, page.fullpath)
end end
end end

View File

@ -7,6 +7,8 @@ module Locomotive
load_and_authorize_resource :class => 'Site' load_and_authorize_resource :class => 'Site'
before_filter :filter_attributes
respond_to :json, :only => :update respond_to :json, :only => :update
def edit def edit
@ -18,13 +20,16 @@ module Locomotive
@site = current_site @site = current_site
@site.update_attributes(params[:site]) @site.update_attributes(params[:site])
respond_with @site, :location => edit_current_site_url(new_host_if_subdomain_changed) respond_with @site, :location => edit_current_site_url(new_host_if_subdomain_changed)
# respond_with @site do |format|
# format.html { redirect_to edit_current_site_url(new_host_if_subdomain_changed) }
# end
end end
protected protected
def filter_attributes
unless can?(:manage, Locomotive::Membership)
params[:site].delete(:memberships_attributes)
end
end
def new_host_if_subdomain_changed def new_host_if_subdomain_changed
if !Locomotive.config.manage_subdomain? || @site.domains.include?(request.host) if !Locomotive.config.manage_subdomain? || @site.domains.include?(request.host)
{} {}

View File

@ -100,9 +100,9 @@ module Locomotive::BaseHelper
def public_page_url(page, options = {}) def public_page_url(page, options = {})
if content = options.delete(:content) if content = options.delete(:content)
File.join(current_site_url, page.fullpath.gsub('content_type_template', ''), content._slug) File.join(current_site_public_url, page.fullpath.gsub('content_type_template', ''), content._slug)
else else
File.join(current_site_url, page.fullpath) File.join(current_site_public_url, page.fullpath)
end end
end end

View File

@ -2,7 +2,6 @@ module Locomotive
class CodeInput < Formtastic::Inputs::TextInput class CodeInput < Formtastic::Inputs::TextInput
def input_wrapping(&block) def input_wrapping(&block)
Rails.logger.debug hint_html.inspect
template.content_tag(:li, template.content_tag(:li,
[template.capture(&block), error_html, image_picker_html, hint_html].join("\n").html_safe, [template.capture(&block), error_html, image_picker_html, hint_html].join("\n").html_safe,
wrapper_html_options wrapper_html_options
@ -10,9 +9,7 @@ module Locomotive
end end
def hint_text def hint_text
localized_string(method, options[:hint], :hint).tap do |foo| localized_string(method, options[:hint], :hint)
Rails.logger.debug foo.inspect
end
end end
def to_html def to_html

View File

@ -12,6 +12,7 @@ module Locomotive
input_wrapping do input_wrapping do
label_html << label_html <<
template.content_tag(:em, "http://") <<
builder.text_field(method, input_html_options) << builder.text_field(method, input_html_options) <<
template.content_tag(:em, ".#{domain}") template.content_tag(:em, ".#{domain}")
end end

View File

@ -29,7 +29,7 @@ module Locomotive
## behaviours ## ## behaviours ##
enable_subdomain_n_domains_if_multi_sites enable_subdomain_n_domains_if_multi_sites
accepts_nested_attributes_for :memberships accepts_nested_attributes_for :memberships, :allow_destroy => true
## methods ## ## methods ##

View File

@ -1,10 +1,10 @@
module Locomotive module Locomotive
class SitePresenter < BasePresenter class SitePresenter < BasePresenter
delegate :name, :subdomain, :domains, :robots_txt, :seo_title, :meta_keywords, :meta_description, :domains_without_subdomain, :to => :source delegate :name, :subdomain, :domains, :robots_txt, :seo_title, :meta_keywords, :meta_description, :domains_without_subdomain, :memberships, :to => :source
def included_methods def included_methods
super + %w(name subdomain domains robots_txt seo_title meta_keywords meta_description domains_without_subdomain) super + %w(name subdomain domains robots_txt seo_title meta_keywords meta_description domains_without_subdomain memberships)
end end
end end

View File

@ -24,30 +24,32 @@
- if can?(:index, Locomotive::Membership) - if can?(:index, Locomotive::Membership)
= f.inputs :name => :memberships do = f.inputs :name => :memberships do
= f.semantic_fields_for :memberships do |fm| %li{ :class => 'input empty no-label' }
.list.memberships
= f.semantic_fields_for :memberships do |fm|
- membership, account = fm.object, fm.object.account - membership, account = fm.object, fm.object.account
%li.item.membership{ :'data-role' => membership.role } .entry
%strong= account.name = fm.hidden_field :_destroy
%em.email= account.email %strong= account.name
- if can?(:update, membership) %em.email= account.email
.role
%em.editable= t("locomotive.memberships.roles.#{membership.role}") - if can?(:update, membership)
.role
- if can?(:grant_admin, membership)
= fm.select :role, Locomotive::Ability::ROLES.map { |r| [t("locomotive.memberships.roles.#{r}"), r] }, :include_blank => false
- else
= fm.select :role, (Locomotive::Ability::ROLES - ['admin']).map { |r| [t("locomotive.memberships.roles.#{r}"), r] }, :include_blank => false
%span.actions
= link_to 'x', '#', :class => 'remove'
- if can?(:grant_admin, membership)
= fm.select :role, Locomotive::Ability::ROLES.map { |r| [t("locomotive.memberships.roles.#{r}"), r] }, :include_blank => false
- else - else
= fm.select :role, (Locomotive::Ability::ROLES - ['admin']).map { |r| [t("locomotive.memberships.roles.#{r}"), r] }, :include_blank => false .role
%em.locked= t("locomotive.memberships.roles.#{membership.role}")
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), membership_url(membership), :class => 'remove first', :confirm =>t('locomotive.messages.confirm'), :method => :delete
- else
.role
%em.locked= t("locomotive.memberships.roles.#{membership.role}")
- if can?(:manage, current_site) - if can?(:manage, current_site)

View File

@ -12,7 +12,7 @@
%p!= t('.help') %p!= t('.help')
= semantic_form_for @site, :url => current_site_url, :html => { :class => 'save-with-shortcut' } do |form| = semantic_form_for @site, :url => current_site_url do |form|
= render 'form', :f => form = render 'form', :f => form

View File

@ -2,7 +2,7 @@
- content_for :submenu do - content_for :submenu do
= render 'locomotive/shared/menu/contents' = render 'locomotive/shared/menu/contents'
- content_for :actions do - content_for :actions do
= render 'locomotive/shared/actions/contents' = render 'locomotive/shared/actions/contents'
@ -11,7 +11,7 @@
%p!= t('.help') %p!= t('.help')
= semantic_form_for @page, :url => page_url(@page), :html => { :class => 'save-with-shortcut', :multipart => true } do |form| = semantic_form_for @page, :url => page_url(@page), :html => { :multipart => true } do |form|
= render 'form', :f => form = render 'form', :f => form

View File

@ -1,7 +1,7 @@
%h1 %h1
= link_to current_site.name, pages_url = link_to current_site.name, pages_url
= render_cell 'locomotive/global_actions', :show, :current_locomotive_account => current_locomotive_account, :current_site_url => current_site_url = render_cell 'locomotive/global_actions', :show, :current_locomotive_account => current_locomotive_account, :current_site_url => current_site_public_url
- if multi_sites? && current_locomotive_account.sites.size > 1 - if multi_sites? && current_locomotive_account.sites.size > 1
#sites-picker{ :style => 'display: none' } #sites-picker{ :style => 'display: none' }

View File

@ -1,10 +1,14 @@
%script{ :type => 'text/html', :id => 'domains_list' } %script{ :type => 'text/html', :id => 'domains_list' }
%p.empty{ :style => 'display: none' }!= t('.empty')
%ul %ul
%hr
.new-entry .new-entry
%em http:// %em http://
= text_field_tag 'domain', '', :id => '', :placeholder => t('formtastic.hints.site.domain_name') = text_field_tag 'domain', '', :id => '', :placeholder => t('formtastic.hints.site.domain_name'), :class => 'path'
%span.actions %span.actions
= link_to t('locomotive.buttons.new_item'), '#', :class => 'add' = link_to t('locomotive.buttons.new_item'), '#', :class => 'add'
@ -12,7 +16,7 @@
%script{ :type => 'text/html', :id => 'domain_entry' } %script{ :type => 'text/html', :id => 'domain_entry' }
%em http:// %em http://
= text_field_tag 'site[domains][]', '{{name}}', :id => '' = text_field_tag 'site[domains][]', '{{name}}', :id => '', :class => 'path'
{{#if error}} {{#if error}}
%span.inline-errors {{error}} %span.inline-errors {{error}}

View File

@ -0,0 +1,37 @@
- content_for :head do
= include_javascripts :site
= f.foldable_inputs :name => :information, :style => "#{'display: none' unless @site.new_record?}" do
= f.input :name, :required => false
- if manage_subdomain_or_domains?
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
= f.custom_input :subdomain, :css => 'path' do
%em
http://
= f.text_field :subdomain
\.
%em
= application_domain
- if manage_domains?
- @site.domains_without_subdomain.each_with_index do |name, index|
%li{ :class => "item added #{'last' if index == @site.domains.size - 1}" }
%em
http://
= text_field_tag 'site[domains][]', name, :class => 'string label void domain'
&nbsp;
= error_on_domain(@site, name)
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('locomotive.messages.confirm')
%li.item.template
%em
http://
= text_field_tag 'label', t('formtastic.hints.site.domain_name'), :class => 'string label void domain'
&nbsp;
%span.actions
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove first', :confirm => t('locomotive.messages.confirm')
%button{ :class => 'button light add', :type => 'button' }
%span!= t('locomotive.buttons.new_item')

View File

@ -0,0 +1,12 @@
- title t('.title')
- content_for :submenu do
= render_cell 'locomotive/settings_menu', :show
%p!= t('.help')
= semantic_form_for @site, :url => sites_url do |form|
= render 'form', :f => form
= render 'locomotive/shared/form_actions', :back_url => edit_my_account_url, :button_label => :create

View File

@ -144,6 +144,8 @@ en:
new: new:
title: New site title: New site
help: "Fill in the form below to create your new site." help: "Fill in the form below to create your new site."
domains:
empty: "There are no domains tied this site yet. Simply add your domains just below. <b>Do not forget to upgrade your DNS.</b>"
current_site: current_site:
edit: edit:

View File

@ -16,11 +16,12 @@ x fix css in firefox
x update page in ajax x update page in ajax
- fix other sections - fix other sections
- edit my site - edit my site
x css
x robots.txt
- domains - domains
- robots.txt
- roles - roles
- save - save
- css
- create a new site - create a new site
- edit my account - edit my account
- theme assets - theme assets

View File

@ -47,7 +47,7 @@ module Locomotive
sign_out(current_locomotive_account) sign_out(current_locomotive_account)
flash[:alert] = I18n.t(:no_membership, :scope => [:devise, :failure, :locomotive]) flash[:alert] = I18n.t(:no_membership, :scope => [:devise, :failure, :locomotive])
redirect_to new_session_url and return false redirect_to new_locomotive_account_session_url and return false
end end
end end

View File

@ -0,0 +1,50 @@
/**
* Version 0.0.1
* tiny effect to display an input field when clicking on a label
* Didier Lafforgue
*/
$.fn.editableField = function(settings) {
var destroy = false;
if ('destroy' == settings) {
destroy = true
} else {
settings = $.extend({}, settings);
}
function getText(element) {
if (element.is('select')) {
return element[0].options[element[0].options.selectedIndex].text;
} else {
return element.val();
}
}
return this.each(function() {
if (destroy) {
$(this).unbind('mouseenter').unbind('mouseleave');
$(this).prev('.editable').unbind('click').remove();
} else {
var input = $(this).hide();
var label = $('<em></em>').addClass('editable').html(getText(input));
var timer = null;
input.before(label);
label.bind('click', function() {
label.hide();
input.show().focus();
});
input.hover(function() {
clearTimeout(timer);
}, function() {
timer = setTimeout(function() { input.hide(); label.show() }, 1000);
}).change(function() {
input.hide();
label.show().html(getText(input))
});
}
});
}