| 1 | # Copyright 2007 Six Apart. This code cannot be redistributed without |
|---|
| 2 | # permission from www.sixapart.com. For more information, consult your |
|---|
| 3 | # Movable Type license. |
|---|
| 4 | # |
|---|
| 5 | # $Id$ |
|---|
| 6 | |
|---|
| 7 | package MT::Plugin::iMT; |
|---|
| 8 | |
|---|
| 9 | use MT 4; |
|---|
| 10 | use base qw( MT::Plugin ); |
|---|
| 11 | |
|---|
| 12 | my $enabled = 0; |
|---|
| 13 | our $VERSION = '1.02'; |
|---|
| 14 | my $plugin = __PACKAGE__->new({ |
|---|
| 15 | name => "iPhone / iPod touch UI Support", |
|---|
| 16 | author_name => "<a href='http://www.iwalt.com/'>Walt Dickinson</a>, <a href='http://bradchoate.com/'>Brad Choate</a>", |
|---|
| 17 | description => "Provides an iPhone and iPod touch-friendly UI for Movable Type. Once enabled, navigate to your MT installation from your iPhone (or iPod touch) to use this interface.", |
|---|
| 18 | version => $VERSION, |
|---|
| 19 | registry => { |
|---|
| 20 | applications => { |
|---|
| 21 | cms => { |
|---|
| 22 | methods => { |
|---|
| 23 | iphone_main => \&iphone_main, |
|---|
| 24 | edit_entry => \&iphone_edit_entry, |
|---|
| 25 | edit_comment => \&iphone_edit_comment, |
|---|
| 26 | delete_confirm => \&iphone_delete_confirm, |
|---|
| 27 | set_comment_status => \&iphone_set_comment_status, |
|---|
| 28 | view => \&iphone_view, |
|---|
| 29 | # save_entry => \&iphone_save_entry, |
|---|
| 30 | }, |
|---|
| 31 | }, |
|---|
| 32 | }, |
|---|
| 33 | callbacks => { |
|---|
| 34 | template_param => \&page_param, |
|---|
| 35 | 'template_param.list_comment' => \&iphone_list_comment_param, |
|---|
| 36 | }, |
|---|
| 37 | }, |
|---|
| 38 | }); |
|---|
| 39 | MT->add_plugin($plugin); |
|---|
| 40 | |
|---|
| 41 | sub iphone_list_comment_param { |
|---|
| 42 | return unless $enabled; |
|---|
| 43 | my $cb = shift; |
|---|
| 44 | my ($app, $param, $tmpl) = @_; |
|---|
| 45 | |
|---|
| 46 | if (my $pager_json = $param->{'pager_json'}) { |
|---|
| 47 | # Fix parameters for pagination of comments (app listing method |
|---|
| 48 | # no longer provides these, but populates a json value that is |
|---|
| 49 | # handled by a javascript routine to display pagination in MT4). |
|---|
| 50 | require JSON; |
|---|
| 51 | my $pager = JSON::jsonToObj($pager_json); |
|---|
| 52 | my $offset = $pager->{offset}; |
|---|
| 53 | my $limit = $pager->{limit}; |
|---|
| 54 | if ($offset) { |
|---|
| 55 | $param->{prev_offset} = 1; |
|---|
| 56 | $param->{prev_offset_val} = $offset - $limit; |
|---|
| 57 | $param->{prev_offset_val} = 0 if $param{prev_offset_val} < 0; |
|---|
| 58 | } |
|---|
| 59 | my $next_offset = ( $offset || 0 ) + $limit; |
|---|
| 60 | if ($next_offset < $pager->{listTotal}) { |
|---|
| 61 | $param->{next_offset} = 1; |
|---|
| 62 | $param->{next_offset_val} = $next_offset; |
|---|
| 63 | } |
|---|
| 64 | } |
|---|
| 65 | } |
|---|
| 66 | |
|---|
| 67 | sub init_request { |
|---|
| 68 | my $plugin = shift; |
|---|
| 69 | my ($app) = @_; |
|---|
| 70 | |
|---|
| 71 | $enabled = 0; |
|---|
| 72 | |
|---|
| 73 | # user agent test; if iPhone and CMS app, switch template directory |
|---|
| 74 | if ($app->isa('MT::App::CMS')) { |
|---|
| 75 | # A bit of User Agent sniffing to determine if MT should |
|---|
| 76 | # be using our AppleWebKit mobile interface. |
|---|
| 77 | # Using keyword detection provided by Apple: |
|---|
| 78 | # http://trac.webkit.org/projects/webkit/wiki/DetectingWebKit |
|---|
| 79 | if (my $ua = $ENV{HTTP_USER_AGENT}) { |
|---|
| 80 | if ((( $ua =~ m!AppleWebKit/! ) && ( $ua =~ m!Mobile/! )) || |
|---|
| 81 | ( $ua =~ m!Opera Mini/!)) { |
|---|
| 82 | $enabled = 1; |
|---|
| 83 | |
|---|
| 84 | # Redirect 'dashboard' or 'default' modes to iphone_main |
|---|
| 85 | $app->mode('iphone_main') |
|---|
| 86 | if ($app->mode eq 'default') || ($app->mode eq 'dashboard'); |
|---|
| 87 | |
|---|
| 88 | $app->config('AltTemplatePath', $plugin->path . '/tmpl'); |
|---|
| 89 | } |
|---|
| 90 | } |
|---|
| 91 | } |
|---|
| 92 | } |
|---|
| 93 | |
|---|
| 94 | sub iphone_view { |
|---|
| 95 | my $app = shift; |
|---|
| 96 | if ($enabled && ($app->param('_type') eq 'entry')) { |
|---|
| 97 | # We replace the 'view' mode since after saving an entry, |
|---|
| 98 | # we get redirected back to a view mode. |
|---|
| 99 | return iphone_edit_entry($app, @_); |
|---|
| 100 | } |
|---|
| 101 | else { |
|---|
| 102 | return undef; |
|---|
| 103 | } |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | sub iphone_main { |
|---|
| 107 | my $app = shift; |
|---|
| 108 | my $param = {}; |
|---|
| 109 | $param->{blog_id} = $app->param('blog_id'); |
|---|
| 110 | $app->build_blog_selector($param); |
|---|
| 111 | my $blog_loop = $param->{top_blog_loop} || []; |
|---|
| 112 | foreach (@$blog_loop) { |
|---|
| 113 | $_->{blog_name} = $_->{top_blog_name}; |
|---|
| 114 | $_->{blog_id} = $_->{top_blog_id}; |
|---|
| 115 | } |
|---|
| 116 | $param->{blogs} = $blog_loop; |
|---|
| 117 | $param->{user_has_weblog} = 1 if @$blog_loop; |
|---|
| 118 | $app->load_tmpl('main.tmpl', $param); |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | sub iphone_set_comment_status { |
|---|
| 122 | my $app = shift; |
|---|
| 123 | my $id = $app->param('id'); |
|---|
| 124 | my $blog_id = $app->param('blog_id'); |
|---|
| 125 | $app->param('_type', 'comment'); |
|---|
| 126 | $app->return_args('__mode=list_comments&id=' . $id . '&blog_id=' . $blog_id); |
|---|
| 127 | my $status = $app->param('status'); |
|---|
| 128 | if ( $status eq 'delete' ) { |
|---|
| 129 | return $app->delete(); |
|---|
| 130 | } |
|---|
| 131 | elsif ( $status eq 'junk' ) { |
|---|
| 132 | return $app->handle_junk(); |
|---|
| 133 | } |
|---|
| 134 | elsif ( $status eq '2' ) { |
|---|
| 135 | return $app->approve_item(); |
|---|
| 136 | } |
|---|
| 137 | else { |
|---|
| 138 | return $app->unapprove_item(); |
|---|
| 139 | } |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | sub iphone_delete_confirm { |
|---|
| 143 | my $app = shift; |
|---|
| 144 | |
|---|
| 145 | my $blog_id = $app->param('blog_id'); |
|---|
| 146 | my $type = $app->param('_type') || 'entry'; |
|---|
| 147 | my $param = { |
|---|
| 148 | blog_id => $blog_id, |
|---|
| 149 | id => $app->param('id'), |
|---|
| 150 | type => $type, |
|---|
| 151 | return => 'edit_entry', |
|---|
| 152 | id_loop => [ $app->param('id') ], |
|---|
| 153 | script_parent_url => $app->uri, |
|---|
| 154 | }; |
|---|
| 155 | return $app->build_page('delete_confirm.tmpl', $param); |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | sub iphone_edit_comment { |
|---|
| 159 | my $app = shift; |
|---|
| 160 | $app->param('_type', 'comment'); |
|---|
| 161 | return $app->edit_object(); |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | # sub iphone_save_entry { |
|---|
| 165 | # my $app = shift; |
|---|
| 166 | # return $app->save_entry(@_) unless $enabled; |
|---|
| 167 | # |
|---|
| 168 | # if ($app->param('preview_entry')) { |
|---|
| 169 | # return $app->preview_entry(@_); |
|---|
| 170 | # } |
|---|
| 171 | # return $app->save_entry(@_); |
|---|
| 172 | # } |
|---|
| 173 | |
|---|
| 174 | sub iphone_edit_entry { |
|---|
| 175 | my $app = shift; |
|---|
| 176 | |
|---|
| 177 | $app->param('_type', 'entry'); |
|---|
| 178 | my $tmpl = $app->edit_object(); |
|---|
| 179 | |
|---|
| 180 | my $sel_cats = $tmpl->param('selected_category_loop') || []; |
|---|
| 181 | my @cat_loop; |
|---|
| 182 | my $curr_cats = ''; |
|---|
| 183 | my $curr_cat_ids = ''; |
|---|
| 184 | my %selected; |
|---|
| 185 | foreach my $sel (@$sel_cats) { |
|---|
| 186 | my $cat = MT::Category->load($sel) or next; |
|---|
| 187 | $curr_cats .= ', ' if $curr_cats ne ''; |
|---|
| 188 | $curr_cat_ids .= ',' if $curr_cat_ids ne ''; |
|---|
| 189 | $curr_cats .= $cat->label; |
|---|
| 190 | $curr_cat_ids .= $cat->id; |
|---|
| 191 | $selected{$cat->id} = 1; |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | my $c_data = $app->_build_category_list( |
|---|
| 195 | blog_id => $app->blog->id, |
|---|
| 196 | type => 'category', |
|---|
| 197 | ); |
|---|
| 198 | for my $row (@$c_data) { |
|---|
| 199 | my $spacer = $row->{category_label_spacer} || ''; |
|---|
| 200 | push @cat_loop, { |
|---|
| 201 | category_id => $row->{category_id}, |
|---|
| 202 | category_label => $spacer . MT::Util::encode_html($row->{category_label}), |
|---|
| 203 | category_is_selected => $selected{$row->{category_id}} ? 1 : 0, |
|---|
| 204 | }; |
|---|
| 205 | } |
|---|
| 206 | $tmpl->param('category_loop', \@cat_loop); |
|---|
| 207 | $tmpl->param('current_categories', $curr_cats); |
|---|
| 208 | $tmpl->param('current_category_ids', $curr_cat_ids); |
|---|
| 209 | return $tmpl; |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | sub page_param { |
|---|
| 213 | return unless $enabled; |
|---|
| 214 | |
|---|
| 215 | my $cb = shift; |
|---|
| 216 | my ($app, $param, $tmpl) = @_; |
|---|
| 217 | $param->{portal_label} = MT->translate("Movable Type"); |
|---|
| 218 | $param->{user_id} = $app->user && $app->user->id; |
|---|
| 219 | $param->{script_base_url} = $param->{script_parent_url} = $app->uri; |
|---|
| 220 | $param->{page_mode} = $app->mode; |
|---|
| 221 | $param->{static_uri} = $app->static_path . $plugin->{envelope} . '/'; |
|---|
| 222 | } |
|---|
| 223 | |
|---|
| 224 | 1; |
|---|