Compare commits

..

No commits in common. "master" and "sgrove-master" have entirely different histories.

1745 changed files with 73327 additions and 33227 deletions

17
.gitignore vendored
View File

@ -1,12 +1,11 @@
.bundle
db/*.sqlite3
log
log/*.log
tmp/**/*
.DS_Store
rerun.txt
uploads
spec/tmp
spec/fixtures/themes/default
public/assets
public/sites
public/uploads
@ -30,16 +29,4 @@ Capfile
config/deploy.rb
perf/*.rb
gem_graph.png
permanent
doc/bushido
*.swp
.sass-cache/
spec/dummy/public/sites
/spec/dummy/tmp/
/spec/dummy/spec/tmp
/spec/dummy/log/*.log
/spec/dummy/tmp/**/*
app/assets/javascripts/old/
app/assets/stylesheets/old/
.rbenv-gemsets
sites/

2
.rspec
View File

@ -1,2 +0,0 @@
--colour
--backtrace

View File

@ -1,14 +0,0 @@
script: "bundle exec rake travis"
before_script: ./bin/ci/before_build.sh
rvm:
- 1.9.2
- 1.9.3
notifications:
email:
- didier@nocoffee.fr
- mario@mariovisic.com
irc: "irc.freenode.org#locomotivecms"
branches:
only:
- master
- 1.0-stable

90
Gemfile Executable file → Normal file
View File

@ -1,55 +1,65 @@
#!/usr/bin/env bundle
# encoding: utf-8
source :rubygems
gemspec # Include gemspec dependencies
# add in all the runtime dependencies
# The rest of the dependencies are for use when in the locomotive development environment
gem 'rails', '>= 3.0.5'
gem 'warden'
gem 'devise', '= 1.1.3'
gem 'mongoid', '2.0.0.rc.7'
gem 'bson_ext', '~> 1.3.0'
gem 'locomotive_mongoid_acts_as_tree', '0.1.5.5', :require => 'mongoid_acts_as_tree'
gem 'will_paginate'
gem 'haml', '3.0.25'
gem 'locomotive_liquid', '2.2.2', :require => 'liquid'
gem 'formtastic', '~> 1.2.3'
gem 'inherited_resources', '~> 1.1.2'
gem 'rmagick', '2.12.2'
gem 'locomotive_carrierwave', '0.5.0.1.beta3', :require => 'carrierwave'
gem 'custom_fields', '1.0.0.beta.9'
gem 'fog', '0.3.7'
gem 'mimetype-fu'
gem 'actionmailer-with-request', :require => 'actionmailer_with_request'
gem 'heroku', '1.19.1'
gem 'bushido'
gem 'httparty', '>= 0.6.1'
gem 'RedCloth', '4.2.7'
gem 'delayed_job', '2.1.4'
gem 'delayed_job_mongoid', '1.0.2'
gem 'rubyzip'
gem 'locomotive_jammit-s3', :require => 'jammit-s3'
gem 'SystemTimer', :platforms => :ruby_18
# The rest of the dependencies are for use when in the locomotive dev environment
group :development do
# gem 'custom_fields', :path => '../gems/custom_fields' # for Developers
# gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => '2.0.0.rc' # Branch on Github
# gem 'locomotive-aloha-rails', :path => '../gems/aloha-rails' # for Developers
gem 'rspec-rails', '~> 2.8.0' # In order to have rspec tasks and generators
gem 'rspec-cells'
gem 'unicorn' # Using unicorn_rails instead of webrick (default server)
# Using unicorn_rails instead of webrick (default server)
gem 'unicorn'
end
group :assets do
gem 'sass-rails', '~> 3.2.4'
gem 'coffee-rails', '~> 3.2.2'
gem 'uglifier', '~> 1.2.4'
gem 'compass-rails'
group :test, :development do
gem "ruby-debug", :platforms => :mri_18
gem "ruby-debug19", :platforms => :mri_19
end
group :test do
gem 'launchy'
# gem 'autotest', :platforms => :mri
# gem 'ZenTest', :platforms => :mri
# gem 'growl-glue'
gem 'cucumber-rails', :require => false
gem 'poltergeist'
gem 'rspec-rails', '~> 2.8.0'
gem 'shoulda-matchers'
gem 'factory_girl_rails', '~> 1.6.0'
gem 'autotest'
gem 'ZenTest'
gem 'growl-glue'
gem 'rspec-rails', '2.3.1'
gem 'factory_girl_rails'
gem 'pickle'
gem 'mocha', '0.9.12' # :git => 'git://github.com/floehopper/mocha.git'
gem 'xpath', :git => 'https://github.com/wunderbread/xpath.git'
gem 'capybara'
gem 'xpath', '~> 0.1.4'
gem 'json_spec'
gem 'database_cleaner'
# gem 'debugger', :git => 'git://github.com/cldwalker/debugger.git'
gem 'cucumber', '0.8.5'
gem 'cucumber-rails'
gem 'spork'
gem 'launchy'
gem 'mocha', :git => 'git://github.com/floehopper/mocha.git'
end

View File

@ -1,345 +1,311 @@
PATH
remote: .
GIT
remote: git://github.com/floehopper/mocha.git
revision: 2b4e868d1907859cd03f407078bd8b630f7d0dd6
specs:
locomotive_cms (2.0.0.rc8)
RedCloth (~> 4.2.8)
actionmailer-with-request (~> 0.3.0)
bson_ext (~> 1.5.2)
cancan (~> 1.6.7)
carrierwave-mongoid (~> 0.2.1)
cells (~> 3.8.0)
codemirror-rails (~> 2.21)
custom_fields (~> 2.0.0.rc12)
devise (~> 2.1.0)
devise-encryptable (~> 0.1.1)
dragonfly (~> 0.9.8)
flash_cookie_session (~> 1.1.1)
fog (~> 1.3.1)
formtastic (~> 2.0.2)
haml (~> 3.1.6)
highline (~> 1.6.2)
httparty (~> 0.8.1)
jquery-rails (~> 1.0.19)
kaminari (~> 0.13.0)
locomotive-aloha-rails (~> 0.20.1.4)
locomotive-mongoid-tree (~> 0.6.2)
locomotive-tinymce-rails (~> 3.4.7.2)
locomotive_liquid (= 2.2.2)
mimetype-fu (~> 0.1.2)
mongo (~> 1.5.2)
mongoid (~> 2.4.9)
multi_json (~> 1.3.4)
rack-cache (~> 1.1)
rails (~> 3.2.5)
rails-backbone (~> 0.6.1)
rake (~> 0.9.2)
responders (~> 0.6.4)
rmagick (~> 2.12.2)
sanitize (~> 2.0.3)
unidecoder (~> 1.1.1)
mocha (0.9.12.20110213002255)
GIT
remote: https://github.com/wunderbread/xpath.git
revision: d04da707886287e7dfe82705fda5b3d4f65e94c3
specs:
xpath (0.1.2)
nokogiri (~> 1.4)
GEM
remote: http://rubygems.org/
specs:
RedCloth (4.2.9)
actionmailer (3.2.5)
actionpack (= 3.2.5)
mail (~> 2.4.4)
POpen4 (0.1.4)
Platform (>= 0.4.0)
open4
Platform (0.4.0)
RedCloth (4.2.7)
SystemTimer (1.2.3)
ZenTest (4.5.0)
abstract (1.0.0)
actionmailer (3.0.7)
actionpack (= 3.0.7)
mail (~> 2.2.15)
actionmailer-with-request (0.3.0)
rails (>= 3)
actionpack (3.2.5)
activemodel (= 3.2.5)
activesupport (= 3.2.5)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.1)
rack (~> 1.4.0)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.1.3)
activemodel (3.2.5)
activesupport (= 3.2.5)
builder (~> 3.0.0)
activerecord (3.2.5)
activemodel (= 3.2.5)
activesupport (= 3.2.5)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.5)
activemodel (= 3.2.5)
activesupport (= 3.2.5)
activesupport (3.2.5)
i18n (~> 0.6)
multi_json (~> 1.0)
addressable (2.2.8)
arel (3.0.2)
bcrypt-ruby (3.0.1)
bson (1.5.2)
bson_ext (1.5.2)
bson (= 1.5.2)
builder (3.0.0)
cancan (1.6.7)
capybara (1.1.2)
actionpack (3.0.7)
activemodel (= 3.0.7)
activesupport (= 3.0.7)
builder (~> 2.1.2)
erubis (~> 2.6.6)
i18n (~> 0.5.0)
rack (~> 1.2.1)
rack-mount (~> 0.6.14)
rack-test (~> 0.5.7)
tzinfo (~> 0.3.23)
activemodel (3.0.7)
activesupport (= 3.0.7)
builder (~> 2.1.2)
i18n (~> 0.5.0)
activerecord (3.0.7)
activemodel (= 3.0.7)
activesupport (= 3.0.7)
arel (~> 2.0.2)
tzinfo (~> 0.3.23)
activeresource (3.0.7)
activemodel (= 3.0.7)
activesupport (= 3.0.7)
activesupport (3.0.7)
archive-tar-minitar (0.5.2)
arel (2.0.9)
autotest (4.4.6)
ZenTest (>= 4.4.1)
bcrypt-ruby (2.1.4)
bson (1.3.0)
bson_ext (1.3.0)
builder (2.1.2)
bushido (0.0.12)
highline (>= 1.6.1)
json (>= 1.4.6)
rest-client (>= 1.6.1)
capybara (0.4.0)
celerity (>= 0.7.9)
culerity (>= 0.2.4)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
selenium-webdriver (~> 2.0)
xpath (~> 0.1.4)
carrierwave (0.6.2)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
carrierwave-mongoid (0.2.1)
carrierwave (~> 0.6.1)
mongoid (~> 2.1)
cells (3.8.5)
actionpack (~> 3.0)
railties (~> 3.0)
childprocess (0.3.2)
selenium-webdriver (>= 0.0.27)
xpath (~> 0.1.2)
celerity (0.8.9)
childprocess (0.1.8)
ffi (~> 1.0.6)
chunky_png (1.2.5)
codemirror-rails (2.24)
railties (~> 3.0)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.3.3)
compass (0.12.1)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
sass (~> 3.1)
compass-rails (1.0.2)
compass (>= 0.12.0, < 0.14)
cucumber (1.2.1)
builder (>= 2.1.2)
diff-lcs (>= 1.1.3)
gherkin (~> 2.11.0)
json (>= 1.4.6)
cucumber-rails (1.3.0)
capybara (>= 1.1.2)
cucumber (>= 1.1.8)
nokogiri (>= 1.5.0)
custom_fields (2.0.0.rc12)
activesupport (~> 3.2.1)
carrierwave-mongoid (~> 0.2.1)
mongoid (~> 2.4.9)
database_cleaner (0.8.0)
devise (2.1.0)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.0.7)
railties (~> 3.1)
warden (~> 1.1.1)
devise-encryptable (0.1.1)
devise (>= 2.1.0.rc)
diff-lcs (1.1.3)
dragonfly (0.9.12)
rack
ejs (1.0.0)
erubis (2.7.0)
eventmachine (0.12.10)
excon (0.13.4)
execjs (1.4.0)
multi_json (~> 1.0)
factory_girl (2.5.2)
activesupport (>= 2.3.9)
factory_girl_rails (1.6.0)
factory_girl (~> 2.5.0)
closure-compiler (1.1.1)
columnize (0.3.2)
configuration (1.2.0)
crack (0.1.8)
cucumber (0.8.5)
builder (~> 2.1.2)
diff-lcs (~> 1.1.2)
gherkin (~> 2.1.4)
json_pure (~> 1.4.3)
term-ansicolor (~> 1.0.4)
cucumber-rails (0.3.2)
cucumber (>= 0.8.0)
culerity (0.2.15)
custom_fields (1.0.0.beta.9)
activesupport (>= 3.0.4)
locomotive_carrierwave
mongoid (~> 2.0.0.rc.7)
daemons (1.1.3)
database_cleaner (0.6.7)
delayed_job (2.1.4)
activesupport (~> 3.0)
daemons
delayed_job_mongoid (1.0.2)
delayed_job (~> 2.1.1)
mongoid (~> 2.0.0.rc)
devise (1.1.3)
bcrypt-ruby (~> 2.1.2)
warden (~> 0.10.7)
diff-lcs (1.1.2)
erubis (2.6.6)
abstract (>= 1.0.0)
excon (0.6.2)
factory_girl (1.3.3)
factory_girl_rails (1.0.1)
factory_girl (~> 1.3)
railties (>= 3.0.0)
faye-websocket (0.4.5)
eventmachine (>= 0.12.0)
ffi (1.0.11)
flash_cookie_session (1.1.3)
rails (~> 3.0)
fog (1.3.1)
ffi (1.0.7)
rake (>= 0.8.7)
fog (0.3.7)
builder
excon (~> 0.13.0)
formatador (~> 0.2.0)
excon (>= 0.2.3)
formatador (>= 0.0.15)
json
mime-types
multi_json (~> 1.0)
net-scp (~> 1.0.4)
net-ssh (>= 2.1.3)
nokogiri (~> 1.5.0)
net-ssh (~> 2.0.23)
nokogiri (~> 1.4.3.1)
ruby-hmac
formatador (0.2.3)
formtastic (2.0.2)
rails (~> 3.0)
fssm (0.2.9)
gherkin (2.11.0)
json (>= 1.4.6)
haml (3.1.6)
highline (1.6.12)
hike (1.2.1)
http_parser.rb (0.5.3)
httparty (0.8.3)
multi_json (~> 1.0)
multi_xml
i18n (0.6.0)
journey (1.0.3)
jquery-rails (1.0.19)
railties (~> 3.0)
thor (~> 0.14)
json (1.7.3)
json_spec (1.0.3)
multi_json (~> 1.0)
rspec (~> 2.0)
kaminari (0.13.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
railties (>= 3.0.0)
kgio (2.7.4)
launchy (2.1.0)
addressable (~> 2.2.6)
libwebsocket (0.1.3)
addressable
locomotive-aloha-rails (0.20.1.4)
actionpack (~> 3.2.1)
locomotive-mongoid-tree (0.6.2)
mongoid (~> 2.0)
locomotive-tinymce-rails (3.4.7.2)
actionpack (~> 3.0)
formatador (0.1.3)
formtastic (1.2.3)
actionpack (>= 2.3.7)
activesupport (>= 2.3.7)
i18n (~> 0.4)
gherkin (2.1.5)
trollop (~> 1.16.2)
growl-glue (1.0.7)
haml (3.0.25)
has_scope (0.5.0)
heroku (1.19.1)
activesupport (>= 2.1.0)
launchy (~> 0.3.2)
rest-client (>= 1.4.0, < 1.7.0)
highline (1.6.1)
httparty (0.7.7)
crack (= 0.1.8)
i18n (0.5.0)
inherited_resources (1.1.2)
has_scope (~> 0.5.0)
responders (~> 0.6.0)
jammit (0.6.0)
closure-compiler (>= 0.1.0)
yui-compressor (>= 0.9.1)
json (1.5.1)
json_pure (1.4.6)
kgio (2.3.3)
launchy (0.3.7)
configuration (>= 0.0.5)
rake (>= 0.8.1)
linecache (0.43)
linecache19 (0.5.12)
ruby_core_source (>= 0.1.4)
locomotive_carrierwave (0.5.0.1.beta3)
activesupport (~> 3.0)
locomotive_jammit-s3 (0.5.4.4)
jammit (>= 0.5.4)
mimemagic (>= 0.1.7)
s3 (>= 0.3.7)
locomotive_liquid (2.2.2)
mail (2.4.4)
locomotive_mongoid_acts_as_tree (0.1.5.5)
mongoid (~> 2.0.0.rc.7)
mail (2.2.19)
activesupport (>= 2.3.6)
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.18)
mime-types (1.16)
mimemagic (0.1.8)
mimetype-fu (0.1.2)
mocha (0.9.12)
mongo (1.5.2)
bson (= 1.5.2)
mongoid (2.4.11)
activemodel (~> 3.1)
mongo (<= 1.6.2)
mongo (1.3.0)
bson (>= 1.3.0)
mongoid (2.0.0.rc.7)
activemodel (~> 3.0)
mongo (~> 1.2)
tzinfo (~> 0.3.22)
multi_json (1.3.6)
multi_xml (0.5.1)
net-scp (1.0.4)
net-ssh (>= 1.99.1)
net-ssh (2.5.2)
nokogiri (1.5.3)
orm_adapter (0.0.7)
pickle (0.4.10)
will_paginate (~> 3.0.pre)
net-ssh (2.0.24)
nokogiri (1.4.3.1)
open4 (1.0.1)
pickle (0.4.7)
cucumber (>= 0.8)
rake
poltergeist (0.6.0)
capybara (~> 1.0)
childprocess (~> 0.3)
faye-websocket (~> 0.4, >= 0.4.4)
http_parser.rb (~> 0.5.3)
multi_json (~> 1.0)
polyglot (0.3.3)
rack (1.4.1)
rack-cache (1.2)
rack (>= 0.4)
rack-ssl (1.3.2)
rack
rack-test (0.6.1)
polyglot (0.3.1)
proxies (0.2.1)
rack (1.2.2)
rack-mount (0.6.14)
rack (>= 1.0.0)
rack-test (0.5.7)
rack (>= 1.0)
rails (3.2.5)
actionmailer (= 3.2.5)
actionpack (= 3.2.5)
activerecord (= 3.2.5)
activeresource (= 3.2.5)
activesupport (= 3.2.5)
rails (3.0.7)
actionmailer (= 3.0.7)
actionpack (= 3.0.7)
activerecord (= 3.0.7)
activeresource (= 3.0.7)
activesupport (= 3.0.7)
bundler (~> 1.0)
railties (= 3.2.5)
rails-backbone (0.6.1)
coffee-script (~> 2.2.0)
ejs (~> 1.0.0)
railties (>= 3.1.0)
railties (3.2.5)
actionpack (= 3.2.5)
activesupport (= 3.2.5)
rack-ssl (~> 1.3.2)
railties (= 3.0.7)
railties (3.0.7)
actionpack (= 3.0.7)
activesupport (= 3.0.7)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
raindrops (0.9.0)
rake (0.9.2.2)
rdoc (3.12)
json (~> 1.4)
responders (0.6.5)
thor (~> 0.14.4)
rake (0.8.7)
responders (0.6.2)
rest-client (1.6.1)
mime-types (>= 1.16)
rmagick (2.12.2)
rspec (2.8.0)
rspec-core (~> 2.8.0)
rspec-expectations (~> 2.8.0)
rspec-mocks (~> 2.8.0)
rspec-cells (0.1.2)
cells (~> 3.4)
rails (~> 3.0)
rspec-rails (~> 2.2)
rspec-core (2.8.0)
rspec-expectations (2.8.0)
rspec (2.3.0)
rspec-core (~> 2.3.0)
rspec-expectations (~> 2.3.0)
rspec-mocks (~> 2.3.0)
rspec-core (2.3.1)
rspec-expectations (2.3.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.8.0)
rspec-rails (2.8.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec (~> 2.8.0)
rspec-mocks (2.3.0)
rspec-rails (2.3.1)
actionpack (~> 3.0)
activesupport (~> 3.0)
railties (~> 3.0)
rspec (~> 2.3.0)
ruby-debug (0.10.4)
columnize (>= 0.1)
ruby-debug-base (~> 0.10.4.0)
ruby-debug-base (0.10.4)
linecache (>= 0.3)
ruby-debug-base19 (0.11.25)
columnize (>= 0.3.1)
linecache19 (>= 0.5.11)
ruby_core_source (>= 0.1.4)
ruby-debug19 (0.11.6)
columnize (>= 0.3.1)
linecache19 (>= 0.5.11)
ruby-debug-base19 (>= 0.11.19)
ruby-hmac (0.4.0)
rubyzip (0.9.8)
sanitize (2.0.3)
nokogiri (>= 1.4.4, < 1.6)
sass (3.1.19)
sass-rails (3.2.5)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
selenium-webdriver (2.22.2)
childprocess (>= 0.2.5)
ffi (~> 1.0)
libwebsocket (~> 0.1.3)
multi_json (~> 1.0)
ruby_core_source (0.1.5)
archive-tar-minitar (>= 0.5.2)
rubyzip (0.9.4)
s3 (0.3.8)
proxies (~> 0.2.0)
selenium-webdriver (0.2.0)
childprocess (>= 0.1.7)
ffi (>= 1.0.7)
json_pure
rubyzip
shoulda-matchers (1.1.0)
activesupport (>= 3.0.0)
sprockets (2.1.3)
hike (~> 1.2)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
thor (0.15.2)
tilt (1.3.3)
treetop (1.4.10)
polyglot
spork (0.8.4)
term-ansicolor (1.0.5)
thor (0.14.6)
treetop (1.4.9)
polyglot (>= 0.3.1)
tzinfo (0.3.33)
uglifier (1.2.4)
execjs (>= 0.3.0)
multi_json (>= 1.0.2)
unicorn (4.3.1)
kgio (~> 2.6)
trollop (1.16.2)
tzinfo (0.3.27)
unicorn (3.6.0)
kgio (~> 2.3)
rack
raindrops (~> 0.7)
unidecoder (1.1.1)
warden (1.1.1)
rack (>= 1.0)
xpath (0.1.4)
nokogiri (~> 1.3)
warden (0.10.7)
rack (>= 1.0.0)
will_paginate (3.0.pre2)
yui-compressor (0.9.6)
POpen4 (>= 0.1.4)
PLATFORMS
ruby
DEPENDENCIES
RedCloth (= 4.2.7)
SystemTimer
ZenTest
actionmailer-with-request
autotest
bson_ext (~> 1.3.0)
bushido
capybara
coffee-rails (~> 3.2.2)
compass-rails
cucumber (= 0.8.5)
cucumber-rails
custom_fields (= 1.0.0.beta.9)
database_cleaner
factory_girl_rails (~> 1.6.0)
json_spec
delayed_job (= 2.1.4)
delayed_job_mongoid (= 1.0.2)
devise (= 1.1.3)
factory_girl_rails
fog (= 0.3.7)
formtastic (~> 1.2.3)
growl-glue
haml (= 3.0.25)
heroku (= 1.19.1)
httparty (>= 0.6.1)
inherited_resources (~> 1.1.2)
launchy
locomotive_cms!
mocha (= 0.9.12)
locomotive_carrierwave (= 0.5.0.1.beta3)
locomotive_jammit-s3
locomotive_liquid (= 2.2.2)
locomotive_mongoid_acts_as_tree (= 0.1.5.5)
mimetype-fu
mocha!
mongoid (= 2.0.0.rc.7)
pickle
poltergeist
rspec-cells
rspec-rails (~> 2.8.0)
sass-rails (~> 3.2.4)
shoulda-matchers
uglifier (~> 1.2.4)
rails (>= 3.0.5)
rmagick (= 2.12.2)
rspec-rails (= 2.3.1)
ruby-debug
ruby-debug19
rubyzip
spork
unicorn
xpath (~> 0.1.4)
warden
will_paginate
xpath!

View File

@ -1,6 +1,6 @@
== MIT License
Copyright (c) 2010-2012, Didier Lafforgue.
Copyright (c) 2010, Didier Lafforgue.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,19 +1,14 @@
h1. Locomotive CMS
"!https://secure.travis-ci.org/locomotivecms/engine.png!":http://travis-ci.org/locomotivecms/engine
Locomotive is a simple but powerful CMS based on liquid templates and mongodb database. At my company ("NoCoffee":http://www.nocoffee.fr), we use it for our clients when they request a simple website.
If we have to give a couple of features to describe our application, there will be:
If we have to give only 5 main features to describe our application, there will be:
* managing as many websites as you want with one application instance
* nice looking UI (see http://www.locomotivecms.com for some screenshots)
* flexible content types
* content localization out of the box
* playing smoothly with Heroku, Bushido and MongoHQ
* inline editing (wip)
* API
* playing smoothly with Heroku and MongoHQ
* inline editing (beta)
h2. Strategy / Development status
@ -22,57 +17,26 @@ Now, our goal is to port our prototype to Rails 3 and migrate from mongomapper t
h2. Gems
Here is a short list of main gems / technologies used in the application.
Here is a short list of main gems used in the application.
* Rails 3.2.5
* Mongoid 2.4.9 (with MongoDB 2.0)
* Rails 3.0.3
* Mongoid 2.0.0.rc.7 (with MongoDB 1.6)
* Liquid
* Devise
* Carrierwave
* Haml
* Formtastic
* Cells
* Coffeescript / Backbone / SASS
* Delayed job
* Jammit-s3
h2. Installation
See the "official website":http://www.locomotivecms.com
h2. Upgrading
We work on the procedure to upgrade from a previous version of the engine (below the 2.0.0)
h2. Community
* Get help or discuss locomotive CMS at the "LocomotiveCMS Google group":https://groups.google.com/forum/?fromgroups#!forum/locomotivecms or the "LocomotiveCMS Discussion Forums":http://locomotive.vanillaforums.com/ (deprecated)
* Join us on IRC "#locomotivecms at irc.freenode.net!":http://webchat.freenode.net/
* "Follow us on twitter":http://twitter.com/locomotivecms
h2. Contributing to Locomotive
Locomotive CMS is an open source project, we encourage contributions. If you have found a bug and want to contribute a fix, or have a new feature you would like to add, follow the steps below to get your patch into the project:
* Install ruby and mongoDB
* Clone the project <code>git clone git@github.com:locomotivecms/engine.git</code>
* Setup a virtual host entry for <code>test.example.com</code> to point to localhost
* Install PhantomJS (Required for the cucumber suite See: https://github.com/jonleighton/poltergeist)
* Run the tests <code>rake</code>
* Write your failing tests
* Make the tests pass
* "Create a GitHub pull request":http://help.github.com/send-pull-requests
For new features (especially large ones) it is best to create a topic on the "Google group":https://groups.google.com/forum/?fromgroups#!forum/locomotivecms first to make sure it fits into the goals of the project.
h2. Team
* Developers: "Didier Lafforgue":http://www.nocoffee.fr, "Mario Visic":http://www.mariovisic.com, "Jacques Crocker":http://www.railsjedi.com
* Contributors: "Dirk Kelly":http://www.dirkkelly.com, "Raphael Costa":http://raphaelcosta.net (Brazilian Portuguese translation), "Bernd Hauser":http://www.designhunger.de (German translation), "Andrea Frigido":http://www.frisoft.it (Italian translation), "Enrique García":https://github.com/kikito (Spanish translation), "Lars Smit":https://github.com/larssmit (Dutch translation), "PitOn":https://github.com/GarPit (Russian translation), "paulsponagl":https://github.com/paulsponagl
* Developers: "Didier Lafforgue":http://www.nocoffee.fr, "Jacques Crocker":http://www.railsjedi.com
* Contributors: "Dirk Kelly":http://www.dirkkelly.com, "Mario Visic":http://www.mariovisic.com, "Raphael Costa":http://raphaelcosta.net (Brazilian Portuguese translation), "Bernd Hauser":http://www.designhunger.de (German translation)
* UI Designer: "Sacha Greif":http://www.sachagreif.com
* IE maintainer: "Alex Sanford":https://github.com/alexsanford
h2. Support
Bernd Hauser from "designhunger":http://www.designhunger.de funded the following feature: *has_one* / *has_many* between content types.
h2. Credits
@ -84,5 +48,4 @@ h2. Contact
Feel free to contact me at didier at nocoffee dot fr.
Copyright (c) 2012 NoCoffee, released under the MIT license
...
Copyright (c) 2011 NoCoffee, released under the MIT license

View File

@ -1,33 +1,20 @@
#!/usr/bin/env rake
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
require File.expand_path('../config/application', __FILE__)
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/gempackagetask'
Locomotive::Application.load_tasks
gemspec = eval(File.read('locomotive_cms.gemspec'))
Rake::GemPackageTask.new(gemspec) do |pkg|
pkg.gem_spec = gemspec
end
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
# === Locomotive tasks ===
load 'lib/tasks/locomotive.rake'
# === Gems install tasks ===
Bundler::GemHelper.install_tasks
# === Travis
task :travis do
["rspec spec", "cucumber -b"].each do |cmd|
puts "Starting to run #{cmd}..."
system("export DISPLAY=:99.0 && bundle exec #{cmd}")
raise "#{cmd} failed!" unless $?.exitstatus == 0
end
desc "build the gem and release it to rubygems.org"
task :release => :gem do
sh "gem push pkg/locomotive_cms-#{gemspec.version}.gem"
end
# === RSpec ===
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
# === Cucumber ===
load 'lib/tasks/cucumber.rake'
# === Default task ===
task :default => [:spec, :cucumber]
task :default => [:spec, :cucumber]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

View File

@ -1,3 +0,0 @@
button.aloha-locomotive-media-insert {
background: url(../img/image.gif) !important;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 621 B

View File

@ -1,96 +0,0 @@
define(
['aloha/jquery', 'aloha/plugin', 'aloha/floatingmenu', 'i18n!aloha/nls/i18n', 'i18n!locomotive_media/nls/i18n', 'css!locomotive_media/css/image.css'],
function(aQuery, Plugin, FloatingMenu, i18nCore, i18n) {
var jQuery = aQuery;
var $ = aQuery;
var GENTICS = window.GENTICS, Aloha = window.Aloha;
return Plugin.create('locomotive_media', {
init: function() {
FloatingMenu.createScope(this.name, 'Aloha.continuoustext');
this._addUIInsertButton(i18nCore.t('floatingmenu.tab.insert'));
},
openDialog: function() {
var that = this;
var picker = window.parent.application_view.content_assets_picker_view;
picker.options.on_select = function(asset) {
if (asset.get('image') == true)
that.insertImg(asset);
else
that.insertLink(asset);
picker.close();
}
picker.fetch_assets();
},
/**
* This method will insert a new image dom element into the dom tree
*/
insertImg: function(asset) {
var range = Aloha.Selection.getRangeObject(),
imageUrl = asset.get('url'),
imagestyle, imagetag, newImg;
if (range.isCollapsed()) {
imagestyle = "max-width: " + asset.get('width') + "; max-height: " + asset.get('height');
imagetag = '<img style="'+ imagestyle + '" src="' + imageUrl + '" title="" />';
newImg = jQuery(imagetag);
GENTICS.Utils.Dom.insertIntoDOM(newImg, range, jQuery(Aloha.activeEditable.obj));
} else {
Aloha.Log.error('media cannot markup a selection');
}
},
/**
* This method will insert a new link dom element into the dom tree
*/
insertLink: function(asset) {
var range = Aloha.Selection.getRangeObject(),
linkText = asset.get('filename'),
linkUrl = asset.get('url'),
linktag, newLink;
if (range.isCollapsed()) {
linktag = '<a href="' + linkUrl + '">' + linkText + '</a>';
newLink = jQuery(linktag);
GENTICS.Utils.Dom.insertIntoDOM(newLink, range, jQuery(Aloha.activeEditable.obj));
range.startContainer = range.endContainer = newLink.contents().get(0);
range.startOffset = 0;
range.endOffset = linkText.length;
} else {
linktag = '<a href="' + linkUrl + '"></a>';
newLink = jQuery(linktag);
GENTICS.Utils.Dom.addMarkup(range, newLink, false);
}
},
/**
* Adds the insert button to the floating menu
*/
_addUIInsertButton: function(tabId) {
var that = this;
this.insertMediaButton = new Aloha.ui.Button({
'name' : 'insertlocomotivemedia',
'iconClass': 'aloha-button aloha-locomotive-media-insert',
'size' : 'small',
'onclick' : function () { that.openDialog(); },
'tooltip' : i18n.t('button.addimg.tooltip'),
'toggle' : false
});
FloatingMenu.addButton(
'Aloha.continuoustext',
this.insertMediaButton,
tabId,
1
);
},
});
}
);

View File

@ -1 +0,0 @@
define({ 'button.addimg.tooltip': 'insérer média' });

View File

@ -1,4 +0,0 @@
define({
root: { "button.addimg.tooltip": "insert media" },
fr: true
});

View File

@ -1,25 +0,0 @@
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require underscore
//= require backbone
//= require codemirror
//= require tinymce-jquery
//= require codemirror/utils/overlay
//= require codemirror/modes/css
//= require codemirror/modes/javascript
//= require codemirror/modes/xml
//= require codemirror/modes/htmlmixed
//= require locomotive/vendor
//= require ./locomotive/application
$(document).ready(function() {
$.datepicker.setDefaults($.datepicker.regional[window.locale]);
});

View File

@ -1,2 +0,0 @@
#= require ./utils/aloha_settings
#= require aloha

View File

@ -1,12 +0,0 @@
#= require_self
#= require_tree ./utils
#= require_tree ./models
#= require_tree ./views
window.Locomotive =
mounted_on: window.Locomotive.mounted_on
Models: {}
Collections: {}
Views: {}
window.Locomotive.Views.Memberships = {}

View File

@ -1,22 +0,0 @@
#= require jquery
#= require jquery-ui
#= require jquery_ujs
#= require underscore
#= require backbone
#= require locomotive/backbone.sync
#= require locomotive/growl
#= require locomotive/handlebars
#= require locomotive/ICanHandlebarz
#= require locomotive/resize
#= require locomotive/toggle
#= require_self
#= require_tree ./utils
#= require_tree ./models
#= require_tree ./views/content_assets
#= require_tree ./views/inline_editor
window.Locomotive =
mounted_on: '/locomotive' # default path
Models: {}
Collections: {}
Views: {}

View File

@ -1,11 +0,0 @@
class Locomotive.Models.Account extends Backbone.Model
paramRoot: 'account'
urlRoot: "#{Locomotive.mounted_on}/accounts"
class Locomotive.Models.CurrentAccount extends Locomotive.Models.Account
url: "#{Locomotive.mounted_on}/my_account"

View File

@ -1,20 +0,0 @@
class Locomotive.Models.ContentAsset extends Backbone.Model
paramRoot: 'content_asset'
urlRoot: "#{Locomotive.mounted_on}/content_assets"
initialize: ->
@prepare()
prepare: ->
@set
image: @get('content_type') == 'image'
return @
class Locomotive.Models.ContentAssetsCollection extends Backbone.Collection
model: Locomotive.Models.ContentAsset
url: "#{Locomotive.mounted_on}/content_assets"

View File

@ -1,61 +0,0 @@
class Locomotive.Models.ContentEntry extends Backbone.Model
paramRoot: 'content_entry'
urlRoot: "#{Locomotive.mounted_on}/content_types/:slug/entries"
initialize: ->
@urlRoot = @urlRoot.replace(':slug', @get('content_type_slug'))
_.each @get('has_many_custom_fields'), (field) =>
name = field[0]
collection = new Locomotive.Models.ContentEntriesCollection(@get(name))
@set_attribute name, collection
_.each @get('many_to_many_custom_fields'), (field) =>
name = field[0]
collection = new Locomotive.Models.ContentEntriesCollection(@get(name))
collection.comparator = (entry) -> entry.get('__position') || 0
@set_attribute name, collection
set_attribute: (attribute, value) ->
data = {}
data[attribute] = value
@set data
update_attributes: (attributes) ->
_.each attributes.file_custom_fields, (field) => # special treatment for files
attribute = "#{field}_url"
@set_attribute attribute, attributes[attribute]
@set_attribute "remove_#{field}", false
toMinJSON: ->
_.tap {}, (hash) =>
_.each @attributes, (val, key) =>
if key == 'id' || key == '_destroy' || key.indexOf('position_in_') == 0
hash[key] = val
toJSON: ->
_.tap super, (hash) =>
hash['_slug'] = '' if hash['_slug'] == null # avoid empty hash
_.each _.keys(hash), (key) =>
unless _.include(@get('safe_attributes'), key)
delete hash[key]
_.each @get('has_many_custom_fields'), (field) => # include the has_many relationships
name = field[0]
if @get(name).length > 0
hash["#{name}_attributes"] = @get(name).toMinJSON()
_.each @get('many_to_many_custom_fields'), (field) => # include the many_to_many relationships
name = field[0]; setter_name = field[1]
hash[setter_name] = @get(name).sort().map (entry) => entry.id
class Locomotive.Models.ContentEntriesCollection extends Backbone.Collection
model: Locomotive.Models.ContentEntry
url: "#{Locomotive.mounted_on}/content_types/:slug/entries"
toMinJSON: ->
@map (entry) => entry.toMinJSON()

View File

@ -1,23 +0,0 @@
class Locomotive.Models.ContentType extends Backbone.Model
paramRoot: 'content_type'
urlRoot: "#{Locomotive.mounted_on}/content_types"
initialize: ->
@_normalize()
_normalize: ->
@set
entries_custom_fields: new Locomotive.Models.CustomFieldsCollection(@get('entries_custom_fields'))
toJSON: ->
_.tap super, (hash) =>
delete hash.entries_custom_fields
hash.entries_custom_fields_attributes = @get('entries_custom_fields').toJSONForSave() if @get('entries_custom_fields')? && @get('entries_custom_fields').length > 0
class Locomotive.Models.ContentTypesCollection extends Backbone.Collection
model: Locomotive.Models.ContentType
url: "#{Locomotive.mounted_on}/content_types"

View File

@ -1,38 +0,0 @@
class Locomotive.Models.CustomField extends Backbone.Model
initialize: ->
@_normalize()
unless @get('name')?
@set name: @get('label').slugify()
_normalize: ->
@set
select_options: new Locomotive.Models.CustomFieldSelectOptionsCollection(@get('select_options'))
_undesired_fields:
['select_options', 'type_text', 'text_formatting_text', 'inverse_of_text', 'class_name_text', 'undefined_text', 'undefined', 'created_at', 'updated_at']
_relationship_fields:
['class_name', 'inverse_of', 'ui_enabled']
is_relationship_type: ->
_.include(['belongs_to', 'has_many', 'many_to_many'], @get('type'))
toJSONForSave: ->
_.tap {}, (hash) =>
for key, value of @.toJSON()
unless _.include(@_undesired_fields, key)
if _.include(@_relationship_fields, key)
hash[key] = value if @is_relationship_type()
else
hash[key] = value
hash.select_options_attributes = @get('select_options').toJSONForSave() if @get('select_options')? && @get('select_options').length > 0
class Locomotive.Models.CustomFieldsCollection extends Backbone.Collection
model: Locomotive.Models.CustomField
toJSONForSave: ->
@map (model) => model.toJSONForSave()

View File

@ -1,13 +0,0 @@
class Locomotive.Models.CustomFieldSelectOption extends Backbone.Model
toJSONForSave: ->
_.tap {}, (hash) =>
for key, value of @.toJSON()
hash[key] = value unless _.include(['created_at', 'updated_at'], key)
class Locomotive.Models.CustomFieldSelectOptionsCollection extends Backbone.Collection
model: Locomotive.Models.CustomFieldSelectOption
toJSONForSave: ->
@map (model) => model.toJSONForSave()

View File

@ -1,3 +0,0 @@
class Locomotive.Models.Domain extends Backbone.Model

View File

@ -1,27 +0,0 @@
class Locomotive.Models.EditableElement extends Backbone.Model
toJSONForSave: ->
_.tap {}, (hash) =>
for key, value of @.toJSON()
hash[key] = value if _.include(['id', 'source', 'content', 'remove_source'], key)
if @get('type') == 'EditableFile'
delete hash['content']
else
delete hash['source']
class Locomotive.Models.EditableElementsCollection extends Backbone.Collection
model: Locomotive.Models.EditableElement
blocks: ->
names = _.uniq(@map (editable, index) -> editable.get('block_name'))
_.tap [], (list) =>
_.each names, (name, index) ->
list.push name: name, index: index
by_block: (name) ->
@filter (editable) -> editable.get('block_name') == name
toJSONForSave: ->
@map (model) => model.toJSONForSave()

View File

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

View File

@ -1,27 +0,0 @@
class Locomotive.Models.Page extends Backbone.Model
paramRoot: 'page'
urlRoot: "#{Locomotive.mounted_on}/pages"
initialize: ->
@_normalize()
@set
edit_url: "#{Locomotive.mounted_on}/pages/#{@id}/edit"
_normalize: ->
@set
editable_elements: new Locomotive.Models.EditableElementsCollection(@get('editable_elements') || [])
toJSON: ->
_.tap super, (hash) =>
_.each ['fullpath', 'localized_fullpaths', 'templatized_from_parent', 'target_klass_name_text', 'content_type_id_text', 'edit_url', 'parent_id_text', 'response_type_text'], (key) => delete hash[key]
delete hash['editable_elements']
hash.editable_elements = @get('editable_elements').toJSONForSave() if @get('editable_elements')? && @get('editable_elements').length > 0
delete hash['target_klass_name']
hash.target_klass_name = @get('target_klass_name') if @get('templatized') == true
class Locomotive.Models.PagesCollection extends Backbone.Collection

View File

@ -1,33 +0,0 @@
class Locomotive.Models.Site extends Backbone.Model
paramRoot: 'site'
urlRoot: "#{Locomotive.mounted_on}/sites"
initialize: ->
# Be careful, domains_without_subdomain becomes domains
domains = _.map @get('domains_without_subdomain'), (name) =>
new Locomotive.Models.Domain(name: name)
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) =>
delete hash.memberships
hash.memberships_attributes = @get('memberships').toJSONForSave() if @get('memberships')? && @get('memberships').length > 0
delete hash.domains
hash.domains = _.map(@get('domains'), (domain) -> domain.get('name'))
class Locomotive.Models.CurrentSite extends Locomotive.Models.Site
url: "#{Locomotive.mounted_on}/current_site"

View File

@ -1,11 +0,0 @@
class Locomotive.Models.Snippet extends Backbone.Model
paramRoot: 'snippet'
urlRoot: "#{Locomotive.mounted_on}/snippets"
class Locomotive.Models.SnippetsCollection extends Backbone.Collection
model: Locomotive.Models.Snippet
url: "#{Locomotive.mounted_on}/snippets"

View File

@ -1,11 +0,0 @@
class Locomotive.Models.ThemeAsset extends Backbone.Model
paramRoot: 'theme_asset'
urlRoot: "#{Locomotive.mounted_on}/theme_assets"
class Locomotive.Models.ThemeAssetsCollection extends Backbone.Collection
model: Locomotive.Models.ThemeAsset
url: "#{Locomotive.mounted_on}/theme_assets"

View File

@ -1 +0,0 @@
#= require jquery

View File

@ -1,37 +0,0 @@
window.Aloha = window.Aloha ?= {}
window.Aloha.settings =
logLevels: { 'error': true, 'warn': true, 'info': false, 'debug': false }
errorhandling: true
plugins:
format:
config: [ 'b', 'i', 'u','del','sub','sup', 'p', 'title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'removeFormat']
editables:
'.editable-short-text' : [ 'b', 'i', 'u' ]
link:
config: [ 'a' ]
editables:
'.editable-short-text': [ ]
list:
config: [ 'ul' ]
editables:
'.editable-short-text': [ ]
image:
ui:
insert: false
crop: false
i18n:
available: ['en', 'fr', 'pt-BR', 'es', 'de', 'no', 'ru', 'nl']
sidebar:
disabled: true

View File

@ -1,75 +0,0 @@
(function() {
String.prototype.trim = function() {
return this.replace(/^\s+/g, '').replace(/\s+$/g, '');
}
String.prototype.repeat = function(num) {
for (var i = 0, buf = ""; i < num; i++) buf += this;
return buf;
}
String.prototype.truncate = function(length) {
if (this.length > length) {
return this.slice(0, length - 3) + "...";
} else {
return this;
}
}
String.prototype.slugify = function(sep) {
if (typeof sep == 'undefined') sep = '_';
var alphaNumRegexp = new RegExp('[^\\w\\' + sep + ']', 'g');
var avoidDuplicateRegexp = new RegExp('[\\' + sep + ']{2,}', 'g');
return this.replace(/\s/g, sep).replace(alphaNumRegexp, '').replace(avoidDuplicateRegexp, sep).toLowerCase();
}
window.addParameterToURL = function(key, value, context) { // code from http://stackoverflow.com/questions/486896/adding-a-parameter-to-the-url-with-javascript
if (typeof context == 'undefined') context = document;
key = encodeURIComponent(key); value = encodeURIComponent(value);
var kvp = context.location.search.substr(1).split('&');
var i = kvp.length; var x; while(i--) {
x = kvp[i].split('=');
if (x[0] == key) {
x[1] = value;
kvp[i] = x.join('=');
break;
}
}
if (i < 0) { kvp[kvp.length] = [key,value].join('='); }
//this will reload the page, it's likely better to store this until finished
context.location.search = kvp.join('&');
}
window.addJavascript = function(doc, src, options) {
var script = doc.createElement('script');
script.type = 'text/javascript';
script.src = src;
if (options && options.onload) {
script.onload = options.onload;
delete(options.onload);
}
for (var key in options) {
script.setAttribute(key, options[key]);
}
doc.body.appendChild(script);
}
window.addStylesheet = function(doc, src, options) {
var stylesheet = doc.createElement('link');
stylesheet.style = 'text/css';
stylesheet.href = src;
stylesheet.media = 'screen';
stylesheet.rel = 'stylesheet';
doc.head.appendChild(stylesheet);
}
$.ui.dialog.prototype.overlayEl = function() { return this.overlay.$el; }
})();

View File

@ -1,14 +0,0 @@
$.growl.settings.noticeTemplate = '' +
'<div class="notice %title%">' +
' <p>%message%</p>' +
'</div>';
$.growl.settings.dockCss = {
position: 'fixed',
bottom: '20px',
left: '0px',
width: '100%',
zIndex: 50000
};
// $.growl.settings.displayTimeout = 500;

View File

@ -1,9 +0,0 @@
Handlebars.registerHelper 'each_with_index', (context, block) ->
ret = ""
for num in context
data = context[num]
data._index = num
ret = ret + block(data)
ret

View File

@ -1,48 +0,0 @@
window.Locomotive.tinyMCE =
defaultSettings:
theme: 'advanced'
skin: 'locomotive'
plugins: 'safari,jqueryinlinepopups,locomotive_media,fullscreen'
extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title]'
theme_advanced_buttons1: 'fullscreen,code,|,bold,italic,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink,|,locomotive_media'
theme_advanced_buttons2: 'formatselect,fontselect,fontsizeselect'
theme_advanced_buttons3: ''
theme_advanced_toolbar_location: 'top'
theme_advanced_toolbar_align: 'left'
height: '300'
width: '709'
convert_urls: false
fullscreen_new_window: false
fullscreen_settings:
theme_advanced_path_location: 'top'
minimalSettings:
theme: 'advanced'
skin: 'locomotive'
plugins: 'safari,jqueryinlinepopups,locomotive_media'
theme_advanced_buttons1: 'code,|,bold,italic,strikethrough,|,fontselect,fontsizeselect,|,link,unlink,|,locomotive_media'
theme_advanced_buttons2: ''
theme_advanced_buttons3: ''
theme_advanced_toolbar_location: 'top'
theme_advanced_toolbar_align: 'left'
height: '20'
width: '709'
convert_urls: false
popupSettings:
theme: 'advanced'
skin: 'locomotive'
plugins: 'safari,jqueryinlinepopups,locomotive_media,fullscreen'
extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title]'
theme_advanced_buttons1: 'fullscreen,code,|,bold,italic,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink,|,locomotive_media'
theme_advanced_buttons2: 'formatselect,fontselect,fontsizeselect'
theme_advanced_buttons3: ''
theme_advanced_toolbar_location: 'top'
theme_advanced_toolbar_align: 'left'
height: '300'
width: '545'
convert_urls: false
fullscreen_new_window: false
fullscreen_settings:
theme_advanced_path_location: 'top'

View File

@ -1,92 +0,0 @@
class Locomotive.Views.ApplicationView extends Backbone.View
el: 'body'
render: ->
@render_flash_messages(@options.flash)
@add_submenu_behaviours()
@center_ui_dialog()
@enable_sites_picker()
@enable_content_locale_picker()
# render page view
if @options.view?
@view = new @options.view(@options.view_data || {})
@view.render()
window.Locomotive.tinyMCE.defaultSettings.language = window.locale # set the default tinyMCE language
window.Locomotive.tinyMCE.minimalSettings.language = window.locale
return @
render_flash_messages: (messages) ->
_.each messages, (couple) ->
$.growl couple[0], couple[1]
center_ui_dialog: ->
$(window).resize ->
$('.ui-dialog-content:visible').dialog('option', 'position', 'center')
add_submenu_behaviours: ->
$('#submenu ul li.hoverable').each ->
timer = null
link = $(@)
(popup = link.find('.popup')).removeClass('popup').addClass('submenu-popup'
).bind('show', ->
link.find('a').addClass('hover') & popup.css(
top: link.offset().top + link.height() - 2
left: link.offset().left - parseInt(popup.css('padding-left'))
).show()
).bind('hide', ->
link.find('a').removeClass('hover') & $(@).hide()
).bind('mouseleave', -> popup.trigger('hide')
).bind 'mouseenter', -> clearTimeout(timer)
$(document.body).append(popup)
link.hover(
-> popup.trigger('show')
-> timer = window.setTimeout (-> popup.trigger('hide')), 30
)
css = $('#submenu > ul').attr('class')
$("#submenu > ul > li.#{css}").addClass('on') if css != ''
enable_sites_picker: ->
link = @$('#sites-picker-link')
picker = @$('#sites-picker')
return if picker.size() == 0
left = link.position().left + link.parent().position().left - (picker.width() - link.width())
picker.css('left', left)
link.bind 'click', (event) ->
event.stopPropagation() & event.preventDefault()
picker.toggle()
enable_content_locale_picker: ->
link = @$('#content-locale-picker-link')
picker = @$('#content-locale-picker')
return if picker.size() == 0
link.bind 'click', (event) ->
event.stopPropagation() & event.preventDefault()
picker.toggle()
picker.find('li').bind 'click', (event) ->
locale = $(@).attr('data-locale')
window.addParameterToURL 'content_locale', locale
unique_dialog_zindex: ->
# returns the number of jQuery UI modals created in order to set a valid zIndex for each of them.
# Each modal window should have a different zIndex, otherwise there will be conflicts between them.
window.Locomotive.jQueryModals ||= 0
998 + window.Locomotive.jQueryModals++

View File

@ -1,30 +0,0 @@
Locomotive.Views.ContentAssets ||= {}
class Locomotive.Views.ContentAssets.PickerItemView extends Backbone.View
tagName: 'li'
className: 'asset'
events:
'click h4 a, .icon, .image': 'select_asset'
'click a.remove': 'remove_asset'
render: ->
$(@el).html(ich.content_asset(@model.toJSON()))
return @
select_asset: (event) ->
event.stopPropagation() & event.preventDefault()
@on_select(@model)
on_select: ->
@options.parent.options.on_select(@model) if @options.parent.options.on_select
remove_asset: (event) ->
event.stopPropagation() & event.preventDefault()
message = $(event.target).attr('data-confirm') || $(event.target).parent().attr('data-confirm')
@model.destroy() if confirm(message)

View File

@ -1,58 +0,0 @@
#= require ../shared/asset_picker_view
Locomotive.Views.ContentAssets ||= {}
class Locomotive.Views.ContentAssets.PickerView extends Locomotive.Views.Shared.AssetPickerView
number_items_per_row: 4
_item_views: []
template: ->
ich.content_asset_picker
fetch_assets: ->
@_reset()
@collection.fetch
success: () =>
@open()
build_uploader: (el, link) ->
link.bind 'click', (event) ->
event.stopPropagation() & event.preventDefault()
el.click()
el.bind 'change', (event) =>
_.each event.target.files, (file) =>
asset = new Locomotive.Models.ContentAsset(source: file)
asset.save {},
headers: { 'X-Flash': true }
success: (model, response) => @collection.add(model.prepare())
error: => @shake()
add_asset: (asset, first) ->
view = new Locomotive.Views.ContentAssets.PickerItemView model: asset, parent: @
(@_item_views ||= []).push(view)
@$('ul.list .clear').before(view.render().el)
@_refresh()
@_move_to_last_asset() unless first == true
remove_asset: (asset) ->
view = _.find @_item_views, (tmp) -> tmp.model == asset
view.remove() if view?
@_refresh()
_on_refresh: ->
self = @
@$('ul.list li.asset').each (index) ->
if (index + 1) % self.number_items_per_row == 0
$(@).addClass('last')
else
$(@).removeClass('last')
_reset: ->
_.each @_item_views || [], (view) -> view.remove()
super()

View File

@ -1,117 +0,0 @@
#= require ../shared/form_view
Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.FormView extends Locomotive.Views.Shared.FormView
el: '#content'
_file_field_views: []
_has_many_field_views: []
_many_to_many_field_views: []
events:
'submit': 'save'
initialize: ->
@model ||= new Locomotive.Models.ContentEntry(@options.content_entry)
Backbone.ModelBinding.bind @
render: ->
super()
@enable_checkboxes()
@enable_datepickers()
@enable_richtexteditor()
@enable_file_fields()
@enable_has_many_fields()
@enable_many_to_many_fields()
@slugify_label_field()
return @
enable_checkboxes: ->
@$('li.input.toggle input[type=checkbox]').checkToggle()
enable_datepickers: ->
@$('li.input.date input[type=text]').datepicker()
enable_richtexteditor: ->
_.each @$('li.input.rte textarea.html'), (textarea) =>
settings = _.extend {}, @tinyMCE_settings(),
oninit: ((editor) =>
$.cmd 'S', (() =>
editor.save()
$(textarea).trigger('changeSilently')
@$('form').trigger('submit')
), [], ignoreCase: true, document: editor.dom.doc),
onchange_callback: (editor) =>
editor.save()
$(textarea).trigger('changeSilently')
$(textarea).tinymce(settings)
enable_file_fields: ->
_.each @model.get('file_custom_fields'), (name) =>
view = new Locomotive.Views.Shared.Fields.FileView model: @model, name: name
@_file_field_views.push(view)
@$("##{@model.paramRoot}_#{name}_input label").after(view.render().el)
enable_has_many_fields: ->
unless @model.isNew()
_.each @model.get('has_many_custom_fields'), (field) =>
name = field[0]; inverse_of = field[1]
new_entry = new Locomotive.Models.ContentEntry(@options["#{name}_new_entry"])
view = new Locomotive.Views.Shared.Fields.HasManyView model: @model, name: name, new_entry: new_entry, inverse_of: inverse_of
if view.ui_enabled()
@_has_many_field_views.push(view)
@$("##{@model.paramRoot}_#{name}_input label").after(view.render().el)
enable_many_to_many_fields: ->
_.each @model.get('many_to_many_custom_fields'), (field) =>
name = field[0]
view = new Locomotive.Views.Shared.Fields.ManyToManyView model: @model, name: name, all_entries: @options["all_#{name}_entries"]
if view.ui_enabled()
@_many_to_many_field_views.push(view)
@$("##{@model.paramRoot}_#{name}_input label").after(view.render().el)
slugify_label_field: ->
@$('li.input.highlighted > input[type=text]').slugify(target: @$('#content_entry__slug'))
refresh_file_fields: ->
_.each @_file_field_views, (view) => view.refresh()
refresh: ->
@$('li.input.toggle input[type=checkbox]').checkToggle('sync')
_.each @_file_field_views, (view) => view.refresh()
reset: ->
@$('li.input.string input[type=text], li.input.text textarea, li.input.date input[type=text]').val('').trigger('change')
_.each @$('li.input.rte textarea.html'), (textarea) => $(textarea).tinymce().setContent(''); $(textarea).trigger('change')
_.each @_file_field_views, (view) => view.reset()
@$('li.input.toggle input[type=checkbox]').checkToggle('sync')
remove: ->
_.each @_file_field_views, (view) => view.remove()
_.each @_has_many_field_views, (view) => view.remove()
_.each @_many_to_many_field_views, (view) => view.remove()
super
tinyMCE_settings: ->
window.Locomotive.tinyMCE.defaultSettings

View File

@ -1,84 +0,0 @@
#= require ../shared/form_view
Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.PopupFormView extends Locomotive.Views.ContentEntries.FormView
initialize: ->
@create_dialog()
super()
render: ->
super()
return @
save: (event) ->
@save_in_ajax event,
headers: { 'X-Flash': true }
on_success: (response, xhr) =>
entry = new Locomotive.Models.ContentEntry(response)
@options.parent_view.insert_or_update_entry(entry)
@close()
create_dialog: ->
@dialog = $(@el).dialog
autoOpen: false
modal: true
zIndex: window.application_view.unique_dialog_zindex()
width: 770,
create: (event, ui) =>
$(@el).prev().find('.ui-dialog-title').html(@$('h2').html())
@$('h2').remove()
actions = @$('.dialog-actions').appendTo($(@el).parent()).addClass('ui-dialog-buttonpane ui-widget-content ui-helper-clearfix')
actions.find('#close-link').click (event) => @close(event)
actions.find('input[type=submit]').click (event) => @save(event)
open: (event, ui, extra) =>
$(@el).dialog('overlayEl').bind 'click', => @close()
# nothing to do
open: ->
parent_el = $(@el).parent()
if @model.isNew()
parent_el.find('.edit-section').hide()
parent_el.find('.new-section').show()
else
parent_el.find('.new-section').hide()
parent_el.find('.edit-section').show()
@clear_errors()
$(@el).dialog('open')
close: (event) ->
event.stopPropagation() & event.preventDefault() if event?
@clear_errors()
$(@el).dialog('overlayEl').unbind('click')
$(@el).dialog('close')
center: ->
$(@el).dialog('option', 'position', 'center')
reset: (entry) =>
@model.set entry.attributes
if entry.isNew()
@model.id = null
super()
else
@refresh()
slugify_label_field: ->
# disabled in a popup form
enable_has_many_fields: ->
# disabled in a popup form
enable_many_to_many_fields: ->
# disabled in a popup form
tinyMCE_settings: ->
window.Locomotive.tinyMCE.popupSettings

View File

@ -1,9 +0,0 @@
Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.EditView extends Locomotive.Views.ContentEntries.FormView
save: (event) ->
@save_in_ajax event,
on_success: (response, xhr) =>
@model.update_attributes(response)
@refresh_file_fields()

View File

@ -1,36 +0,0 @@
Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.IndexView extends Backbone.View
el: '#content'
render: ->
@make_sortable()
return @
make_sortable: ->
self = @
@$('ul#entries-list.sortable').sortable
handle: 'span.handle'
items: 'li.item'
axis: 'y'
update: (event, ui) -> self.call_sort $(@)
call_sort: (folder) ->
$.rails.ajax
url: folder.attr('data-url')
type: 'post'
dataType: 'json'
data:
entries: (_.map folder.sortable('toArray'), (el) -> el.replace('entry-', ''))
_method: 'put'
success: @.on_successful_sort
error: @.on_failed_sort
on_successful_sort: (data, status, xhr) ->
$.growl('success', xhr.getResponseHeader('X-Message'))
on_failed_sort: (data, status, xhr) ->
$.growl('error', xhr.getResponseHeader('X-Message'))

View File

@ -1,8 +0,0 @@
Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.NewView extends Locomotive.Views.ContentEntries.FormView
save: (event) ->
@save_in_ajax event,
on_success: (response, xhr) ->
window.location.href = xhr.getResponseHeader('location')

View File

@ -1,83 +0,0 @@
#= require ../shared/form_view
Locomotive.Views.ContentTypes ||= {}
class Locomotive.Views.ContentTypes.FormView extends Locomotive.Views.Shared.FormView
el: '#content'
events:
'submit': 'save'
initialize: ->
@model = new Locomotive.Models.ContentType(@options.content_type)
Backbone.ModelBinding.bind @
render: ->
super()
@render_custom_fields()
@slugify_name() # slugify the slug field from name
@enable_liquid_editing() # turn textarea into editable liquid code zone
@enable_public_submission_checkbox()
@enable_order_by_toggler()
return @
render_custom_fields: ->
@custom_fields_view = new Locomotive.Views.ContentTypes.CustomFieldsView model: @model, inverse_of_list: @options.inverse_of_list
@$('#custom_fields_input').append(@custom_fields_view.render().el)
slugify_name: ->
@$('#content_type_name').slugify(target: @$('#content_type_slug'), sep: '_')
enable_liquid_editing: ->
input = @$('#content_type_raw_item_template')
@editor = CodeMirror.fromTextArea input.get()[0],
mode: 'liquid'
autoMatchParens: false
lineNumbers: false
passDelay: 50
tabMode: 'shift'
theme: 'default medium'
onChange: (editor) => @model.set(raw_item_template: editor.getValue())
enable_public_submission_checkbox: ->
@_enable_checkbox 'public_submission_enabled',
on_callback: => @$('#content_type_public_submission_accounts_input').show()
off_callback: => @$('#content_type_public_submission_accounts_input').hide()
enable_order_by_toggler: ->
@$('#content_type_order_by_input').bind 'change', (event) =>
target = @$('#content_type_order_direction_input')
if $(event.target).val() == '_position'
target.hide()
else
target.show()
show_error: (attribute, message, html) ->
if attribute != 'entries_custom_fields'
super
else
return if _.isEmpty(message)
_.each _.keys(message), (key) =>
_messages = message[key]
if key == 'base'
html = $("<div class=\"inline-errors\"><p>#{_messages[0]}</p></div>")
@$('#custom_fields_input .list').after(html)
else
view = @custom_fields_view.find_entry_view(key)
view.show_error(_messages[0]) if view?
remove: ->
@custom_fields_view.remove()
super

View File

@ -1,104 +0,0 @@
Locomotive.Views.ContentTypes ||= {}
class Locomotive.Views.ContentTypes.CustomFieldEntryView extends Backbone.View
tagName: 'li'
className: 'custom-field'
events:
'click a.toggle': 'toggle'
'click a.remove': 'remove'
initialize: ->
@inverse_of_list = @options.parent_view.options.inverse_of_list
@model.bind 'change', (custom_field) =>
@switch_to_type() if @model.hasChanged('type')
@fetch_inverse_of_list() if @model.hasChanged('class_name') && @model.get('class_name')?
render: ->
$(@el).html(ich.custom_field_entry(@model.toJSON()))
@fetch_inverse_of_list() unless @model.isNew()
Backbone.ModelBinding.bind @, all: 'class'
@make_fields_editable()
@enable_behaviours()
@switch_to_type()
return @
enable_behaviours: ->
required_input = @$('.required-input input[type=checkbox]')
required_input.checkToggle(on_label: required_input.attr('data-on-label'), off_label: required_input.attr('data-off-label'))
@$('li.input.toggle input[type=checkbox]').checkToggle()
@render_select_options_view()
switch_to_type: ->
@$('li.input.extra').hide() # reset
switch @model.get('type')
when 'select'
@$('li.input.select-options').show()
when 'text'
@$('li.input.text-formatting').show()
when 'belongs_to'
@$('li.input.localized').hide()
@$('li.input.class-name').show()
when 'has_many', 'many_to_many'
@$('li.input.localized').hide()
@$('li.input.class-name').show()
@$('li.input.inverse-of').show()
@$('li.input.ui-enabled').show()
fetch_inverse_of_list: ->
@$('li.input.inverse-of select option').remove()
list = @inverse_of_list[@model.get('type')] || []
_.each list, (data) =>
if data.class_name == @model.get('class_name')
option = new Option(data.label, data.name, data.name == @model.get('inverse_of') || list.length == 1)
@$('li.input.inverse-of select').append(option)
# by default, select the first option
if !@model.get('inverse_of')? && list.length > 0
@model.set
inverse_of: list[0].name
render_select_options_view: ->
@select_options_view = new Locomotive.Views.ContentTypes.SelectOptionsView
model: @model
collection: @model.get('select_options')
@$('#content_type_contents_custom_field_select_options_input').append(@select_options_view.render().el)
make_fields_editable: ->
@$('.label-input input[type=text], .type-input select').editableField()
toggle: (event) ->
event.stopPropagation() & event.preventDefault()
form = @$('ol')
if form.is(':hidden')
@$('a.toggle').addClass('open')
form.slideDown()
else
@$('a.toggle').removeClass('open')
form.slideUp()
show_error: (message) ->
html = $("<span class=\"inline-errors\">#{message}</span>")
@$('.required-input').after(html)
remove: (event) ->
event.stopPropagation() & event.preventDefault()
if confirm($(event.target).attr('data-confirm'))
@$('.label-input input[type=text], .type-input select').editableField('destroy')
super()
@options.parent_view.remove_entry(@model, @)

View File

@ -1,94 +0,0 @@
Locomotive.Views.ContentTypes ||= {}
class Locomotive.Views.ContentTypes.CustomFieldsView extends Backbone.View
tagName: 'div'
className: 'list'
_entry_views = []
events:
'click .new-entry a.add': 'add_entry'
'keypress .new-entry input[type=text]': 'add_on_entry_from_enter'
initialize: ->
_.bindAll(@, 'refresh_position_entries')
render: ->
$(@el).html(ich.custom_fields_list(@model.toJSON()))
@render_entries()
@make_list_sortable()
return @
make_list_sortable: ->
@sortable_list = @$('> ul').sortable
handle: '.handle'
items: 'li.custom-field'
axis: 'y'
update: @refresh_position_entries
refresh_position_entries: ->
_.each @_entry_views, (view) ->
view.model.set position: $(view.el).index()
find_entry_view: (key) ->
_.find @_entry_views, (view) ->
if key.length > 3
view.model.id == key
else
view.model.get('position') == parseInt(key)
add_entry: (event) ->
event.stopPropagation() & event.preventDefault()
labelInput = @$('> .new-entry input[name=label]')
typeInput = @$('> .new-entry select')
if labelInput.val() != ''
custom_field = new Locomotive.Models.CustomField label: labelInput.val(), type: typeInput.val()
@model.get('entries_custom_fields').add(custom_field)
@_insert_entry(custom_field)
@$('> .empty').hide()
@sortable_list.sortable('refresh')
labelInput.val('') # reset for further entries
add_on_entry_from_enter: (event) ->
return if event.keyCode != 13
@add_entry(event)
remove_entry: (custom_field, view) ->
if custom_field.isNew()
@model.get('entries_custom_fields').remove(custom_field)
else
custom_field.set _destroy: true
@_entry_views = _.reject @_entry_views, (_view) -> _view == view
@refresh_position_entries()
@$('> .empty').show() if @_entry_views.length == 0
render_entries: ->
if @model.get('entries_custom_fields').length == 0
@$('> .empty').show()
else
@model.get('entries_custom_fields').each (custom_field) =>
@_insert_entry(custom_field)
_insert_entry: (custom_field) ->
view = new Locomotive.Views.ContentTypes.CustomFieldEntryView model: custom_field, parent_view: @
(@_entry_views ||= []).push(view)
@$('> ul').append(view.render().el)
@refresh_position_entries()

View File

@ -1,14 +0,0 @@
Locomotive.Views.ContentTypes ||= {}
class Locomotive.Views.ContentTypes.EditView extends Locomotive.Views.ContentTypes.FormView
save: (event) ->
@save_in_ajax event, on_success: (response, xhr) =>
_.each response.entries_custom_fields, (data) =>
custom_field = @model.get('entries_custom_fields').detect (entry) => entry.get('name') == data.name
if custom_field.isNew() # assign an id for each new custom field
custom_field.set id: data._id, _id: data._id

View File

@ -1,11 +0,0 @@
Locomotive.Views.ContentTypes ||= {}
class Locomotive.Views.ContentTypes.NewView extends Locomotive.Views.ContentTypes.FormView
save: (event) ->
@save_in_ajax event,
on_success: (response, xhr) ->
window.location.href = xhr.getResponseHeader('location')
enable_liquid_editing: ->
true # do nothing

View File

@ -1,85 +0,0 @@
Locomotive.Views.ContentTypes ||= {}
class Locomotive.Views.ContentTypes.SelectOptionsView extends Backbone.View
tagName: 'div'
className: 'list'
events:
'click a.add': 'add_entry'
'click span.name': 'edit_entry'
'click a.remove': 'remove_entry'
initialize: ->
_.bindAll(@, 'refresh_position_entries', '_insert_entry')
@collection.bind 'add', @_insert_entry
render: ->
$(@el).html(ich.select_options_list())
@prompt_message = @$('> ul').attr('data-prompt')
@render_entries()
@make_list_sortable()
return @
render_entries: ->
@collection.each @_insert_entry
make_list_sortable: ->
@sortable_list = @$('> ul').sortable
handle: 'a.drag'
items: 'li.entry'
update: @refresh_position_entries
refresh_position_entries: ->
@$('> ul li.entry').each (index, view_dom) =>
select_option = @collection.getByCid($(view_dom).attr('data-cid'))
select_option.set position: index
add_entry: (event) ->
event.stopPropagation() & event.preventDefault()
name = prompt(@prompt_message)
if name != ''
@collection.add [{ name: name }]
edit_entry: (event) ->
event.stopPropagation() & event.preventDefault()
span = $(event.target)
view_dom = span.closest('li')
select_option = @collection.getByCid(view_dom.attr('data-cid'))
if (name = prompt(@prompt_message, select_option.get('name'))) != ''
select_option.set(name: name)
span.html(name)
remove_entry: (event) ->
event.stopPropagation() & event.preventDefault()
link = $(event.target)
view_dom = link.closest('li')
select_option = @collection.getByCid(view_dom.attr('data-cid'))
if confirm(link.attr('date-confirm'))
if select_option.isNew()
@collection.remove(select_option)
else
select_option.set _destroy: true
view_dom.remove()
_insert_entry: (select_option) ->
view_dom = ich.select_option_entry(select_option.toJSON())
view_dom.attr('data-cid', select_option.cid)
@$('> ul').append(view_dom)
@refresh_position_entries

View File

@ -1,83 +0,0 @@
#= require ../shared/form_view
#= require ../sites/domains_view
Locomotive.Views.CurrentSite ||= {}
class Locomotive.Views.CurrentSite.EditView extends Locomotive.Views.Shared.FormView
el: '#content'
events:
'submit': 'save'
initialize: ->
@model = new Locomotive.Models.CurrentSite(@options.site)
Backbone.ModelBinding.bind @, checkbox: 'class'
render: ->
super()
@add_toggle_mode_for_locales()
@make_locales_sortable()
@render_domains()
@render_memberships()
@enable_liquid_editing()
add_toggle_mode_for_locales: ->
@$('#site_locales_input .list input[type=checkbox]').bind 'change', (event) ->
el = $(event.target)
if el.is(':checked')
el.closest('.entry').addClass('selected')
else
el.closest('.entry').removeClass('selected')
make_locales_sortable: ->
@sortable_locales_list = @$('#site_locales_input .list').sortable
items: '.entry'
tolerance: 'pointer'
update: =>
list = _.map @$('#site_locales_input .list input:checked'), (el) => $(el).val()
@model.set locales: list
render_domains: ->
@domains_view = new Locomotive.Views.Sites.DomainsView model: @model, errors: @options.errors
@$('#site_domains_input label').after(@domains_view.render().el)
render_memberships: ->
@memberships_view = new Locomotive.Views.Sites.MembershipsView model: @model
@$('#site_memberships_input').append(@memberships_view.render().el)
enable_liquid_editing: ->
if($('#site_robots_txt').length)
input = @$('#site_robots_txt')
@editor = CodeMirror.fromTextArea input.get()[0],
mode: 'liquid'
autoMatchParens: false
lineNumbers: false
passDelay: 50
tabMode: 'shift'
theme: 'default'
onChange: (editor) => @model.set(robots_txt: editor.getValue())
save: (event) ->
if @model.includes_domain(window.location.host)
@save_in_ajax(event)
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

@ -1,24 +0,0 @@
Locomotive.Views.EditableElements ||= {}
class Locomotive.Views.EditableElements.ControlView extends Backbone.View
tagName: 'li'
className: 'control input'
render: ->
$(@el).html(ich.editable_control_input(@model.toJSON()))
@bind_model()
return @
after_render: ->
# do nothing
refresh: ->
@bind_model()
bind_model: ->
Backbone.ModelBinding.bind @, { select: 'class' }

View File

@ -1,83 +0,0 @@
Locomotive.Views.EditableElements ||= {}
class Locomotive.Views.EditableElements.EditAllView extends Backbone.View
id: 'editable-elements'
tagName: 'div'
_editable_elements_views: []
render: ->
window.bar = @
if @collection.isEmpty()
$(@el).hide()
else
@blocks = @collection.blocks()
$(@el).html(ich.editable_elements_edit(blocks: @blocks))
@render_elements()
@enable_nav()
return @
after_render: ->
_.each @_editable_elements_views, (view) => view.after_render()
refresh: ->
_.each @_editable_elements_views, (view) =>
view.model = @collection.get(view.model.get('id'))
view.refresh()
unbind_model: ->
_.each @_editable_elements_views, (view) => Backbone.ModelBinding.unbind(view)
render_elements: ->
index = 0
_.each @blocks, (block) =>
list = @collection.by_block block.name
_.each list, (element) =>
element.set(index: index)
view_class = switch element.get('type')
when 'EditableShortText' then Locomotive.Views.EditableElements.ShortTextView
when 'EditableLongText' then Locomotive.Views.EditableElements.LongTextView
when 'EditableFile' then Locomotive.Views.EditableElements.FileView
when 'EditableControl' then Locomotive.Views.EditableElements.ControlView
view = new view_class(model: element)
@$("#block-#{block.index} > fieldset > ol").append(view.render().el)
@_editable_elements_views.push(view)
index += 1
enable_nav: ->
@$('.nav a').click (event) =>
event.stopPropagation() & event.preventDefault()
link = $(event.target)
index = parseInt(link.attr('href').match(/block-(.+)/)[1])
@$('.wrapper ul li.block').hide()
@$("#block-#{index}").show()
@_hide_last_separator()
link.parent().find('.on').removeClass('on')
link.addClass('on')
_hide_last_separator: ->
_.each @$('fieldset'), (fieldset) =>
$(fieldset).find('li.last').removeClass('last')
$(_.last($(fieldset).find('li.input:visible'))).addClass('last')
remove: ->
_.each @_editable_elements_views, (view) => view.remove()
@_editable_elements_views.length = 0
super

View File

@ -1,74 +0,0 @@
Locomotive.Views.EditableElements ||= {}
class Locomotive.Views.EditableElements.FileView extends Backbone.View
tagName: 'li'
className: 'file input'
states:
change: false
delete: false
events:
'click a.change': 'toggle_change'
'click a.delete': 'toggle_delete'
render: ->
$(@el).html(ich.editable_file_input(@model.toJSON()))
# only in HTML 5
@$('input[type=file]').bind 'change', (event) =>
input = $(event.target)[0]
if input.files?
@model.set(source: input.files[0])
return @
after_render: ->
# do nothing
refresh: ->
@$('input[type=file]').unbind 'change'
@states = { 'change': false, 'delete': false }
@render()
toggle_change: (event) ->
@_toggle event, 'change',
on_change: =>
@$('a:first').hide() & @$('input[type=file]').show() & @$('a.delete').hide()
on_cancel: =>
@model.set(source: null)
@$('a:first').show() & @$('input[type=file]').val('').hide() & @$('a.delete').show()
toggle_delete: (event) ->
@_toggle event, 'delete',
on_change: =>
@$('a:first').addClass('deleted') & @$('a.change').hide()
@$('input[type=hidden].remove-flag').val('1')
@model.set('remove_source': true)
on_cancel: =>
@$('a:first').removeClass('deleted') & @$('a.change').show()
@$('input[type=hidden].remove-flag').val('0')
@model.set('remove_source': false)
_toggle: (event, state, options) ->
event.stopPropagation() & event.preventDefault()
button = $(event.target)
label = button.attr('data-alt-label')
unless @states[state]
options.on_change()
else
options.on_cancel()
button.attr('data-alt-label', button.html())
button.html(label)
@states[state] = !@states[state]
remove: ->
@$('input[type=file]').unbind 'change'
super

View File

@ -1,36 +0,0 @@
#= require ./short_text_view
Locomotive.Views.EditableElements ||= {}
class Locomotive.Views.EditableElements.LongTextView extends Backbone.View
tagName: 'li'
className: 'text input html'
render: ->
$(@el).html(ich.editable_text_input(@model.toJSON()))
return @
after_render: ->
settings = _.extend {}, @tinymce_settings(),
oninit: ((editor) =>
$.cmd 'S', (() =>
@model.set(content: editor.getBody().innerHTML)
$(@el).parents('form').trigger('submit')
), [], ignoreCase: true, document: editor.dom.doc),
onchange_callback: (editor) =>
@model.set(content: editor.getBody().innerHTML)
@$('textarea').tinymce(settings)
tinymce_settings: ->
window.Locomotive.tinyMCE.defaultSettings
refresh: ->
# do nothing
remove: ->
@$('textarea').tinymce().destroy()
super

View File

@ -1,22 +0,0 @@
Locomotive.Views.EditableElements ||= {}
class Locomotive.Views.EditableElements.ShortTextView extends Backbone.View
tagName: 'li'
className: 'text input short'
render: ->
$(@el).html(ich.editable_text_input(@model.toJSON()))
@$('textarea').bind 'keyup', (event) =>
input = $(event.target)
@model.set(content: input.val())
return @
after_render: ->
# do nothing
refresh: ->
# do nothing

View File

@ -1,103 +0,0 @@
Locomotive.Views.InlineEditor ||= {}
#= require ./toolbar_view
class Locomotive.Views.InlineEditor.ApplicationView extends Backbone.View
el: 'body'
initialize: ->
super
@iframe = @$('#page iframe')
_.bindAll(@, '_$')
@toolbar_view = new Locomotive.Views.InlineEditor.ToolbarView(target: @iframe)
@content_assets_picker_view = new Locomotive.Views.ContentAssets.PickerView(collection: new Locomotive.Models.ContentAssetsCollection())
render: ->
super
@enable_iframe_autoheight()
@toolbar_view.render()
@content_assets_picker_view.render()
enable_iframe_autoheight: ->
iframe = @iframe
iframe.load =>
if @_$('meta[name=inline-editor]').size() > 0
# bind the resize event. When the iFrame's size changes, update its height
iframe_content = iframe.contents()
iframe_content.resize ->
elem = $(this)
if elem.outerHeight(true) > iframe.outerHeight(true) # Resize the iFrame.
iframe.css height: elem.outerHeight(true)
# Resize the iFrame immediately.
iframe_content.resize()
else
@toolbar_view.show_status('disabled', true).hide_editing_mode_block()
# keep the user in the admin mode
@enhance_iframe_links()
set_page: (attributes) ->
@page = new Locomotive.Models.Page(attributes)
@toolbar_view.model = @page
@enhance_iframe()
@toolbar_view.refresh()
enhance_iframe: ->
_window = @iframe[0].contentWindow
_window.Aloha.settings.locale = window.locale
# set main window title
window.document.title = _window.document.title
# keep the user in the admin mode
@enhance_iframe_links _window.Aloha.jQuery
# notify the toolbar about changes
_window.Aloha.bind 'aloha-editable-deactivated', (event, editable) =>
@toolbar_view.notify editable.editable
enhance_iframe_links: (_jQuery) ->
toolbar_view = @toolbar_view
_jQuery ||= @_$
_jQuery('a').each ->
link = _jQuery(this)
url = link.attr('href')
if url? && url.indexOf('#') != 0 && /^(www|http)/.exec(url) == null && /(\/_edit)$/.exec(url) == null && /^\/sites\//.exec(url) == null
url = '/index' if url == '/'
unless url.indexOf('_edit') > 0
if url.indexOf('?') > 0
link.attr('href', url.replace('?', '/_edit?'))
else
link.attr('href', "#{url}/_edit")
link.bind 'click', ->
toolbar_view.show_status 'loading'
window.history.pushState('Object', 'Title', link.attr('href').replace('_edit', '_admin'))
unique_dialog_zindex: ->
# returns the number of jQuery UI modals created in order to set a valid zIndex for each of them.
# Each modal window should have a different zIndex, otherwise there will be conflicts between them.
window.Locomotive.jQueryModals ||= 0
1050 + window.Locomotive.jQueryModals++
_$: (selector) ->
$(selector, @iframe[0].contentWindow.document)

View File

@ -1,131 +0,0 @@
Locomotive.Views.InlineEditor ||= {}
class Locomotive.Views.InlineEditor.ToolbarView extends Backbone.View
el: '#toolbar .inner'
events:
'change .editing-mode input[type=checkbox]': 'toggle_editing_mode'
'click .back a': 'back'
'click .element-actions a.save': 'save_changes'
'click .element-actions a.cancel': 'cancel_changes'
render: ->
super
@enable_editing_mode_checkbox()
@enable_content_locale_picker()
@
notify: (aloha_editable) ->
window.bar = aloha_editable
element_id = aloha_editable.obj.attr('data-element-id')
@model.get('editable_elements').get(element_id).set
content: aloha_editable.getContents()
@$('.element-actions').show()
@hide_editing_mode_block()
show_status: (status, growl) ->
growl ||= false
message = @$('h1').attr("data-#{status}-status")
@$('h1').html(message).removeClass().addClass(status)
$.growl('error', message) if growl
@
save_changes: (event) ->
event.stopPropagation() & event.preventDefault()
previous_attributes = _.clone @model.attributes
@model.save {},
success: (model, response, xhr) =>
model.attributes = previous_attributes
@$('.element-actions').hide()
@show_editing_mode_block()
error: (model, xhr) =>
@$('.element-actions').hide()
cancel_changes: (event) ->
event.stopPropagation() & event.preventDefault()
@options.target[0].contentWindow.location.href = @options.target[0].contentWindow.location.href
back: (event) ->
event.stopPropagation() & event.preventDefault()
if @model
window.location.href = @model.get('edit_url')
else
window.location.href = window.Locomotive.mounted_on + '/pages'
show_editing_mode_block: ->
@$('.editing-mode').show()
hide_editing_mode_block: ->
@$('.editing-mode').hide()
toggle_editing_mode: (event) ->
return if @editable_elements() == null
if $(event.target).is(':checked')
@editable_elements().aloha()
else
@editable_elements().removeClass('aloha-editable-highlight').mahalo()
editable_elements: ->
if @options.target[0].contentWindow.Aloha
@options.target[0].contentWindow.Aloha.jQuery('.editable-long-text, .editable-short-text')
else
null
enable_editing_mode_checkbox: ->
@$('.editing-mode input[type=checkbox]').checkToggle
on_label_color: '#fff'
off_label_color: '#bbb'
enable_content_locale_picker: ->
_window = @options.target[0].contentWindow
link = @$('#content-locale-picker-link')
picker = $('#content-locale-picker')
return if picker.size() == 0
link.bind 'click', (event) ->
event.stopPropagation() & event.preventDefault()
picker.toggle()
picker.find('li').bind 'click', (event) =>
current = @get_locale_attributes(link)
selected = @get_locale_attributes($(event.target).closest('li'))
@set_locale_attributes(link, selected)
@set_locale_attributes($(event.target).closest('li'), current)
picker.toggle()
window.content_locale = selected[1]
_window.location.href = '/' + @model.get('localized_fullpaths')[selected[1]] + '/_edit'
get_locale_attributes: (context) ->
[context.find('img').attr('src'), context.find('span.text').html()]
set_locale_attributes: (context, values) ->
context.find('img').attr('src', values[0])
context.find('span.text').html(values[1])
refresh: ->
@$('h1').html(@model.get('title')).removeClass()
if @$('.editing-mode input[type=checkbox]').is(':checked')
@$('.editing-mode div.switchArea').trigger('click')
@$('.element-actions').hide()
@show_editing_mode_block()

View File

@ -1,24 +0,0 @@
#= require ../shared/form_view
Locomotive.Views.MyAccount ||= {}
class Locomotive.Views.MyAccount.EditView extends Locomotive.Views.Shared.FormView
el: '#content'
events:
'submit': 'save'
initialize: ->
@model = new Locomotive.Models.CurrentAccount(@options.account)
Backbone.ModelBinding.bind @
render: ->
super()
save: (event) ->
if @model.get('locale') == window.locale
@save_in_ajax(event)

View File

@ -1,149 +0,0 @@
#= require ../shared/form_view
Locomotive.Views.Pages ||= {}
class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
el: '#content'
events:
'change #page_parent_id': 'change_page_url'
'click a#image-picker-link': 'open_image_picker'
'submit': 'save'
initialize: ->
_.bindAll(@, 'insert_image')
@model = new Locomotive.Models.Page(@options.page)
@touched_url = false
@image_picker_view = new Locomotive.Views.ThemeAssets.ImagePickerView
collection: new Locomotive.Models.ThemeAssetsCollection()
on_select: @insert_image
@image_picker_view.render()
Backbone.ModelBinding.bind @
@editable_elements_view = new Locomotive.Views.EditableElements.EditAllView(collection: @model.get('editable_elements'))
render: ->
super()
# slugify the slug field from title
@slugify_title()
# the url gets modified by different ways so reflect the changes in the UI
@listen_for_url_changes()
# enable response type
@enable_response_type_select()
# enable check boxes
@enable_templatized_checkbox()
@enable_redirect_checkbox()
@enable_other_checkboxes()
# liquid code textarea
@enable_liquid_editing()
# editable elements
@render_editable_elements()
return @
open_image_picker: (event) ->
event.stopPropagation() & event.preventDefault()
@image_picker_view.editor = @editor
@image_picker_view.fetch_assets()
insert_image: (path) ->
text = "{{ '#{path}' | theme_image_url }}"
@editor.replaceSelection(text)
@image_picker_view.close()
enable_liquid_editing: ->
input = @$('#page_raw_template')
if input.size() > 0
@editor = CodeMirror.fromTextArea input.get()[0],
mode: 'liquid'
autoMatchParens: false
lineNumbers: false
passDelay: 50
tabMode: 'shift'
theme: 'default'
onChange: (editor) => @model.set(raw_template: editor.getValue())
after_inputs_fold: ->
@editor.refresh()
render_editable_elements: ->
@$('.formtastic fieldset.inputs:first').before(@editable_elements_view.render().el)
@editable_elements_view.after_render()
# Remove the editable elements and rebuild them
reset_editable_elements: ->
@editable_elements_view.remove()
@editable_elements_view.collection = @model.get('editable_elements')
@render_editable_elements()
# Just re-connect the model and the views (+ redraw the file fields)
refresh_editable_elements: ->
@editable_elements_view.unbind_model()
@editable_elements_view.collection = @model.get('editable_elements')
@editable_elements_view.refresh()
slugify_title: ->
@$('#page_title').slugify(target: @$('#page_slug'))
@$('#page_slug').bind 'change', ((event) => @touched_url = true)
listen_for_url_changes: ->
setInterval (=> (@change_page_url() & @touched_url = false) if @touched_url), 2000
change_page_url: ->
$.rails.ajax
url: @$('#page_slug').attr('data-url')
type: 'get'
dataType: 'json'
data: { parent_id: @$('#page_parent_id').val(), slug: @$('#page_slug').val() }
success: (data) =>
@$('#page_slug_input .inline-hints').html(data.url).effect('highlight')
if data.templatized_parent
@$('li#page_slug_input').show()
@$('li#page_templatized_input, li#page_target_klass_name_input').hide()
else
@$('li#page_templatized_input').show() unless @model.get('redirect')
enable_response_type_select: ->
@$('li#page_response_type_input').change (event) =>
if $(event.target).val() == 'text/html'
@$('li#page_redirect_input, li#page_redirect_url_input').show()
else
@model.set redirect: false
@$('li#page_redirect_input, li#page_redirect_url_input').hide()
enable_templatized_checkbox: ->
@_enable_checkbox 'templatized',
features: ['slug', 'redirect', 'listed']
on_callback: =>
@$('li#page_target_klass_name_input').show()
off_callback: =>
@$('li#page_target_klass_name_input').hide()
@$('li#page_templatized_input').hide() if @model.get('templatized_from_parent') == true
enable_redirect_checkbox: ->
@_enable_checkbox 'redirect',
features: ['templatized', 'cache_strategy']
on_callback: =>
@$('li#page_redirect_url_input').show()
off_callback: =>
@$('li#page_redirect_url_input').hide()
enable_other_checkboxes: ->
_.each ['published', 'listed'], (exp) =>
@$('li#page_' + exp + '_input input[type=checkbox]').checkToggle()

View File

@ -1,28 +0,0 @@
Locomotive.Views.Pages ||= {}
class Locomotive.Views.Pages.EditView extends Locomotive.Views.Pages.FormView
save: (event) ->
event.stopPropagation() & event.preventDefault()
form = $(event.target).trigger('ajax:beforeSend')
@clear_errors()
@model.save {},
success: (model, response, xhr) =>
form.trigger('ajax:complete')
model._normalize()
if model.get('template_changed') == true
@reset_editable_elements()
else
@refresh_editable_elements()
error: (model, xhr) =>
form.trigger('ajax:complete')
errors = JSON.parse(xhr.responseText)
@show_errors errors

View File

@ -1,11 +0,0 @@
Locomotive.Views.Pages ||= {}
class Locomotive.Views.Pages.IndexView extends Backbone.View
el: '#content'
render: ->
@index_view = new Locomotive.Views.Pages.ListView()
@index_view.render()
return @

View File

@ -1,40 +0,0 @@
Locomotive.Views.Pages ||= {}
class Locomotive.Views.Pages.ListView extends Backbone.View
el: '#pages-list'
render: ->
@make_foldable()
@make_sortable()
return @
make_foldable: ->
@$('ul.folder img.toggler').toggleMe()
make_sortable: ->
self = @
@$('ul.folder').sortable
handle: 'em'
axis: 'y'
update: (event, ui) -> self.call_sort $(@)
call_sort: (folder) ->
$.rails.ajax
url: folder.attr('data-url')
type: 'post'
dataType: 'json'
data:
children: (_.map folder.sortable('toArray'), (el) -> el.replace('item-', ''))
_method: 'put'
success: @.on_successful_sort
error: @.on_failed_sort
on_successful_sort: (data, status, xhr) ->
$.growl('success', xhr.getResponseHeader('X-Message'))
on_failed_sort: (data, status, xhr) ->
$.growl('error', xhr.getResponseHeader('X-Message'))

View File

@ -1,8 +0,0 @@
Locomotive.Views.Pages ||= {}
class Locomotive.Views.Pages.NewView extends Locomotive.Views.Pages.FormView
save: (event) ->
@save_in_ajax event,
on_success: (response, xhr) ->
window.location.href = xhr.getResponseHeader('location')

View File

@ -1,92 +0,0 @@
Locomotive.Views.Shared ||= {}
class Locomotive.Views.Shared.AssetPickerView extends Backbone.View
tag: 'div'
initialize: ->
_.bindAll(@, 'add_assets', 'add_asset', 'remove_asset')
@collection.bind('reset', @add_assets)
@collection.bind('add', @add_asset)
@collection.bind('remove', @remove_asset)
render: ->
$(@el).html(@template()())
@create_dialog()
return @
template: ->
# please overide template
fetch_assets: ->
# please overide fetch_assets
build_uploader: (el, link) ->
# please overide build_uploader
create_dialog: ->
@dialog ||= $(@el).dialog
autoOpen: false
modal: true
zIndex: window.application_view.unique_dialog_zindex()
width: 650,
create: (event, ui) =>
$(@el).prev().find('.ui-dialog-title').html(@$('h2').html())
@$('h2').remove()
actions = @$('.dialog-actions').appendTo($(@el).parent()).addClass('ui-dialog-buttonpane ui-widget-content ui-helper-clearfix')
actions.find('#close-link').click (event) => @close(event)
input = actions.find('input[type=file]')
link = actions.find('#upload-link')
@build_uploader(input, link)
open: (event, ui, extra) =>
$(@el).dialog('overlayEl').bind 'click', => @close()
open: ->
$(@el).dialog('open')
close: (event) ->
event.stopPropagation() & event.preventDefault() if event?
$(@el).dialog('overlayEl').unbind('click')
$(@el).dialog('close')
shake: ->
$(@el).parents('.ui-dialog').effect('shake', { times: 4 }, 100)
center: ->
$(@el).dialog('option', 'position', 'center')
add_assets: (collection) ->
collection.each (asset) =>
@add_asset(asset, true)
@_refresh()
add_asset: (asset, first) ->
# please overide add_asset (the 'first' param is to know if it comes from the first collection fetch)
remove_asset: (asset) ->
# please overide remove_asset
_move_to_last_asset: ->
limit = @$('ul.list li.clear').position()
@$('ul.list').animate(scrollTop: limit.top, 100) if limit?
_refresh: ->
if @collection.length == 0
@$('ul.list').hide() & @$('p.no-items').show()
else
@$('p.no-items').hide() & @$('ul.list').show()
@_on_refresh()
@center() if @dialog?
_on_refresh: ->
_reset: ->
# for nothing to do

View File

@ -1,88 +0,0 @@
Locomotive.Views.Shared ||= {}
Locomotive.Views.Shared.Fields ||= {}
class Locomotive.Views.Shared.Fields.FileView extends Backbone.View
tagName: 'span'
className: 'file'
states:
change: false
delete: false
events:
'click a.change': 'toggle_change'
'click a.delete': 'toggle_delete'
template: ->
ich["#{@options.name}_file_input"]
render: ->
url = @model.get("#{@options.name}_url") || ''
data =
filename: url.split('/').pop()
url: url
$(@el).html(@template()(data))
# only in HTML 5
@$('input[type=file]').bind 'change', (event) =>
input = $(event.target)[0]
if input.files?
name = $(input).attr('name')
hash = {}
hash[name.replace("#{@model.paramRoot}[", '').replace(/]$/, '')] = input.files[0]
@model.set(hash)
return @
refresh: ->
@$('input[type=file]').unbind 'change'
@states = { 'change': false, 'delete': false }
@render()
reset: ->
@model.set_attribute @options.name, null
@model.set_attribute "#{@options.name}_url", null
@refresh()
toggle_change: (event) ->
@_toggle event, 'change',
on_change: =>
@$('a:first').hide() & @$('input[type=file]').show() & @$('a.delete').hide()
on_cancel: =>
@$('a:first').show() & @$('input[type=file]').hide() & @$('a.delete').show()
toggle_delete: (event) ->
@_toggle event, 'delete',
on_change: =>
@$('a:first').addClass('deleted') & @$('a.change').hide()
@$('input[type=hidden].remove-flag').val('1')
@model.set_attribute("remove_#{@options.name}", true)
on_cancel: =>
@$('a:first').removeClass('deleted') & @$('a.change').show()
@$('input[type=hidden].remove-flag').val('0')
@model.set_attribute("remove_#{@options.name}", false)
_toggle: (event, state, options) ->
event.stopPropagation() & event.preventDefault()
button = $(event.target)
label = button.attr('data-alt-label')
unless @states[state]
options.on_change()
else
options.on_cancel()
button.attr('data-alt-label', button.html())
button.html(label)
@states[state] = !@states[state]
remove: ->
@$('input[type=file]').unbind 'change'
super

View File

@ -1,125 +0,0 @@
Locomotive.Views.Shared ||= {}
Locomotive.Views.Shared.Fields ||= {}
class Locomotive.Views.Shared.Fields.HasManyView extends Backbone.View
tagName: 'div'
className: 'list'
events:
'click p.actions a.add': 'open_new_entry_view'
'click ul span.actions a.edit': 'edit_entry'
'click ul span.actions a.remove': 'remove_entry'
template: ->
ich["#{@options.name}_list"]
entry_template: ->
ich["#{@options.name}_entry"]
initialize: ->
_.bindAll(@, 'refresh_position_entries')
@collection = @model.get(@options.name)
@build_target_entry_view()
render: ->
$(@el).html(@template()())
@insert_entries()
@make_entries_sortable()
return @
ui_enabled: ->
@template()?
insert_entries: ->
if @collection.length > 0
@collection.each (entry) => @insert_entry(entry)
else
@$('.empty').show()
insert_entry: (entry) ->
unless @collection.get(entry.get('_id'))?
@collection.add(entry)
@$('.empty').hide()
entry_html = $(@entry_template()(label: entry.get('_label')))
entry_html.data('data-entry-id', entry.id)
@$('> ul').append(entry_html)
make_entries_sortable: ->
@sortable_list = @$('> ul').sortable
handle: '.handle'
items: 'li'
axis: 'y'
update: @refresh_position_entries
refresh_position_entries: ->
@$('> ul > li').each (index, entry_html) =>
id = $(entry_html).data('data-entry-id')
entry = @collection.get(id)
entry.set_attribute "position_in_#{@options.inverse_of}", index
build_target_entry_view: ->
@target_entry_view = new Locomotive.Views.ContentEntries.PopupFormView
el: $("##{@options.name}-template-entry")
parent_view: @
model: @options.new_entry.clone() # by default, it does not matter
@target_entry_view.render()
edit_entry: (event) ->
event.stopPropagation() & event.preventDefault()
entry = @get_entry_from_element($(event.target))
@target_entry_view.reset(entry)
@target_entry_view.open()
update_entry: (entry) ->
entry_html = $(_.detect @$('> ul > li'), (_entry_html) -> $(_entry_html).data('data-entry-id') == entry.id)
@collection.get(entry.id).set(entry.attributes) # sync
new_entry_html = $(@entry_template()(label: entry.get('_label')))
new_entry_html.data('data-entry-id', entry.id)
entry_html.replaceWith(new_entry_html)
insert_or_update_entry: (entry) ->
if @collection.get(entry.id)?
@update_entry(entry)
else
@insert_entry(entry)
remove_entry: (event) ->
event.stopPropagation() & event.preventDefault()
if confirm($(event.target).attr('data-confirm'))
entry = @get_entry_from_element($(event.target))
entry.set _destroy: true
$(event.target).closest('li').remove()
@$('.empty').show() if @$('> ul > li').size() == 0
@refresh_position_entries()
open_new_entry_view: (event) ->
event.stopPropagation() & event.preventDefault()
@target_entry_view.reset(@options.new_entry.clone())
@target_entry_view.open()
get_entry_from_element: (element) =>
entry_html = $(element).closest('li')
id = $(entry_html).data('data-entry-id')
@collection.get(id)

Some files were not shown because too many files have changed in this diff Show More