the screen for editing site has been refactored

This commit is contained in:
did 2011-11-29 14:58:19 +01:00
parent 35012ca2b2
commit 5d271239b7
30 changed files with 331 additions and 116 deletions

View File

@ -0,0 +1,13 @@
class Locomotive.Models.Membership extends Backbone.Model
toJSONForSave: ->
_.tap {}, (hash) =>
for key, value of @.toJSON()
hash[key] = value if _.include(['id', 'role', '_destroy'], key)
class Locomotive.Models.MembershipsCollection extends Backbone.Collection
model: Locomotive.Models.Membership
toJSONForSave: ->
@map (model) => model.toJSONForSave()

View File

@ -1,6 +1,6 @@
class Locomotive.Models.Site extends Backbone.Model
paramRoot: 'page'
paramRoot: 'site'
urlRoot: "#{Locomotive.mount_on}/sites"
@ -9,10 +9,23 @@ class Locomotive.Models.Site extends Backbone.Model
domains = _.map @get('domains_without_subdomain'), (name) =>
new Locomotive.Models.Domain(name: name)
@set domains: domains
memberships = new Locomotive.Models.MembershipsCollection(@get('memberships'))
@set domains: domains, memberships: memberships
includes_domain: (name) ->
name == @domain_with_domain() || _.any(@get('domains'), (domain) -> domain.get('name') == name)
domain_with_domain: ->
"#{@get('subdomain')}.#{@get('domain_name')}"
toJSON: ->
_.tap super, (hash) =>
hash.memberships = @get('memberships').toJSONForSave() if @get('memberships')
hash.domains = _.map(@get('domains'), (domain) -> domain.get('name'))
class Locomotive.Models.CurrentSite extends Locomotive.Models.Site
urlRoot: "#{Locomotive.mount_on}/current_site"
url: "#{Locomotive.mount_on}/current_site"

View File

@ -8,7 +8,7 @@ class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.Form
el: '#content'
events:
'click .memberships a.remove': 'remove_membership'
'submit': 'save'
initialize: ->
@model = new Locomotive.Models.CurrentSite(@options.site)
@ -20,17 +20,22 @@ class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.Form
render: ->
super()
@render_domain_entries()
@render_domains()
@render_memberships()
@enable_liquid_editing()
@enable_ui_effects()
render_domain_entries: ->
render_domains: ->
@domains_view = new Locomotive.Views.Site.DomainsView model: @model, errors: @options.errors
@$('#site_domains_input label').after(@domains_view.render().el)
render_memberships: ->
@memberships_view = new Locomotive.Views.Site.MembershipsView model: @model
@$('#site_memberships_input').append(@memberships_view.render().el)
enable_liquid_editing: ->
input = @$('#site_robots_txt')
@editor = CodeMirror.fromTextArea input.get()[0],
@ -42,12 +47,18 @@ class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.Form
theme: 'default'
onChange: (editor) => @model.set(robots_txt: editor.getValue())
enable_ui_effects: ->
@$('#site_domains_input .domain input[type=text]').editableField()
@$('.memberships .entry .role select').editableField()
save: (event) ->
if @model.includes_domain(window.location.host)
@save_in_ajax(event)
remove_membership: (event) ->
event.stopPropagation() & event.preventDefault()
entry = $(event.target).parents('.entry').hide()
entry.find('input[type=hidden]').val(1)
show_error: (attribute, message, html) ->
if attribute == 'domains'
@domains_view.show_error(message)
else
super
remove: ->
@domains_view.remove()
@memberships_view.remove()
super

View File

@ -29,8 +29,6 @@ class Locomotive.Views.EditableElements.EditAllView extends Backbone.View
refresh: ->
_.each @_editable_elements_views, (view) =>
foo = @collection.get(view.model.get('id'))
console.log(foo.cid)
view.model = @collection.get(view.model.get('id'))
view.refresh()

View File

@ -7,8 +7,6 @@ class Locomotive.Views.Pages.EditView extends Locomotive.Views.Pages.FormView
@clear_errors()
console.log('saving')
@model.save {},
success: (model, response, xhr) =>
model._normalize()

View File

@ -18,6 +18,32 @@ class Locomotive.Views.Shared.FormView extends Backbone.View
save: (event) ->
# by default, follow the default behaviour
save_in_ajax: (event, options) ->
event.stopPropagation() & event.preventDefault()
@clear_errors()
options ||= { on_success: null, on_error: null }
previous_attributes = _.clone @model.attributes
@model.save {},
success: (model, response, xhr) =>
$.growl('success', xhr.getResponseHeader('X-Message'))
model.attributes = previous_attributes
options.on_success(response) if options.on_success
error: (model, xhr) =>
$.growl('error', xhr.getResponseHeader('X-Message'))
errors = JSON.parse(xhr.responseText)
@show_errors errors
options.on_error() if options.on_error
make_title_editable: ->
title = @$('h2 a.editable')
@ -49,7 +75,7 @@ class Locomotive.Views.Shared.FormView extends Backbone.View
# overide this method if necessary
clear_errors: ->
@$('div.inline-errors').remove()
@$('.inline-errors').remove()
show_errors: (errors) ->
for attribute, message of errors

View File

@ -1,4 +1,4 @@
Locomotive.Views.CurrentSite ||= {}
Locomotive.Views.Site ||= {}
class Locomotive.Views.Site.DomainEntryView extends Backbone.View

View File

@ -17,6 +17,8 @@ class Locomotive.Views.Site.DomainsView extends Backbone.View
@render_entries()
@enable_ui_effects()
return @
add_entry: (event) ->
@ -53,11 +55,22 @@ class Locomotive.Views.Site.DomainsView extends Backbone.View
@$('.empty').show()
else
_.each @model.get('domains'), (domain) =>
_.each @options.errors.domain || [], (message) =>
domain.error = message if message.test /^#{domain.get('name')} /
@_insert_entry(domain)
@show_errors()
show_errors: ->
_.each @options.errors.domain || [], (message) => @show_error(message)
show_error: (message) ->
_.each (@_entry_views || []), (view) ->
if new RegExp("^#{view.model.get('name')}").test message
html = $('<span></span>').addClass('inline-errors').html(message)
view.$('input[type=text].path').after(html)
enable_ui_effects: ->
@$('.domain input[type=text]').editableField()
_insert_entry: (domain) ->
view = new Locomotive.Views.Site.DomainEntryView model: domain, parent_view: @

View File

@ -0,0 +1,29 @@
Locomotive.Views.Site ||= {}
class Locomotive.Views.Site.MembershipEntryView extends Backbone.View
className: 'entry'
events:
'change select' : 'change'
'click a.remove': 'remove'
render: ->
data = @model.toJSON()
data.index = @options.index
$(@el).html(ich.membership_entry(data))
@$('select').val(@model.get('role'))
return @
change: (event) ->
value = $(event.target).val()
@options.parent_view.change_entry(@model, value)
remove: (event) ->
event.stopPropagation() & event.preventDefault()
@$('select').editableField('destroy')
@options.parent_view.remove_entry(@model)
super()

View File

@ -0,0 +1,41 @@
Locomotive.Views.Site ||= {}
class Locomotive.Views.Site.MembershipsView extends Backbone.View
tagName: 'div'
className: 'list'
_entry_views = []
render: ->
@render_entries()
@enable_ui_effects()
return @
change_entry: (membership, value) ->
membership.set role: value
remove_entry: (membership) ->
membership.set _destroy: true
render_entries: ->
@model.get('memberships').each (membership, index) =>
@_insert_entry(membership, index)
enable_ui_effects: ->
@$('.entry select').editableField()
_insert_entry: (membership, index) ->
view = new Locomotive.Views.Site.MembershipEntryView model: membership, parent_view: @, index: index
(@_entry_views ||= []).push(view)
$(@el).append(view.render().el)

View File

@ -95,6 +95,16 @@ form.formtastic {
}
}
span.inline-errors {
margin-left: 10px;
padding: 2px 3px;
background: #FFE5E5;
color: #CE2525;
font-size: 13px;
}
span.actions {
position: absolute;
top: 0px;
@ -323,44 +333,45 @@ form.formtastic {
margin-top: 10px;
margin-bottom: 0px;
}
}
} // li.no-label
&.memberships {
em.email {
margin-left: 10px;
}
&#site_memberships_input {
.entry {
em.email {
margin-left: 10px;
}
.role {
position: absolute;
top: 0px;
right: 30px;
width: 170px;
.role {
position: absolute;
top: 0px;
right: 30px;
width: 170px;
line-height: 30px;
line-height: 30px;
em {
padding-left: 17px;
margin-left: 0px;
background-repeat: no-repeat;
em {
padding-left: 17px;
margin-left: 0px;
background-repeat: no-repeat;
color: #757575;
font-size: 13px;
font-weight: normal;
color: #757575;
font-size: 13px;
font-weight: normal;
&.locked {
background-image: image-url("locomotive/icons/membership_lock.png");
background-position: 1px 0px;
}
&.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;
}
&.editable {
background-image: image-url("locomotive//icons/membership_edit.png");
background-position: 0px 3px;
}
}
} // li.no-label .list.memberships
}
}
} // li.no-label
} // > li#site_memberships_input
} // > li

View File

@ -31,7 +31,7 @@ module Locomotive
sign_in(account)
redirect_to admin_pages_path
else
redirect_to new_admin_session_path, :alert => t('fash.locomotive.cross_domain_sessions.create.alert')
redirect_to new_admin_session_path, :alert => t('flash.locomotive.cross_domain_sessions.create.alert')
end
end

View File

@ -106,5 +106,17 @@ module Locomotive::BaseHelper
end
end
# memberships
def options_for_membership_roles(options = {})
list = (unless options[:skip_admin]
Locomotive::Ability::ROLES.map { |r| [t("locomotive.memberships.roles.#{r}"), r] }
else
(Locomotive::Ability::ROLES - ['admin']).map { |r| [t("locomotive.memberships.roles.#{r}"), r] }
end)
options_for_select(list)
end
end

View File

@ -1,11 +1,11 @@
module Locomotive::SitesHelper
def error_on_domain(site, name)
if (error = (site.errors[:domains] || []).detect { |n| n.include?(name) })
content_tag(:span, error, :class => 'inline-errors')
else
''
end
end
# def error_on_domain(site, name)
# if (error = (site.errors[:domains] || []).detect { |n| n.include?(name) })
# content_tag(:span, error, :class => 'inline-errors')
# else
# ''
# end
# end
end

View File

@ -9,6 +9,12 @@ module Locomotive
end
end
def wrapper_html_options
super.tap do |opts|
opts[:class] += ' no-label' unless render_label?
end
end
def error_html
""
end
@ -17,13 +23,5 @@ module Locomotive
false
end
# def hint_html
# ""
# end
#
# def hint?
# false
# end
end
end

View File

@ -51,6 +51,10 @@ module Locomotive
@ability ||= Ability.new(self.account, self.site)
end
def as_json(options = {})
Locomotive::MembershipPresenter.new(self, options).as_json
end
protected
def define_role

View File

@ -50,7 +50,7 @@ module Locomotive
end
def as_json(options = {})
Locomotive::SitePresenter.new(self).as_json
Locomotive::SitePresenter.new(self, options).as_json
end
protected

View File

@ -5,18 +5,27 @@ class Locomotive::BasePresenter
include ActionView::Helpers::TextHelper
include ActionView::Helpers::NumberHelper
attr_reader :source
attr_reader :source, :options, :ability
delegate :created_at, :updated_at, :to => :source
def initialize(object)
@source = object
def initialize(object, options = {})
@source = object
@options = options
if @options && @options[:current_account] && @options[:current_site]
@ability = Locomotive::Ability.new @options[:current_account], @options[:current_site]
end
end
def id
@source._id.to_s
end
def ability?
self.ability.present?
end
def included_methods
%w(id created_at updated_at)
end

View File

@ -0,0 +1,33 @@
module Locomotive
class MembershipPresenter < BasePresenter
delegate :role, :to => :source
def name
self.source.account.name
end
def role_name
I18n.t("locomotive.memberships.roles.#{self.source.role}")
end
def email
self.source.account.email
end
def can_update
return nil unless self.ability?
self.ability.can? :update, self.source
end
def grant_admin
return nil unless self.ability?
self.ability.can? :grant_admin, self.source
end
def included_methods
super + %w(name email role role_name can_update grant_admin)
end
end
end

View File

@ -1,10 +1,18 @@
module Locomotive
class SitePresenter < BasePresenter
delegate :name, :subdomain, :domains, :robots_txt, :seo_title, :meta_keywords, :meta_description, :domains_without_subdomain, :memberships, :to => :source
delegate :name, :subdomain, :domains, :robots_txt, :seo_title, :meta_keywords, :meta_description, :domains_without_subdomain, :to => :source
def domain_name
Locomotive.config.domain
end
def memberships
self.source.memberships.map { |membership| membership.as_json(self.options) }
end
def included_methods
super + %w(name subdomain domains robots_txt seo_title meta_keywords meta_description domains_without_subdomain memberships)
super + %w(name domain_name subdomain domains robots_txt seo_title meta_keywords meta_description domains_without_subdomain memberships)
end
end

View File

@ -1,9 +1,10 @@
- content_for :head do
= render 'locomotive/sites/domains'
= render 'locomotive/sites/memberships'
- content_for :backbone_view_data do
:plain
{ site: #{@site.to_json}, errors: #{@site.errors.to_json} }
{ site: #{@site.to_json(:current_account => current_locomotive_account, :current_site => current_site)}, errors: #{@site.errors.to_json} }
= f.inputs :name => :information, :style => "#{'display: none' unless @site.new_record?}" do
= f.input :name, :required => false
@ -24,32 +25,7 @@
- if can?(:index, Locomotive::Membership)
= f.inputs :name => :memberships do
%li{ :class => 'input empty no-label' }
.list.memberships
= f.semantic_fields_for :memberships do |fm|
- membership, account = fm.object, fm.object.account
.entry
= fm.hidden_field :_destroy
%strong= account.name
%em.email= account.email
- 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'
- else
.role
%em.locked= t("locomotive.memberships.roles.#{membership.role}")
= f.input :memberships, :as => :'Locomotive::Empty', :label => false, :wrapper_html => { :id => 'site_memberships_input' }
- if can?(:manage, current_site)

View File

@ -18,9 +18,5 @@
%em http://
= text_field_tag 'site[domains][]', '{{name}}', :id => '', :class => 'path'
{{#if error}}
%span.inline-errors {{error}}
{{/if}}
%span.actions
= link_to 'x', '#', :class => 'remove'

View File

@ -0,0 +1,25 @@
%script{ :type => 'text/html', :id => 'membership_entry' }
= hidden_field_tag 'site[memberships_attributes][{{index}}][id]', '{{id}}'
= hidden_field_tag 'site[memberships_attributes][{{index}}][_destroy]'
%strong {{name}}
%em.email {{email}}
{{#if can_update}}
.role
{{#if grant_admin}}
= select_tag 'site[memberships_attributes][{{index}}][role]', options_for_membership_roles
{{else}}
= select_tag 'site[memberships_attributes][{{index}}][role]', options_for_membership_roles(:skip_admin => true)
{{/if}}
%span.actions
= link_to 'x', '#', :class => 'remove'
{{else}}
.role
%em.locked {{role_name}}
{{/if}}

View File

@ -157,7 +157,7 @@ en:
memberships:
roles:
locomotive: Administrator
admin: Administrator
designer: Designer
author: Author
new:

View File

@ -150,7 +150,7 @@ es:
memberships:
roles:
locomotive: Administrador
admin: Administrador
designer: Diseñador
author: Autor
new:

View File

@ -155,7 +155,7 @@ fr:
memberships:
roles:
locomotive: Administrateur
admin: Administrateur
designer: Designeur
author: Auteur
new:

View File

@ -150,7 +150,7 @@ it:
memberships:
roles:
locomotive: Amministratore
admin: Amministratore
designer: Designer
author: Autore
new:

View File

@ -152,7 +152,7 @@
memberships:
roles:
locomotive: Administrator
admin: Administrator
designer: Designer
author: Forfatter
new:

View File

@ -152,7 +152,7 @@ ru:
memberships:
roles:
locomotive: Администратор
admin: Администратор
designer: Дизайнер
author: Автор
new:

View File

@ -15,18 +15,19 @@ x menu / submenu in full css3 (no images)
x fix css in firefox
x update page in ajax
- fix other sections
- edit my site
x edit my site
x css
x robots.txt
- domains
- roles
- save
x domains
x roles
x save
- create a new site
- edit my account
- theme assets
- content types
- install a site by default at the first installation (without asking)