refactoring of the import UI is done

This commit is contained in:
did 2011-12-11 23:33:38 +01:00
parent bbf0b0e083
commit 8271782284
9 changed files with 367 additions and 49 deletions

View File

@ -0,0 +1,47 @@
Locomotive.Views.Import ||= {}
class Locomotive.Views.Import.ShowView extends Backbone.View
el: '#content'
render: ->
super
@enable_updating()
enable_updating: ->
@updater = @$('#import-steps').smartupdater
url : @$('#import-steps').attr('data-url')
dataType: 'json'
minTimeout: 300,
@refresh_steps
refresh_steps: (data) =>
console.log 'refresh_steps: ....'
window.foo = data
window.bar = @
if data.step == 'done'
$('#import-steps li').addClass('done')
$.growl 'notice', @$('#import-steps').attr('data-success-message')
else
steps = ['site', 'content_types', 'assets', 'snippets', 'pages']
current_index = steps.indexOf(data.step) || 0
_.each steps, (step, index) =>
state = null
if index == current_index + 1 && data.failed then state = 'failed'
if (index <= current_index) then state = 'done'
@$("#import-steps li:eq(#{index})").addClass(state) if state?
if data.failed
$.growl 'alert', @$('#import-steps').attr('data-failure-message')
if data.step == 'done' || data.failed
@updater.smartupdater('stop')
remove: ->
super
@updater.smartupdater('stop') if @updater?

View File

@ -325,18 +325,21 @@ ul.list {
margin: 0px 200px;
li {
strong a { color: #b7baca; }
strong {
margin-left: 18px;
color: #b7baca;
}
.more .states {
position: relative;
top: 4px;
top: 7px;
height: 16px;
width: 16px;
background: transparent image-url("locomotive/list/icons/states.png") no-repeat 0 0;
}
&.done {
strong a { color: #1F82BC; }
strong { color: #1F82BC; }
.more .states {
background-position: 0 -16px;

View File

@ -7,6 +7,8 @@ module Locomotive
before_filter :authorize_import
respond_to :json, :only => :show
def show
@import = Locomotive::Import::Model.current(current_site)
respond_with @import
@ -30,36 +32,3 @@ module Locomotive
end
end
# begin
# Locomotive::Import::Job.run!(params[:zipfile], current_site, {
# :samples => Boolean.set(params[:samples]),
# :reset => Boolean.set(params[:reset])
# })
#
# flash[:notice] = t("fash.locomotive.import.create.#{Locomotive.config.delayed_job ? 'notice' : 'done'}")
#
# redirect_to Locomotive.config.delayed_job ? import_url : new_import_url
# rescue Exception => e
# logger.error "[Locomotive import] #{e.message} / #{e.backtrace}"
#
# @error = e.message
# flash[:alert] = t('fash.locomotive.import.create.alert')
#
# render 'new'
# end
# def show
# @job = Delayed::Job.where({ :job_type => 'import', :site_id => current_site.id }).last
#
# respond_to do |format|
# format.html do
# redirect_to new_import_url if @job.nil?
# end
# format.json { render :json => {
# :step => @job.nil? ? 'done' : @job.step,
# :failed => @job && @job.last_error.present?
# } }
# end
# end

View File

@ -3,7 +3,7 @@ module Locomotive
sections 'settings'
respond_to :json, :only => [:create]
respond_to :json, :only => [:create, :destroy]
def new
@site = Site.new

View File

@ -1,6 +1,3 @@
- content_for :head do
= include_javascripts :import
- title t('.title')
- content_for :submenu do
@ -10,7 +7,7 @@
%ul{ :id => 'import-steps', :class => 'list', :'data-url' => import_url(:json), :'data-success-message' => t('.messages.success'), :'data-failure-message' => t('.messages.failure') }
- %w(site content_types assets snippets pages).each do |step|
%li{ :id => "#{step}-step" }
%li.item{ :id => "#{step}-step" }
%strong= t(".steps.#{step}")
.more
.states

View File

@ -29,9 +29,8 @@ x edit my site
x snippets
x delete in ajax
x upload many files at once
- import/export
- export
- replace DJ by QU
x import/export
x export
- site picker
- content types
- change in main menu

View File

@ -47,15 +47,14 @@ module Locomotive
self.reset! if @options[:reset]
# %w(site content_types content_assets snippets pages).each do |step|
%w(site assets snippets pages).each do |step|
# %w(site content_types assets snippets pages).each do |step|
%w(site assets snippets pages).each do |step| # TODO (Did): unable content_types for now, waiting for its refactoring
if @options[:enabled][step] != false
"Locomotive::Import::#{step.camelize}".constantize.process(context, @options)
@worker.update_attributes :step => step if @worker
else
self.log "skipping #{step}"
end
sleep 10 # FIXME DEBUG PURPOSE
end
end

View File

@ -41,7 +41,6 @@ module Locomotive
## class methods ##
def self.create(attributes = {})
puts attributes.inspect
new(attributes).tap do |job|
if job.valid?
begin
@ -61,6 +60,15 @@ module Locomotive
}
end
def self.current(site)
job = Delayed::Job.where({ :job_type => 'import', :site_id => site.id }).last
{
:step => job.nil? ? 'done' : job.step,
:failed => job && job.last_error.present?
}
end
def self.name
'Import'
end

View File

@ -0,0 +1,296 @@
/**
* smartupdater - jQuery Plugin
*
* Version - 4.0.beta
* Copyright (c) 2010 - 2011 Vadim Kiryukhin
* vkiryukhin @ gmail.com
*
* http://www.eslinstructor.net/smartupdater/
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* USAGE:
*
* $("#myObject").smartupdater({
* url : "foo.php"
* }, function (data) {
* //process data here;
* }
* );
*
* Public functions:
* $("#myObject").smartupdater("stop")
* $("#myObject").smartupdater("restart");
* $("#myObject").smartupdater("setTimeout",timeout);
* $("#myObject").smartupdater("alterUrl"[,"foo.php"[,data]]);
* $("#myObject").smartupdater("alterCallback"[, foo]);
*
* Public Attributes:
* var status = $("#myObject").smartupdater("getState");
* var timeout = $("#myObject").smartupdater("getTimeout");
*
**/
(function($) {
var methods = {
init : function( options, callback) {
return this.each(function () {
var elem = this,
es = {};
elem.settings = jQuery.extend(true,{
url : '', // see jQuery.ajax for details
type : 'get', // see jQuery.ajax for details
data : '', // see jQuery.ajax for details
dataType : 'text', // see jQuery.ajax for details
minTimeout : 60000, // 1 minute
maxFailedRequests : 10, // max. number of consecutive ajax failures
maxFailedRequestsCb : false, // falure callback function
httpCache : false, // http cache
rCallback : false, // remote callback functions
selfStart : true, // start automatically after initializing
smartStop : { active: false, //disabled by default
monitorTimeout: 2500, // 2.5 seconds
minHeight: 1, // 1px
minWidth: 1 // 1px
}
}, options);
elem.smartupdaterStatus = {state:'',timeout:0};
es = elem.settings;
es.prevContent = '';
es.failedRequests = 0;
es.etag = '0';
es.lastModified = '0';
es.callback = callback;
es.origReq = {url:es.url,data:es.data,callback:callback};
es.stopFlag = false;
function start() {
/* check if element has been deleted and clean it up */
if(!$(elem).parents('body').length) {
clearInterval(elem.smartupdaterStatus.smartStop);
clearTimeout(elem.settings.h);
elem = {};
return;
}
$.ajax({
url : es.url,
type : es.type,
data : es.data,
dataType: es.dataType,
cache : false, // MUST be set to false to prevent IE caching issue.
success: function (data, statusText, xhr) {
var dataNotModified = false,
rCallback = false,
xSmart = jQuery.parseJSON(xhr.getResponseHeader("X-Smartupdater")),
xhrEtag, xhrLM;
if(xSmart) { // remote control
/* remote timeout */
es.minTimeout = xSmart.timeout ? xSmart.timeout : es.minTimeout;
/* remote callback */
rCallback = xSmart.callback ? xSmart.callback : false;
}
if(es.httpCache) { // http cache process here
xhrEtag = xhr.getResponseHeader("ETag");
xhrLM = xhr.getResponseHeader("Last-Modified");
dataNotModified = (es.etag == xhrEtag || es.lastModified == xhrLM) ? true : false;
es.etag = xhrEtag ? xhrEtag : es.etag;
es.lastModified = xhrLM ? xhrLM : es.lastModified;
}
if ( dataNotModified ||
es.prevContent == xhr.responseText ||
xhr.status == 304 ) { // data is not changed
if(!es.stopFlag) {
clearTimeout(es.h);
es.h = setTimeout(start, es.minTimeout);
}
} else { // data is changed
/* cache response data */
es.prevContent = xhr.responseText;
/* reset timeout */
if(!es.stopFlag) {
clearTimeout(es.h);
es.h = setTimeout(start, es.minTimeout);
}
/* run callback function */
if(es.rCallback && rCallback && es.rCallback.search(rCallback) != -1) {
window[rCallback](data);
} else {
es.callback(data);
}
}
elem.smartupdaterStatus.timeout = es.minTimeout;
es.failedRequests = 0;
},
error: function(xhr, textStatus, errorThrown) {
if ( ++es.failedRequests < es.maxFailedRequests ) {
/* increment falure counter and reset timeout */
if(!es.stopFlag) {
clearTimeout(es.h);
es.h = setTimeout(start, es.minTimeout);
elem.smartupdaterStatus.timeout = es.minTimeout;
}
} else {
/* stop smartupdater */
clearTimeout(es.h);
elem.smartupdaterStatus.state = 'OFF';
if( typeof(es.maxFailedRequestsCb)==='function') {
es.maxFailedRequestsCb(xhr, textStatus, errorThrown);
}
}
},
beforeSend: function(xhr, settings) {
if(es.httpCache) {
/* set http cache-related headers */
xhr.setRequestHeader("If-None-Match", es.etag );
xhr.setRequestHeader("If-Modified-Since", es.lastModified );
}
/* Feedback: Smartupdater sends it's current timeout to server */
xhr.setRequestHeader("X-Smartupdater", '{"timeout":"'+elem.smartupdaterStatus.timeout+'"}');
}
});
elem.smartupdaterStatus.state = 'ON';
}
es.fnStart = start;
if(es.selfStart) {
start();
}
if(es.smartStop.active) {
elem.smartupdaterStatus.smartStop = setInterval(function(){
// check if object has been deleted
if(!$(elem).parents('body').length) {
clearInterval(elem.smartupdaterStatus.smartStop);
clearTimeout(elem.settings.h);
elem = {};
return;
}
var $elem = $(elem);
var width = $elem.width(),
height = $elem.height(),
hidden = $elem.is(":hidden");
//element has been expanded, so smartupdater should be re-started.
if(!hidden && height > es.smartStop.minHeight && width > es.smartStop.minWidth
&& elem.smartupdaterStatus.state=="OFF") {
$elem.smartupdater("restart");
} else
//element has been minimized, so smartupdater should be stopped.
if( (hidden || height <= es.smartStop.minHeight || width <= es.smartStop.minWidth)
&& elem.smartupdaterStatus.state=="ON") {
$elem.smartupdater("stop");
}
},es.smartStop.monitorTimeout);
}
});
},// init()
stop : function () {
return this.each(function () {
this.settings.stopFlag = true;
clearTimeout(this.settings.h);
this.smartupdaterStatus.state = 'OFF';
});
},
restart : function () {
return this.each(function () {
this.settings.stopFlag = false;
clearTimeout(this.settings.h);
this.settings.failedRequests = 0;
this.settings.etag = "0";
this.settings.lastModified = "0";
this.settings.fnStart();
})
},
setTimeout : function (period) {
return this.each(function () {
clearTimeout(this.settings.h);
this.settings.minTimeout = period;
this.settings.fnStart();
});
},
alterCallback : function (callback) {
return this.each(function () {
this.settings.callback = callback ? callback : this.settings.origReq.callback;
});
},
alterUrl : function (url,data) {
return this.each(function () {
this.settings.url = url ? url : this.settings.origReq.url;
this.settings.data = data ? data : this.settings.origReq.data;
});
},
getTimeout : function () {
return this[0].smartupdaterStatus.timeout;
},
getState : function () {
return this[0].smartupdaterStatus.state;
}
}; //methods
jQuery.fn.smartupdater = function (options, callback) {
if ( methods[options] ) {
return methods[ options ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof options === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + options + ' does not exist on jQuery.tooltip' );
}
};
})(jQuery);