package Solstice::Controller::Remote;
=head1 NAME
Solstice::Controller::Remote - The superclass for all AJAX-called controllers.
=cut
use base qw(Solstice::Controller);
use strict;
use warnings;
use 5.006_000;
use JSON;
use Solstice::View::Remote;
use Solstice::ButtonService;
use Solstice::Session;
use Solstice::CGI;
use constant TRUE => 1;
use constant FALSE => 0;
=over 4
=cut
sub new {
my $obj = shift;
my $self = $obj->SUPER::new(@_);
$self->{'_actions'} = [];
return $self;
}
sub runApp {
my $self = shift;
my $screen = shift;
#get input values
my $app_key = param('solstice_session_app_key');
my $app = param('solstice_remote_app');
my $action = param('solstice_remote_action');
unless( $app_key && $app && $action ){
warn "Badly formed remote call\n";
return;
}
#prepare the js data
my $data = param('solstice_remote_data');
my $json = JSON->new();
$data = $json->jsonToObj($data);
#Okay, what controller do we run?
my $config = Solstice::Configure->new();
my $controller_name = $config->getRemoteDefs()->{$app}{$action};
if(defined $controller_name){
$self->loadModule($controller_name);
#init the controller
my $controller = $controller_name->new($data);
$controller->setSessionAppKey($app_key);
#Run the remote lifecycle with validation
if($controller->validate()){
$controller->runRemote();
}else{
$controller->abortRemote();
}
$controller->addMessages();#adds any message service messages
#gather the info created by the controller for the view
my $view = Solstice::View::Remote->new($data);
$view->setActions($controller->getActions());
$view->paint($screen);
$controller->_commitButtonService();
Solstice::Server->new()->setContentType("text/xml; charset=UTF-8");
return TRUE;
}else{
warn "Call to undefined remote controller \"$app:$action\"\n";
}
}
sub validate {
return TRUE;
}
sub runRemote {
return TRUE;
}
sub abortRemote {
return TRUE;
}
=item addAction($javascript);
Adds a javascript action that will be evaled by the client.
=cut
sub addAction {
my $self = shift;
push @{$self->{'_actions'}}, {type => 'action', content => shift}
}
=item addBlockReplacement($id, $content)
Creates a new element of $content. This new element will replace the element with id $id. $content needs to contain any block structure you wish to maintain, such as
...
.
=cut
sub addBlockReplacement {
my $self = shift;
my $block_id = shift;
my $content = shift;
push @{$self->{'_actions'}}, {
type => 'replacement',
block_id => $block_id,
content => $content,
};
}
=item addContentUpdate($id, $content)
Finds the page element with the given id, and replaces its content with the value provided.
=cut
sub addContentUpdate {
my $self = shift;
my $block_id = shift;
my $content = shift;
push @{$self->{'_actions'}}, {
type => 'update',
block_id => $block_id,
content => $content,
};
}
=item setPopinContent($title, $content)
Configure a popin with the given content.
=cut
sub setPopinContent {
my $self = shift;
my $title = shift;
my $body = shift;
$self->addContentUpdate('solstice_popin_title', $title);
$self->addContentUpdate('solstice_popin_content', $body);
return TRUE;
}
sub getActions {
my $self = shift;
return $self->{'_actions'};
}
sub setSessionAppKey {
my $self = shift;
$self->{'_session_app_key'} = shift;
}
sub getSessionAppKey {
my $self = shift;
return $self->{'_session_app_key'};
}
sub initStatefulAPI {
my $self = shift;
return if $self->{'_stateful_init'};
my $session = Solstice::Session->new();
die "Solstice Exception: User with no session making Remote calls\n" unless $session->hasSession();
#To make sure we use the subsession of the page that is running the remotes,
#we pretend that a button was used that ties this click to the appropriate
#subsession. That way, when loadSubsession() runs, it will pull that particular
#subsession - falling back on the chain if needed
my $button_service = Solstice::ButtonService->new();
my $button = Solstice::Button->new();
$button->_setSubsessionID(param('solstice_subsession_id'));
$button_service->set('selected_button', $button);
$session->loadSubsession($self->_getChainID());
my $application = $session->get($self->getSessionAppKey()) || undef;
die "No application in user session for Remote call\n" unless $application;
my $app_class = ref $application;
$self->loadModule($app_class);
$self->{"_application"} = $application;
$self->{'_stateful_init'} = TRUE;
}
sub getSession {
my $self = shift;
$self->initStatefulAPI();
return Solstice::Session->new();
}
sub getApplication {
my $self = shift;
$self->initStatefulAPI();
return $self->{'_application'};
}
sub getButtonService {
my $self = shift;
$self->initStatefulAPI();
return Solstice::ButtonService->new();
}
sub addMessages {
my $self = shift;
my $msg_service = $self->getMessageService();
my @messages = $msg_service->getMessages();
if((scalar @messages) || $msg_service->isScreenClear()){
my $message_service_view = Solstice::View::MessageService->new();
my $msg_content;
$message_service_view->paint(\$msg_content);
$self->addBlockReplacement('sol_message_service_container',$msg_content);
}
return TRUE;
}
sub _commitButtonService {
my $self = shift;
if( $self->{'_stateful_init'} ){
my $button_service = Solstice::ButtonService->new();
$button_service->commit();
}
}
sub _getChainID {
my $self = shift;
return param('solstice_subsession_chain');
}
1;
__END__
=back
=head1 COPYRIGHT
Copyright 1998-2007 Office of Learning Technologies, University of Washington
Licensed under the Educational Community License, Version 1.0 (the "License");
you may not use this file except in compliance with the License. You may obtain
a copy of the License at: http://www.opensource.org/licenses/ecl1.php
Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
=cut