Changes in [2191:f3ecd85d5c32:2196:234c9e083cfb]
- Files:
-
- 8 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
admin/blog_theme.php
r2191 r2196 15 15 dcPage::check('admin'); 16 16 17 # Loading themes 17 # -------------------------------------------------- 18 # @todo Add settings to Dotclear update features 19 if ($core->blog->settings->system->repository_theme_url === null) { 20 $core->blog->settings->system->put( 21 'repository_theme_url', 'http://update.dotaddict.org/dc2/themes.xml', 'string', 'Themes XML feed location', true, true 22 ); 23 } 24 # -------------------------------------------------- 25 26 # -- Loading themes -- 18 27 $core->themes = new dcThemes($core); 19 $core->themes->loadModules($core->blog->themes_path,null); 20 21 # Theme screenshot 28 $core->themes->loadModules($core->blog->themes_path, null); 29 30 # -- Repository helper -- 31 $repository = new dcRepository( 32 $core->themes, 33 $core->blog->settings->system->repository_theme_url 34 ); 35 $repository->check(); 36 37 # -- Page helper -- 38 $list = new adminThemesList( 39 $core, 40 $core->blog->themes_path, 41 false 42 ); 43 44 # -- Theme screenshot -- 22 45 if (!empty($_GET['shot']) && $core->themes->moduleExists($_GET['shot'])) 23 46 { … … 43 66 } 44 67 45 $can_install = $core->auth->isSuperAdmin(); 46 $is_writable = is_dir($core->blog->themes_path) && is_writable($core->blog->themes_path); 47 $default_tab = 'themes-list'; 48 49 # Selecting theme 50 if (!empty($_POST['theme']) && !empty($_POST['select']) && empty($_REQUEST['conf'])) 51 { 52 $core->blog->settings->addNamespace('system'); 53 $core->blog->settings->system->put('theme',$_POST['theme']); 54 $core->blog->triggerBlog(); 55 $theme = $core->themes->getModules($_POST['theme']); 56 dcPage::addSuccessNotice(sprintf( 57 __('Current theme has been successfully changed to "%s".'), 58 html::escapeHTML($theme['name'])) 68 # -- Display module configuration page -- 69 if ($list->setConfigurationFile($core->themes, $core->blog->settings->system->theme)) { 70 71 # Get content before page headers 72 include $list->getConfigurationFile(); 73 74 # Gather content 75 $list->setConfigurationContent(); 76 77 # Display page 78 dcPage::open(__('Blog appearance'), 79 dcPage::jsPageTabs(). 80 dcPage::jsColorPicker(). 81 82 # --BEHAVIOR-- themesToolsHeaders 83 $core->callBehavior('themesToolsHeaders', $core, true), 84 85 dcPage::breadcrumb( 86 array( 87 html::escapeHTML($core->blog->name) => '', 88 __('Blog appearance') => 'blog_theme.php', 89 '<span class="page-title">'.__('Theme configuration').'</span>' => '' 90 )) 59 91 ); 60 92 61 http::redirect('blog_theme.php'); 62 } 63 64 if ($can_install && !empty($_POST['theme']) && !empty($_POST['remove']) && empty($_REQUEST['conf'])) 65 { 66 try 67 { 68 if ($_POST['theme'] == 'default') { 69 throw new Exception(__('You can\'t remove default theme.')); 70 } 71 72 if (!$core->themes->moduleExists($_POST['theme'])) { 73 throw new Exception(__('Theme does not exist.')); 74 } 75 76 $theme = $core->themes->getModules($_POST['theme']); 77 78 # --BEHAVIOR-- themeBeforeDelete 79 $core->callBehavior('themeBeforeDelete',$theme); 80 81 $core->themes->deleteModule($_POST['theme']); 82 83 # --BEHAVIOR-- themeAfterDelete 84 $core->callBehavior('themeAfterDelete',$theme); 85 86 http::redirect('blog_theme.php'); 87 } 88 catch (Exception $e) 89 { 93 if (!empty($_GET['done'])){ 94 dcPage::success(__('Theme successfully configured.')); 95 } 96 97 # Display previously gathered content 98 $list->getConfigurationContent(); 99 100 dcPage::close(); 101 102 # Stop reading code here 103 return; 104 } 105 106 # -- Execute actions -- 107 if (!empty($_POST) && empty($_REQUEST['conf']) && $core->auth->isSuperAdmin() && $list->isPathWritable()) { 108 try { 109 $list->executeAction('themes', $core->themes, $repository); 110 } 111 catch (Exception $e) { 90 112 $core->error->add($e->getMessage()); 91 113 } 92 114 } 93 115 94 # Theme upload 95 if ($can_install && $is_writable && ((!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file'])) || 96 (!empty($_POST['fetch_pkg']) && !empty($_POST['pkg_url'])))) 97 { 98 try 99 { 100 if (empty($_POST['your_pwd']) || !$core->auth->checkPassword(crypt::hmac(DC_MASTER_KEY,$_POST['your_pwd']))) { 101 throw new Exception(__('Password verification failed')); 102 } 103 104 if (!empty($_POST['upload_pkg'])) 105 { 106 files::uploadStatus($_FILES['pkg_file']); 107 108 $dest = $core->blog->themes_path.'/'.$_FILES['pkg_file']['name']; 109 if (!move_uploaded_file($_FILES['pkg_file']['tmp_name'],$dest)) { 110 throw new Exception(__('Unable to move uploaded file.')); 111 } 112 } 113 else 114 { 115 $url = urldecode($_POST['pkg_url']); 116 $dest = $core->blog->themes_path.'/'.basename($url); 117 118 try 119 { 120 $client = netHttp::initClient($url,$path); 121 $client->setUserAgent('Dotclear - http://www.dotclear.org/'); 122 $client->useGzip(false); 123 $client->setPersistReferers(false); 124 $client->setOutput($dest); 125 $client->get($path); 126 } 127 catch( Exception $e) 128 { 129 throw new Exception(__('An error occurred while downloading the file.')); 130 } 131 132 unset($client); 133 } 134 135 $ret_code = dcModules::installPackage($dest,$core->themes); 136 if ($ret_code == 2) { 137 dcPage::addSuccessNotice(__('Theme has been successfully upgraded.')); 138 } else { 139 dcPage::addSuccessNotice(__('Theme has been successfully installed.')); 140 } 141 http::redirect('blog_theme.php'); 142 } 143 catch (Exception $e) 144 { 145 $core->error->add($e->getMessage()); 146 $default_tab = 'add-theme'; 147 } 148 } 149 150 $theme_conf_mode = false; 151 if (!empty($_REQUEST['conf'])) 152 { 153 $theme_conf_file = path::real($core->blog->themes_path.'/'.$core->blog->settings->system->theme).'/_config.php'; 154 if (file_exists($theme_conf_file)) { 155 $theme_conf_mode = true; 156 } 157 } 158 159 function display_theme_details($id,$details,$current) 160 { 161 global $core; 162 163 $screenshot = 'images/noscreenshot.png'; 164 if (file_exists($core->blog->themes_path.'/'.$id.'/screenshot.jpg')) { 165 $screenshot = 'blog_theme.php?shot='.rawurlencode($id); 166 } 167 168 $radio_id = 'theme_'.html::escapeHTML($id); 169 if (preg_match('#^http(s)?://#',$core->blog->settings->system->themes_url)) { 170 $theme_url = http::concatURL($core->blog->settings->system->themes_url,'/'.$id); 171 } else { 172 $theme_url = http::concatURL($core->blog->url,$core->blog->settings->system->themes_url.'/'.$id); 173 } 174 $has_conf = file_exists(path::real($core->blog->themes_path.'/'.$id).'/_config.php'); 175 $has_css = file_exists(path::real($core->blog->themes_path.'/'.$id).'/style.css'); 176 $parent = $core->themes->moduleInfo($id,'parent'); 177 $has_parent = (boolean)$parent; 178 if ($has_parent) { 179 $is_parent_present = $core->themes->moduleExists($parent); 180 } 181 182 $res = 183 '<div class="theme-details'.($current ? ' current-theme' : '').'">'. 184 '<div class="theme-shot"><img src="'.$screenshot.'" alt="" /></div>'. 185 '<div class="theme-info">'. 186 '<h4>'.form::radio(array('theme',$radio_id),html::escapeHTML($id),$current,'','',($has_parent && !$is_parent_present)).' '. 187 '<label class="classic" for="'.$radio_id.'">'. 188 html::escapeHTML($details['name']).'</label></h4>'. 189 '<p><span class="theme-desc">'.html::escapeHTML($details['desc']).'</span> '. 190 '<span class="theme-author">'.sprintf(__('by %s'),html::escapeHTML($details['author'])).'</span> '. 191 '<span class="theme-version">'.sprintf(__('version %s'),html::escapeHTML($details['version'])).'</span> '; 192 if ($has_parent) { 193 if ($is_parent_present) { 194 $res .= '<span class="theme-parent-ok">'.sprintf(__('(built on "%s")'),html::escapeHTML($parent)).'</span> '; 195 } else { 196 $res .= '<span class="theme-parent-missing">'.sprintf(__('(requires "%s")'),html::escapeHTML($parent)).'</span> '; 197 } 198 } 199 if ($has_css) { 200 $res .= '<span class="theme-css"><a href="'.$theme_url.'/style.css">'.__('Stylesheet').'</a></span>'; 201 } 202 $res .= '</p>'; 203 $res .= 204 '</div>'. 205 '<div class="theme-actions">'; 206 if ($current && $has_conf) { 207 $res .= '<p><a href="blog_theme.php?conf=1" class="button">'.__('Configure theme').'</a></p>'; 208 } 209 if ($current) { 210 # --BEHAVIOR-- adminCurrentThemeDetails 211 $res .= $core->callBehavior('adminCurrentThemeDetails',$core,$id,$details); 212 } 213 $res .= 214 '</div>'. 215 '</div>'; 216 217 return $res; 218 } 219 220 if (!$theme_conf_mode) 221 { 222 $breadcrumb = dcPage::breadcrumb( 116 # -- Page header -- 117 dcPage::open(__('Themes management'), 118 dcPage::jsLoad('js/_blog_theme.js'). 119 dcPage::jsPageTabs(). 120 dcPage::jsColorPicker(), 121 122 # --BEHAVIOR-- themesToolsHeaders 123 $core->callBehavior('themesToolsHeaders', $core, false), 124 125 dcPage::breadcrumb( 223 126 array( 224 127 html::escapeHTML($core->blog->name) => '', 225 __('Blog appearance') => '' 226 )); 227 } else { 228 $breadcrumb = dcPage::breadcrumb( 229 array( 230 html::escapeHTML($core->blog->name) => '', 231 __('Blog appearance') => 'blog_theme.php', 232 __('Theme configuration') => '' 233 )); 234 } 235 236 dcPage::open(__('Blog appearance'), 237 (!$theme_conf_mode ? dcPage::jsLoad('js/_blog_theme.js') : ''). 238 dcPage::jsPageTabs($default_tab). 239 dcPage::jsColorPicker(), 240 $breadcrumb 128 '<span class="page-title">'.__('Blog appearance').'</span>' => '' 129 )) 241 130 ); 242 131 243 if (!$theme_conf_mode) 244 { 245 if (!empty($_GET['upd'])) { 246 dcPage::success(__('Theme has been successfully changed.')); 247 } 248 249 if (!empty($_GET['added'])) { 250 dcPage::success(($_GET['added'] == 2 ? __('Theme has been successfully upgraded') : __('Theme has been successfully installed.'))); 251 } 252 253 if (!empty($_GET['del'])) { 254 dcPage::success(__('Theme has been successfully deleted.')); 255 } 256 257 # Themes list 258 echo '<div class="multi-part" id="themes-list" title="'.__('Themes').'">'. 259 '<h3>'.__('Available themes in your installation').'</h3>'; 260 261 $themes = $core->themes->getModules(); 262 if (isset($themes[$core->blog->settings->system->theme])) { 263 echo '<p>'.sprintf(__('You are currently using <strong>%s</strong>'),$themes[$core->blog->settings->system->theme]['name']).'.</p>'; 264 } 265 266 echo 267 '<form action="blog_theme.php" method="post" id="themes-form">'. 268 '<div id="themes">'; 269 270 if (isset($themes[$core->blog->settings->system->theme])) { 271 echo display_theme_details($core->blog->settings->system->theme,$themes[$core->blog->settings->system->theme],true); 272 } 273 274 foreach ($themes as $k => $v) 275 { 276 if ($core->blog->settings->system->theme == $k) { // Current theme 277 continue; 278 } 279 echo display_theme_details($k,$v,false); 280 } 281 282 echo '</div>'; 283 284 echo 285 '<div id="themes-actions">'. 286 287 '<p>'.$core->formNonce().'<input type="submit" name="select" value="'.__('Use selected theme').'" /> '; 288 if ($can_install) { 289 echo ' <input type="submit" class="delete" name="remove" value="'.__('Delete selected theme').'" />'; 290 } 291 echo '</p>'. 292 293 '</div>'. 294 '</form>'. 132 # -- Succes messages -- 133 if (!empty($_GET['msg'])) { 134 $list->displayMessage($_GET['msg']); 135 } 136 137 # -- Display modules lists -- 138 if ($core->auth->isSuperAdmin() && $list->isPathWritable()) { 139 140 # Updated modules from repo 141 $modules = $repository->get(true); 142 if (!empty($modules)) { 143 echo 144 '<div class="multi-part" id="update" title="'.html::escapeHTML(__('Update themes')).'">'. 145 '<h3>'.html::escapeHTML(__('Update themes')).'</h3>'. 146 '<p>'.sprintf( 147 __('There is one theme to update available from %2$s.', 'There are %s themes to update available from %s.', count($modules)), 148 count($modules), 149 '<a href="http://dotaddict.org/dc2/themes">Dotaddict</a>' 150 ).'</p>'; 151 152 $list 153 ->newList('theme-update') 154 ->setModules($modules) 155 ->setPageTab('update') 156 ->displayModulesList( 157 /*cols */ array('sshot', 'name', 'desc', 'author', 'version', 'current_version', 'parent'), 158 /* actions */ array('update') 159 ); 160 161 echo 162 '</div>'; 163 } 164 } 165 166 # List all active plugins 167 echo 168 '<div class="multi-part" id="themes" title="'.__('Installed themes').'">'; 169 170 $modules = $core->themes->getModules(); 171 if (!empty($modules)) { 172 173 echo 174 '<h3>'.__('Activated themes').'</h3>'. 175 '<p>'.__('Manage installed themes from this list.').'</p>'; 176 177 $list 178 ->newList('theme-activate') 179 ->setModules($modules) 180 ->setPageTab('themes') 181 ->displayModulesList( 182 /* cols */ array('sshot', 'name', 'config', 'desc', 'author', 'version', 'parent'), 183 /* actions */ array('select', 'deactivate', 'delete') 184 ); 185 } 186 187 $modules = $core->themes->getDisabledModules(); 188 if (!empty($modules)) { 189 190 echo 191 '<h3>'.__('Deactivated themes').'</h3>'. 192 '<p>'.__('Deactivated themes are installed but not usable. You can activate them from here.').'</p>'; 193 194 $list 195 ->newList('theme-deactivate') 196 ->setModules($modules) 197 ->setPageTab('themes') 198 ->displayModulesList( 199 /* cols */ array('name', 'distrib'), 200 /* actions */ array('activate', 'delete') 201 ); 202 } 203 204 echo 205 '</div>'; 206 207 if ($core->auth->isSuperAdmin() && $list->isPathWritable()) { 208 209 # New modules from repo 210 $search = $list->getSearchQuery(); 211 $modules = $search ? $repository->search($search) : $repository->get(); 212 213 echo 214 '<div class="multi-part" id="new" title="'.__('Add themes from Dotaddict').'">'. 215 '<h3>'.__('Add themes from Dotaddict repository').'</h3>'; 216 217 $list 218 ->newList('theme-new') 219 ->setModules($modules) 220 ->setPageTab('new') 221 ->displaySearchForm() 222 ->displayNavMenu() 223 ->displayModulesList( 224 /* cols */ array('expander', 'sshot', 'name', 'config', 'desc', 'author', 'version', 'parent', 'distrib'), 225 /* actions */ array('install'), 226 /* nav limit */ true 227 ); 228 229 echo 230 '<p class="info vertical-separator">'.sprintf( 231 __("Visit %s repository, the resources center for Dotclear."), 232 '<a href="http://dotaddict.org/dc2/themes">Dotaddict</a>' 233 ). 234 '</p>'. 235 295 236 '</div>'; 296 297 # Add a new theme 298 if ($can_install) 299 { 300 echo 301 '<div class="multi-part clear" id="add-theme" title="'.__('Install or upgrade a theme').'">'. 302 '<h3>'.__('Add themes to your installation').'</h3>'. 303 '<p class="form-note info">'.sprintf(__('You can find additional themes for your blog on %s.'), 304 '<a href="http://themes.dotaddict.org/galerie-dc2/">Dotaddict</a>').'</p>'; 305 306 if ($is_writable) 307 { 308 echo '<p>'.__('You can also install themes by uploading or downloading zip files.').'</p>'; 309 310 # 'Upload theme' form 311 echo 312 '<form method="post" action="blog_theme.php" id="uploadpkg" enctype="multipart/form-data" class="fieldset">'. 313 '<h4>'.__('Upload a zip file').'</h4>'. 314 '<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Theme zip file:').'</label> '. 315 '<input type="file" name="pkg_file" id="pkg_file" /></p>'. 316 '<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '. 317 form::password(array('your_pwd','your_pwd1'),20,255).'</p>'. 318 '<p><input type="submit" name="upload_pkg" value="'.__('Upload theme').'" />'. 319 $core->formNonce().'</p>'. 320 '</form>'; 321 322 # 'Fetch theme' form 323 echo 324 '<form method="post" action="blog_theme.php" id="fetchpkg" class="fieldset">'. 325 '<h4>'.__('Download a zip file').'</h4>'. 326 '<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Theme zip file URL:').'</label> '. 327 form::field(array('pkg_url','pkg_url'),40,255).'</p>'. 328 '<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '. 329 form::password(array('your_pwd','your_pwd2'),20,255).'</p>'. 330 '<p><input type="submit" name="fetch_pkg" value="'.__('Download theme').'" />'. 331 $core->formNonce().'</p>'. 332 '</form>'; 333 } 334 else 335 { 336 echo 337 '<p class="static-msg">'. 338 __('To enable this function, please give write access to your themes directory.'). 339 '</p>'; 340 } 341 echo '</div>'; 342 } 343 } 344 else 345 { 346 $theme_name = $core->themes->moduleInfo($core->blog->settings->system->theme,'name'); 347 $core->themes->loadModuleL10Nresources($core->blog->settings->system->theme,$_lang); 348 349 echo 350 '<p><a class="back" href="blog_theme.php">'.__('Back to Blog appearance').'</a></p>'; 351 352 try 353 { 354 # Let theme configuration set their own form(s) if required 355 $standalone_config = (boolean) $core->themes->moduleInfo($core->blog->settings->system->theme,'standalone_config'); 356 357 if (!$standalone_config) 358 echo '<form id="theme_config" action="blog_theme.php?conf=1" method="post" enctype="multipart/form-data">'; 359 360 include $theme_conf_file; 361 362 if (!$standalone_config) 363 echo 364 '<p class="clear"><input type="submit" value="'.__('Save').'" />'. 365 $core->formNonce().'</p>'. 366 '</form>'; 367 368 } 369 catch (Exception $e) 370 { 371 echo '<div class="error"><p>'.$e->getMessage().'</p></div>'; 372 } 237 238 # Add a new plugin 239 echo 240 '<div class="multi-part" id="addtheme" title="'.__('Install or upgrade manually').'">'; 241 242 echo '<p>'.__('You can install themes by uploading or downloading zip files.').'</p>'; 243 244 $list->displayManualForm(); 245 246 echo 247 '</div>'; 373 248 } 374 249 -
admin/index.php
r2166 r2175 123 123 } 124 124 $__dashboard_icons['prefs'] = new ArrayObject(array(__('My preferences'),'preferences.php','images/menu/user-pref-b.png')); 125 } 126 127 # Check plugins and themes update from repository 128 function dc_check_repository_update($mod, $url, $img, $icon) 129 { 130 $repo = new dcRepository($mod, $url); 131 $repo->check(); 132 $upd = $repo->get(true); 133 if (!empty($upd)) { 134 $icon[0] .= '<br />'.sprintf(__('An update is available', '%s updates are available.', count($upd)),count($upd)); 135 $icon[1] .= '#update'; 136 $icon[2] = 'images/menu/'.$img.'-b-update.png'; 137 } 138 } 139 if (isset($__dashboard_icons['plugins'])) { 140 dc_check_repository_update($core->plugins, $core->blog->settings->system->repository_plugin_url, 'plugins', $__dashboard_icons['plugins']); 141 } 142 if (isset($__dashboard_icons['blog_theme'])) { 143 $themes = new dcThemes($core); 144 $themes->loadModules($core->blog->themes_path, null); 145 dc_check_repository_update($themes, $core->blog->settings->system->repository_theme_url, 'blog-theme', $__dashboard_icons['blog_theme']); 125 146 } 126 147 -
admin/js/_blog_theme.js
r2101 r2195 1 1 $(function() { 2 $('#themes-actions').hide(); 3 var submit_s = $('#themes-actions input[name=select]'); 4 var submit_r = $('#themes-actions input[name=remove]'); 5 6 var details = $('#themes div.theme-details'); 7 $('div.theme-actions',details).hide(); 8 $('input:radio',details).hide(); 9 $('div.theme-info span, div.theme-info a',details).hide(); 10 details.removeClass('theme-details').addClass('theme-details-js'); 11 12 var themes_wrapper = $('<div id="themes-wrapper"></div>'); 13 var theme_box = $('<div id="theme-box"><div</div>'); 14 $('#themes').wrap(themes_wrapper).before(theme_box); 15 16 details.each(function() { 17 var box = this; 18 var a = $(document.createElement('a')); 19 a.attr('href','#'); 20 a.attr('title',$('>div h3>label',this).text()); 21 $(box).wrap(a); 22 $(box).parent().click(function(event) { 23 update_box(box); 24 event.preventDefault(); 25 return false; 26 }); 2 $('.module-sshot').not('.current-theme .module-sshot').each(function(){ 3 var bar = $('<div>').addClass('bloc-toggler'); 4 $(this).after( 5 $(bar).toggleWithLegend($(this).parent().children('.toggle-bloc'),{ 6 img_on_src: dotclear.img_plus_theme_src, 7 img_on_alt: dotclear.img_plus_theme_alt, 8 img_off_src: dotclear.img_minus_theme_src, 9 img_off_alt: dotclear.img_minus_theme_alt, 10 legend_click: true 11 })); 27 12 }); 28 29 function update_box(e) {30 theme_box.empty();31 var img = $('div.theme-shot',e).clone();32 var info = $('div.theme-info',e).clone();33 34 if ($(e).hasClass('current-theme')) {35 var actions = $('div.theme-actions',e).clone();36 actions.show();37 } else {38 var actions = $('<div class="theme-actions"></div>');39 if (submit_s.length > 0 && !$('input:radio',info).attr('disabled')) {40 var select = $('<a href="#" class="button">' + dotclear.msg.use_this_theme + '</a>');41 select.addClass('select-button').click(function(){42 submit_s.click();43 return false;44 });45 actions.append(select).append(' ');46 }47 if (submit_r.length > 0 && $('input:radio',info).attr('id') != 'theme_default') {48 var remove = $('<a href="#" class="button delete">' + dotclear.msg.remove_this_theme + '</a>');49 remove.click(function() {50 var t_name = $(this).parents('#theme-box').find('div.theme-info h3:first').text();51 t_name = $.trim(t_name);52 if (window.confirm(dotclear.msg.confirm_delete_theme.replace('%s',t_name))) {53 submit_r.click();54 }55 return false;56 });57 actions.append(remove);58 }59 }60 61 $('input:radio',info).remove();62 $('span, a',info).show();63 64 theme_box.append(img).append(info).append(actions);65 details.removeClass('theme-selected');66 $(e).addClass('theme-selected');67 $('input:radio',e).prop('checked',true);68 }69 70 update_box(details[0]);71 13 }); -
admin/js/_plugins.js
r0 r2171 1 dotclear.moduleExpander = function(line) { 2 var td = line.firstChild; 3 4 var img = document.createElement('img'); 5 img.src = dotclear.img_plus_src; 6 img.alt = dotclear.img_plus_alt; 7 img.className = 'expand'; 8 $(img).css('cursor','pointer'); 9 img.line = line; 10 img.onclick = function() { dotclear.viewModuleContent(this,this.line); }; 11 12 td.insertBefore(img,td.firstChild); 13 }; 14 15 dotclear.modulesExpander = function(line,lines) { 16 var td = line.firstChild; 17 18 var img = document.createElement('img'); 19 img.src = dotclear.img_plus_src; 20 img.alt = dotclear.img_plus_alt; 21 img.className = 'expand'; 22 $(img).css('cursor','pointer'); 23 img.lines = lines; 24 img.onclick = function() { dotclear.viewModulesContent(this,this.lines); }; 25 26 td.insertBefore(img,td.firstChild); 27 }; 28 29 dotclear.viewModulesContent = function(img,lines) { 30 31 action = 'toggle'; 32 33 if (img.alt == dotclear.img_plus_alt) { 34 img.src = dotclear.img_minus_src; 35 img.alt = dotclear.img_minus_alt; 36 action = 'open'; 37 } else { 38 img.src = dotclear.img_plus_src; 39 img.alt = dotclear.img_plus_alt; 40 action = 'close'; 41 } 42 43 lines.each(function() { 44 var td = this.firstChild; 45 dotclear.viewModuleContent(td.firstChild,td.firstChild.line,action); 46 }); 47 }; 48 49 dotclear.viewModuleContent = function(img,line,action) { 50 51 var action = action || 'toggle'; 52 var cols = $('td',$(line)).length 53 var sp = line.id.split('_m_'); 54 var listId=sp[0]; 55 var moduleId= sp[1]; 56 57 var tr = document.getElementById('pe'+moduleId); 58 59 if ( !tr && ( action == 'toggle' || action == 'open' ) ) { 60 tr = document.createElement('tr'); 61 tr.id = 'pe'+moduleId; 62 63 var td = document.createElement('td'); 64 td.colSpan = cols; 65 td.className = 'expand'; 66 tr.appendChild(td); 67 68 img.src = dotclear.img_minus_src; 69 img.alt = dotclear.img_minus_alt; 70 71 // Get post content 72 $.get('services.php',{f:'getModuleById', id: moduleId, list: listId},function(data) { 73 var rsp = $(data).children('rsp')[0]; 74 75 if (rsp.attributes[0].value == 'ok') { 76 var author = $(rsp).find('author').text(); 77 var details = $(rsp).find('details').text(); 78 var support = $(rsp).find('support').text(); 79 var box = document.createElement('div'); 80 var dl = document.createElement('ul'); 81 dl.className = "mod-more"; 82 83 if (author) { 84 $(dl).append($('<li class="module-author">'+dotclear.msg.module_author+' '+author+'</li>')); 85 } 86 if (details) { 87 var dd = ''; 88 dd += '<a class="module-details" href="'+details+'">'+dotclear.msg.module_details+'</a>'; 89 if (support) { 90 dd += ' - '; 91 dd += '<a class="module-support" href="'+support+'">'+dotclear.msg.module_support+'</a>'; 92 } 93 $(dl).append($('<li>'+dotclear.msg.module_help+' '+dd+'</li>')); 94 } 95 96 $(td).append($(box).addClass('two-boxes').append(dl)); 97 98 var section = $(rsp).find('section').text(); 99 var tags = $(rsp).find('tags').text(); 100 101 var boxb = document.createElement('div'); 102 var dlb = document.createElement('ul'); 103 dlb.className = "mod-more"; 104 105 if (section) { 106 $(dlb).append($('<li class="module-section">'+dotclear.msg.module_section+' '+section+'</li>')); 107 } 108 if (tags) { 109 $(dlb).append($('<li class="module-tags">'+dotclear.msg.module_tags+' '+tags+'</li>')); 110 } 111 $(td).append($(boxb).addClass('two-boxes').append(dlb)); 112 } else { 113 alert($(rsp).find('message').text()); 114 } 115 }); 116 117 $(line).addClass('expand'); 118 line.parentNode.insertBefore(tr,line.nextSibling); 119 } 120 else if (tr && tr.style.display == 'none' && ( action == 'toggle' || action == 'open' ) ) 121 { 122 $(tr).css('display', 'table-row'); 123 $(line).addClass('expand'); 124 img.src = dotclear.img_minus_src; 125 img.alt = dotclear.img_minus_alt; 126 } 127 else if (tr && tr.style.display != 'none' && ( action == 'toggle' || action == 'close' ) ) 128 { 129 $(tr).css('display', 'none'); 130 $(line).removeClass('expand'); 131 img.src = dotclear.img_plus_src; 132 img.alt = dotclear.img_plus_alt; 133 } 134 135 parentTable = $(line).parents('table'); 136 if( parentTable.find('tr.expand').length == parentTable.find('tr.line').length ) { 137 img = parentTable.find('tr:not(.line) th:first img'); 138 img.attr('src',dotclear.img_minus_src); 139 img.attr('alt',dotclear.img_minus_alt); 140 } 141 142 if( parentTable.find('tr.expand').length == 0 ) { 143 img = parentTable.find('tr:not(.line) th:first img'); 144 img.attr('src',dotclear.img_plus_src); 145 img.attr('alt',dotclear.img_plus_alt); 146 } 147 148 }; 149 150 1 151 $(function() { 2 $('table.plugins form input[type=submit][name=delete]').click(function() { 3 var p_name = $('input[name=plugin_id]',$(this).parent()).val(); 4 return window.confirm(dotclear.msg.confirm_delete_plugin.replace('%s',p_name)); 5 }); 152 $('table.modules.expandable tr:not(.line)').each(function() { 153 dotclear.modulesExpander(this,$('table.modules tr.line')); 154 }); 155 $('table.modules.expandable tr.line').each(function() { 156 dotclear.moduleExpander(this); 157 }); 6 158 }); -
admin/plugins.php
r2166 r2182 13 13 require dirname(__FILE__).'/../inc/admin/prepend.php'; 14 14 15 dcPage::checkSuper(); 16 17 $default_tab = !empty($_REQUEST['tab']) ? html::escapeHTML($_REQUEST['tab']) : 'plugins'; 18 19 $p_paths = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); 20 $p_path = array_pop($p_paths); 21 unset($p_paths); 22 23 $is_writable = false; 24 if (is_dir($p_path) && is_writeable($p_path)) { 25 $is_writable = true; 26 $p_path_pat = preg_quote($p_path,'!'); 27 } 28 29 $plugin_id = !empty($_POST['plugin_id']) ? $_POST['plugin_id'] : null; 30 31 if ($is_writable) 32 { 33 # Delete plugin 34 if ($plugin_id && !empty($_POST['delete'])) 35 { 36 try 37 { 38 if (empty($_POST['deactivated'])) 39 { 40 if (!$core->plugins->moduleExists($plugin_id)) { 41 throw new Exception(__('No such plugin.')); 42 } 43 44 $plugin = $core->plugins->getModules($plugin_id); 45 $plugin['id'] = $plugin_id; 46 47 if (!preg_match('!^'.$p_path_pat.'!', $plugin['root'])) { 48 throw new Exception(__('You don\'t have permissions to delete this plugin.')); 49 } 50 51 # --BEHAVIOR-- pluginBeforeDelete 52 $core->callBehavior('pluginsBeforeDelete', $plugin); 53 54 $core->plugins->deleteModule($plugin_id); 55 56 # --BEHAVIOR-- pluginAfterDelete 57 $core->callBehavior('pluginsAfterDelete', $plugin); 58 } 59 else 60 { 61 $core->plugins->deleteModule($plugin_id,true); 62 } 63 64 http::redirect('plugins.php?removed=1'); 65 } 66 catch (Exception $e) 67 { 68 $core->error->add($e->getMessage()); 69 } 70 } 71 # Deactivate plugin 72 elseif ($plugin_id && !empty($_POST['deactivate'])) 73 { 74 try 75 { 76 if (!$core->plugins->moduleExists($plugin_id)) { 77 throw new Exception(__('No such plugin.')); 78 } 79 80 $plugin = $core->plugins->getModules($plugin_id); 81 $plugin['id'] = $plugin_id; 82 83 if (!$plugin['root_writable']) { 84 throw new Exception(__('You don\'t have permissions to deactivate this plugin.')); 85 } 86 87 # --BEHAVIOR-- pluginBeforeDeactivate 88 $core->callBehavior('pluginsBeforeDeactivate', $plugin); 89 90 $core->plugins->deactivateModule($plugin_id); 91 92 # --BEHAVIOR-- pluginAfterDeactivate 93 $core->callBehavior('pluginsAfterDeactivate', $plugin); 94 95 http::redirect('plugins.php'); 96 } 97 catch (Exception $e) 98 { 99 $core->error->add($e->getMessage()); 100 } 101 } 102 # Activate plugin 103 elseif ($plugin_id && !empty($_POST['activate'])) 104 { 105 try 106 { 107 $p = $core->plugins->getDisabledModules(); 108 if (!isset($p[$plugin_id])) { 109 throw new Exception(__('No such plugin.')); 110 } 111 112 # --BEHAVIOR-- pluginBeforeActivate 113 $core->callBehavior('pluginsBeforeActivate', $plugin_id); 114 115 $core->plugins->activateModule($plugin_id); 116 117 # --BEHAVIOR-- pluginAfterActivate 118 $core->callBehavior('pluginsAfterActivate', $plugin_id); 119 120 http::redirect('plugins.php'); 121 } 122 catch (Exception $e) 123 { 124 $core->error->add($e->getMessage()); 125 } 126 } 127 # Plugin upload 128 elseif ((!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file'])) || 129 (!empty($_POST['fetch_pkg']) && !empty($_POST['pkg_url']))) 130 { 131 try 132 { 133 if (empty($_POST['your_pwd']) || !$core->auth->checkPassword(crypt::hmac(DC_MASTER_KEY,$_POST['your_pwd']))) { 134 throw new Exception(__('Password verification failed')); 135 } 136 137 if (!empty($_POST['upload_pkg'])) 138 { 139 files::uploadStatus($_FILES['pkg_file']); 140 141 $dest = $p_path.'/'.$_FILES['pkg_file']['name']; 142 if (!move_uploaded_file($_FILES['pkg_file']['tmp_name'],$dest)) { 143 throw new Exception(__('Unable to move uploaded file.')); 144 } 145 } 146 else 147 { 148 $url = urldecode($_POST['pkg_url']); 149 $dest = $p_path.'/'.basename($url); 150 151 try 152 { 153 $client = netHttp::initClient($url,$path); 154 $client->setUserAgent('Dotclear - http://www.dotclear.org/'); 155 $client->useGzip(false); 156 $client->setPersistReferers(false); 157 $client->setOutput($dest); 158 $client->get($path); 159 } 160 catch( Exception $e) 161 { 162 throw new Exception(__('An error occurred while downloading the file.')); 163 } 164 165 unset($client); 166 } 167 168 # --BEHAVIOR-- pluginBeforeAdd 169 $core->callBehavior('pluginsBeforeAdd', $plugin_id); 170 171 $ret_code = $core->plugins->installPackage($dest,$core->plugins); 172 173 # --BEHAVIOR-- pluginAfterAdd 174 $core->callBehavior('pluginsAfterAdd', $plugin_id); 175 176 http::redirect('plugins.php?added='.$ret_code); 177 } 178 catch (Exception $e) 179 { 180 $core->error->add($e->getMessage()); 181 $default_tab = 'addplugin'; 182 } 183 } 184 } 185 186 # Plugin install 187 $plugins_install = $core->plugins->installModules(); 188 189 /* DISPLAY Main page 190 -------------------------------------------------------- */ 15 dcPage::check('admin'); 16 17 # -------------------------------------------------- 18 # @todo Add settings to Dotclear update features 19 if ($core->blog->settings->system->plugins_allow_multi_install === null) { 20 $core->blog->settings->system->put( 21 'plugins_allow_multi_install', false, 'boolean', 'Allow multi-installation for plugins', true, true 22 ); 23 } 24 if ($core->blog->settings->system->repository_plugin_url === null) { 25 $core->blog->settings->system->put( 26 'repository_plugin_url', 'http://update.dotaddict.org/dc2/plugins.xml', 'string', 'Plugins XML feed location', true, true 27 ); 28 } 29 # -------------------------------------------------- 30 31 # -- Repository helper -- 32 $repository = new dcRepository( 33 $core->plugins, 34 $core->blog->settings->system->repository_plugin_url 35 ); 36 $repository->check(); 37 38 # -- Page helper -- 39 $list = new adminModulesList( 40 $core, 41 DC_PLUGINS_ROOT, 42 $core->blog->settings->system->plugins_allow_multi_install 43 ); 44 45 $list::setDistributedModules(array( 46 'aboutConfig', 47 'akismet', 48 'antispam', 49 'attachments', 50 'blogroll', 51 'blowupConfig', 52 'daInstaller', 53 'fairTrackbacks', 54 'importExport', 55 'maintenance', 56 'pages', 57 'pings', 58 'simpleMenu', 59 'tags', 60 'themeEditor', 61 'userPref', 62 'widgets' 63 )); 64 65 # -- Display module configuration page -- 66 if ($list->setConfigurationFile($core->plugins)) { 67 68 # Get content before page headers 69 include $list->getConfigurationFile(); 70 71 # Gather content 72 $list->setConfigurationContent(); 73 74 # Display page 75 dcPage::open(__('Plugins management'), 76 77 # --BEHAVIOR-- pluginsToolsHeaders 78 $core->callBehavior('pluginsToolsHeaders', $core, true), 79 80 dcPage::breadcrumb( 81 array( 82 html::escapeHTML($core->blog->name) => '', 83 '<a href="'.$list->getPageURL().'">'.__('Plugins management').'</a>' => '', 84 '<span class="page-title">'.__('Plugin configuration').'</span>' => '' 85 )) 86 ); 87 88 # Message 89 if (!empty($_GET['done'])){ 90 dcPage::success(__('Plugin successfully configured.')); 91 } 92 93 # Display previously gathered content 94 $list->getConfigurationContent(); 95 96 dcPage::close(); 97 98 # Stop reading code here 99 return; 100 } 101 102 # -- Execute actions -- 103 if (!empty($_POST) && empty($_REQUEST['conf']) && $core->auth->isSuperAdmin() && $list->isPathWritable()) { 104 try { 105 $list->executeAction('plugins', $core->plugins, $repository); 106 } 107 catch (Exception $e) { 108 $core->error->add($e->getMessage()); 109 } 110 } 111 112 # -- Plugin install -- 113 $plugins_install = null; 114 if (!$core->error->flag()) { 115 $plugins_install = $core->plugins->installModules(); 116 } 117 118 # -- Page header -- 191 119 dcPage::open(__('Plugins management'), 192 120 dcPage::jsLoad('js/_plugins.js'). 193 dcPage::jsPageTabs($default_tab), 121 dcPage::jsPageTabs(). 122 123 # --BEHAVIOR-- pluginsToolsHeaders 124 $core->callBehavior('pluginsToolsHeaders', $core, false), 125 194 126 dcPage::breadcrumb( 195 127 array( … … 199 131 ); 200 132 201 if (!empty($_GET['removed'])) { 202 dcPage::success(__('Plugin has been successfully deleted.')); 203 } 204 if (!empty($_GET['added'])) { 205 dcPage::success(($_GET['added'] == 2 ? __('Plugin has been successfully upgraded') : __('Plugin has been successfully installed.'))); 206 } 207 208 # Plugins install messages 209 if (!empty($plugins_install['success'])) 210 { 211 echo '<div class="static-msg">'.__('Following plugins have been installed:').'<ul>'; 133 # -- Succes messages -- 134 if (!empty($_GET['msg'])) { 135 $list->displayMessage($_GET['msg']); 136 } 137 138 # -- Plugins install messages -- 139 if (!empty($plugins_install['success'])) { 140 echo 141 '<div class="static-msg">'.__('Following plugins have been installed:').'<ul>'; 212 142 foreach ($plugins_install['success'] as $k => $v) { 213 echo '<li>'.$k.'</li>'; 214 } 215 echo '</ul></div>'; 216 } 217 if (!empty($plugins_install['failure'])) 218 { 219 echo '<div class="error">'.__('Following plugins have not been installed:').'<ul>'; 143 echo 144 '<li>'.$k.'</li>'; 145 } 146 echo 147 '</ul></div>'; 148 } 149 if (!empty($plugins_install['failure'])) { 150 echo 151 '<div class="error">'.__('Following plugins have not been installed:').'<ul>'; 220 152 foreach ($plugins_install['failure'] as $k => $v) { 221 echo '<li>'.$k.' ('.$v.')</li>'; 222 } 223 echo '</ul></div>'; 153 echo 154 '<li>'.$k.' ('.$v.')</li>'; 155 } 156 echo 157 '</ul></div>'; 158 } 159 160 # -- Display modules lists -- 161 if ($core->auth->isSuperAdmin() && $list->isPathWritable()) { 162 163 # Updated modules from repo 164 $modules = $repository->get(true); 165 if (!empty($modules)) { 166 echo 167 '<div class="multi-part" id="update" title="'.html::escapeHTML(__('Update plugins')).'">'. 168 '<h3>'.html::escapeHTML(__('Update plugins')).'</h3>'. 169 '<p>'.sprintf( 170 __('There is one plugin to update available from %2$s.', 'There are %s plugins to update available from %s.', count($modules)), 171 count($modules), 172 '<a href="http://dotaddict.org/dc2/plugins">Dotaddict</a>' 173 ).'</p>'; 174 175 $list 176 ->newList('plugin-update') 177 ->setModules($modules) 178 ->setPageTab('update') 179 ->displayModulesList( 180 /*cols */ array('icon', 'name', 'version', 'current_version', 'desc'), 181 /* actions */ array('update') 182 ); 183 184 echo 185 '</div>'; 186 } 224 187 } 225 188 226 189 # List all active plugins 227 echo '<p>'.__('Plugins add new functionalities to Dotclear. '.228 'Here you can activate or deactivate installed plugins.').'</p>';229 230 echo (!$core->plugins->moduleExists('daInstaller') ?231 sprintf('<p><strong>'.__('You can find additional plugins for your blog on %s.').'</strong></p>',232 '<a href="http://plugins.dotaddict.org/dc2/">Dotaddict</a>') :233 sprintf('<p><strong>'.__('You can find additional plugins for your blog on %s or using the %s.').'</strong></p>',234 '<a href="http://plugins.dotaddict.org/dc2/">Dotaddict</a>',235 '<a href="plugin.php?p=daInstaller">'.__('DotAddict.org Installer').'</a>'));236 237 if ($is_writable) {238 echo '<p>'.__('To install or upgrade a plugin you generally just need to upload it '.239 'in "Install or upgrade a plugin" section.');240 } else {241 echo '<p>'.__('To install or upgrade a plugin you just need to extract it in your plugins directory.');242 }243 echo '</p>';244 245 190 echo 246 '<div class="multi-part" id="plugins" title="'.__('Plugins').'">'; 247 248 $p_available = $core->plugins->getModules(); 249 uasort($p_available,create_function('$a,$b','return strcasecmp($a["name"],$b["name"]);')); 250 if (!empty($p_available)) 251 { 191 '<div class="multi-part" id="plugins" title="'.__('Installed plugins').'">'; 192 193 $modules = $core->plugins->getModules(); 194 if (!empty($modules)) { 195 252 196 echo 253 197 '<h3>'.__('Activated plugins').'</h3>'. 254 '<div class="table-outer clear">'. 255 '<table class="plugins"><tr>'. 256 '<th>'.__('Plugin').'</th>'. 257 '<th class="nowrap">'.__('Version').'</th>'. 258 '<th class="nowrap">'.__('Details').'</th>'. 259 '<th class="nowrap">'.__('Action').'</th>'. 260 '</tr>'; 261 262 $distrib_plugins = array('aboutConfig','akismet','antispam','attachments','blogroll','blowupConfig','daInstaller', 263 'fairTrackbacks','importExport','maintenance','pages','pings','simpleMenu','tags','themeEditor','userPref','widgets'); 264 $distrib_img = '<img src="images/dotclear_pw.png"'. 265 ' alt="'.__('Plugin from official distribution').'" title="'.__('Plugin from official distribution').'" />'; 266 267 foreach ($p_available as $k => $v) 268 { 269 $is_deletable = $is_writable && preg_match('!^'.$p_path_pat.'!',$v['root']); 270 $is_deactivable = $v['root_writable']; 271 $is_distrib = in_array($k, $distrib_plugins); 272 273 echo 274 '<tr class="line wide">'. 275 '<td class="minimal nowrap"><strong>'.html::escapeHTML($k).'</strong></td>'. 276 '<td class="minimal">'.html::escapeHTML($v['version']).'</td>'. 277 '<td class="maximal'.($is_distrib ? ' distrib' : '').'"><strong>'.html::escapeHTML(__($v['name'])).'</strong> '. 278 '<br />'.html::escapeHTML(__($v['desc'])).($is_distrib ? ' '.$distrib_img : '').'</td>'. 279 '<td class="nowrap action">'; 280 281 if ($is_deletable || $is_deactivable) 282 { 283 echo 284 '<form action="plugins.php" method="post">'. 285 '<div>'. 286 $core->formNonce(). 287 form::hidden(array('plugin_id'),html::escapeHTML($k)). 288 ($is_deactivable ? '<input type="submit" name="deactivate" value="'.__('Deactivate').'" /> ' : ''). 289 ($is_deletable ? '<input type="submit" class="delete" name="delete" value="'.__('Delete').'" /> ' : ''). 290 '</div>'. 291 '</form>'; 292 } 293 294 echo 295 '</td>'. 296 '</tr>'; 297 } 298 echo 299 '</table></div>'; 300 } 301 302 $p_disabled = $core->plugins->getDisabledModules(); 303 uksort($p_disabled,create_function('$a,$b','return strcasecmp($a,$b);')); 304 if (!empty($p_disabled)) 305 { 198 '<p>'.__('Manage installed plugins from this list.').'</p>'; 199 200 $list 201 ->newList('plugin-activate') 202 ->setModules($modules) 203 ->setPageTab('plugins') 204 ->displayModulesList( 205 /* cols */ array('expander', 'icon', 'name', 'config', 'version', 'desc', 'distrib'), 206 /* actions */ array('deactivate', 'delete') 207 ); 208 } 209 210 # Deactivated modules 211 $modules = $core->plugins->getDisabledModules(); 212 if (!empty($modules)) { 213 306 214 echo 307 215 '<h3>'.__('Deactivated plugins').'</h3>'. 308 '<div class="clear table-outer">'. 309 '<table class="plugins"><tr>'. 310 '<th>'.__('Plugin').'</th>'. 311 '<th class="nowrap">'.__('Action').'</th>'. 312 '</tr>'; 313 314 foreach ($p_disabled as $k => $v) 315 { 316 $is_deletable = $is_writable && preg_match('!^'.$p_path_pat.'!',$v['root']); 317 $is_activable = $v['root_writable']; 318 319 echo 320 '<tr class="line wide">'. 321 '<td class="maximal nowrap"><strong>'.html::escapeHTML($k).'</strong></td>'. 322 '<td class="nowrap action">'; 323 324 if ($is_deletable || $is_activable) 325 { 326 echo 327 '<form action="plugins.php" method="post">'. 328 '<div>'. 329 $core->formNonce(). 330 form::hidden(array('plugin_id'),html::escapeHTML($k)). 331 form::hidden(array('deactivated'),1). 332 ($is_activable ? '<input type="submit" name="activate" value="'.__('Activate').'" /> ' : ''). 333 ($is_deletable ? '<input type="submit" class="delete" name="delete" value="'.__('Delete').'" /> ' : ''). 334 '</div>'. 335 '</form>'; 336 } 337 338 echo 339 '</td>'. 340 '</tr>'; 341 } 342 echo 343 '</table></div>'; 344 } 345 346 echo '</div>'; 347 348 # Add a new plugin 349 echo 350 '<div class="multi-part" id="addplugin" title="'.__('Install or upgrade a plugin').'">'; 351 352 if ($is_writable) 353 { 216 '<p>'.__('Deactivated plugins are installed but not usable. You can activate them from here.').'</p>'; 217 218 $list 219 ->newList('plugin-deactivate') 220 ->setModules($modules) 221 ->setPageTab('plugins') 222 ->displayModulesList( 223 /* cols */ array('icon', 'name', 'distrib'), 224 /* actions */ array('activate', 'delete') 225 ); 226 } 227 228 echo 229 '</div>'; 230 231 if ($core->auth->isSuperAdmin() && $list->isPathWritable()) { 232 233 # New modules from repo 234 $search = $list->getSearchQuery(); 235 $modules = $search ? $repository->search($search) : $repository->get(); 236 237 echo 238 '<div class="multi-part" id="new" title="'.__('Add plugins from Dotaddict').'">'. 239 '<h3>'.__('Add plugins from Dotaddict repository').'</h3>'; 240 241 $list 242 ->newList('plugin-new') 243 ->setModules($modules) 244 ->setPageTab('new') 245 ->displaySearchForm() 246 ->displayNavMenu() 247 ->displayModulesList( 248 /* cols */ array('expander', 'name', 'version', 'desc'), 249 /* actions */ array('install'), 250 /* nav limit */ true 251 ); 252 253 echo 254 '<p class="info vertical-separator">'.sprintf( 255 __("Visit %s repository, the resources center for Dotclear."), 256 '<a href="http://dotaddict.org/dc2/plugins">Dotaddict</a>' 257 ). 258 '</p>'. 259 260 '</div>'; 261 262 # Add a new plugin 263 echo 264 '<div class="multi-part" id="addplugin" title="'.__('Install or upgrade manually').'">'; 265 354 266 echo '<p>'.__('You can install plugins by uploading or downloading zip files.').'</p>'; 355 267 356 # 'Upload plugin' form 357 echo 358 '<form method="post" action="plugins.php" id="uploadpkg" enctype="multipart/form-data" class="fieldset">'. 359 '<h3>'.__('Upload a zip file').'</h3>'. 360 '<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Plugin zip file:').'</label> '. 361 '<input type="file" id="pkg_file" name="pkg_file" /></p>'. 362 '<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '. 363 form::password(array('your_pwd','your_pwd1'),20,255).'</p>'. 364 '<p><input type="submit" name="upload_pkg" value="'.__('Upload plugin').'" />'. 365 $core->formNonce(). 366 '</p>'. 367 '</form>'; 368 369 # 'Fetch plugin' form 370 echo 371 '<form method="post" action="plugins.php" id="fetchpkg" class="fieldset">'. 372 '<h3>'.__('Download a zip file').'</h3>'. 373 '<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Plugin zip file URL:').'</label> '. 374 form::field(array('pkg_url','pkg_url'),40,255).'</p>'. 375 '<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '. 376 form::password(array('your_pwd','your_pwd2'),20,255).'</p>'. 377 '<p><input type="submit" name="fetch_pkg" value="'.__('Download plugin').'" />'. 378 $core->formNonce().'</p>'. 379 '</form>'; 380 } 381 else 382 { 383 echo 384 '<p class="static-msg">'. 385 __('To enable this function, please give write access to your plugins directory.'). 386 '</p>'; 387 } 388 echo '</div>'; 268 $list->displayManualForm(); 269 270 echo 271 '</div>'; 272 } 389 273 390 274 # --BEHAVIOR-- pluginsToolsTabs 391 $core->callBehavior('pluginsToolsTabs',$core); 275 $core->callBehavior('pluginsToolsTabs', $core); 276 277 # -- Notice for super admin -- 278 if ($core->auth->isSuperAdmin() && !$list->isPathWritable()) { 279 echo 280 '<p class="warning">'.__('Some functions are disabled, please give write access to your plugins directory to enable them.').'</p>'; 281 } 392 282 393 283 dcPage::close(); -
admin/services.php
r1699 r2174 27 27 $core->rest->addFunction('searchMeta',array('dcRestMethods','searchMeta')); 28 28 $core->rest->addFunction('setSectionFold',array('dcRestMethods','setSectionFold')); 29 $core->rest->addFunction('getModuleById',array('dcRestMethods','getModuleById')); 29 30 30 31 $core->rest->serve(); … … 442 443 return true; 443 444 } 444 445 445 446 public static function getModuleById($core, $get, $post) 447 { 448 if (empty($get['id'])) { 449 throw new Exception('No module ID'); 450 } 451 if (empty($get['list'])) { 452 throw new Exception('No list ID'); 453 } 454 455 $id = $get['id']; 456 $list = $get['list']; 457 $module = array(); 458 459 if ($list == 'plugin-activate') { 460 $modules = $core->plugins->getModules(); 461 if (empty($modules) || !isset($modules[$id])) { 462 throw new Exception('Unknow module ID'); 463 } 464 $module = $modules[$id]; 465 } 466 elseif ($list == 'plugin-new') { 467 $repository = new dcRepository( 468 $core->plugins, 469 $core->blog->settings->system->repository_plugin_url 470 ); 471 $repository->check(); 472 473 $modules = $repository->get(); 474 if (empty($modules) || !isset($modules[$id])) { 475 throw new Exception('Unknow module ID'); 476 } 477 $module = $modules[$id]; 478 } 479 else { 480 // behavior not implemented yet 481 } 482 483 if (empty($module)) { 484 throw new Exception('Unknow module ID'); 485 } 486 487 $module = adminModulesList::parseModuleInfo($id, $module); 488 489 $rsp = new xmlTag('module'); 490 $rsp->id = $id; 491 492 foreach($module as $k => $v) { 493 $rsp->{$k}((string) $v); 494 } 495 496 return $rsp; 497 } 446 498 } 447 499 ?> -
admin/style/default.css
r2152 r2195 158 158 -moz-box-sizing: border-box; 159 159 -webkit-box-sizing: border-box; 160 box-sizing: border-box; 160 box-sizing: border-box; 161 text-align: left; 161 162 } 162 163 .two-boxes { … … 1532 1533 } 1533 1534 /* ------------------------------------------------------------------- blog_theme.php */ 1534 #themes { 1535 margin: 0; 1536 width: 100%; 1537 padding: 0; 1538 } 1539 .theme-details { 1540 border-top: 1px solid #ccc; 1541 padding: 12px; 1542 display: inline-block; 1543 vertical-align: top; 1544 width: 284px; 1545 } 1546 .theme-details.current-theme { 1547 background: #eef; 1548 } 1549 .theme-details:hover { 1550 background: #f3f3f3; 1551 } 1552 .theme-shot img { 1553 display: block; 1554 border: 1px solid #ccc; 1555 margin-bottom: 1.5em; 1556 } 1557 span.theme-desc { 1558 display: block; 1559 } 1560 span.theme-version { 1561 color: #676e78; 1562 } 1563 .theme-css { 1564 display: block; 1565 } 1566 #themes-actions { 1567 border-bottom: 1px solid #999; 1568 margin-bottom: 3em; 1569 } 1570 /* Themes list, JS version */ 1571 #themes-wrapper { 1572 display: table; 1573 } 1574 #themes-wrapper #themes { 1575 display: table-cell; 1576 vertical-align: top; 1577 padding-left: 1em; 1578 } 1579 #theme-box { 1580 display: table-cell; 1581 vertical-align: top; 1582 padding: 0; 1583 width: 312px; 1584 border: 1px solid #ccc; 1585 border-radius: 3px; 1586 } 1587 #theme-box .theme-shot, 1588 #theme-box .theme-info, 1589 #theme-box .theme-actions { 1590 background: #eef; 1591 padding: 1em 16px; 1592 margin: 0; 1593 } 1594 #theme-box .theme-shot img { 1595 display: block; 1596 width: 280px; 1597 height: 245px; 1598 border: 1px solid #ccc; 1599 } 1600 #theme-box h4 { 1601 color: #000; 1602 background: #eef; 1603 } 1604 #theme-box span.theme-version { 1605 color: #676e78; 1606 } 1607 #theme-box span.theme-parent-ok { 1608 color: #676e78; 1609 } 1610 #theme-box span.theme-parent-missing { 1611 color: #c00; 1612 font-weight:bold; 1613 } 1614 #theme-box .theme-actions { 1615 border-bottom: 1px solid #ccc; 1616 } 1617 #themes .theme-details-js { 1535 .box.theme { 1536 margin: .5em; 1537 padding: 1em 1em .5em 1em; 1538 border: 1px solid #ccc; 1539 } 1540 .box.current-theme { 1541 width: 652px; 1542 margin: .5em; 1543 padding: 1em 0 .5em 1em; 1544 background: #FCFDFD; 1545 border: 1px solid #9AC123; 1546 -webkit-border-radius: .5em; 1547 border-radius: .5em; 1548 } 1549 #theme-new .box.theme { 1550 width: 280px; 1551 } 1552 .module-name { 1553 margin-bottom: .5em; 1554 } 1555 .module-sshot img { 1556 border: 1px solid #ddd; 1557 padding: .5em; 1558 background: #f7f7f7; 1559 box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); 1560 } 1561 .module-actions { 1562 margin-top: 1em; 1563 } 1564 .current-theme .module-sshot img { 1618 1565 float: left; 1619 width: 120px;1620 height: 150px;1621 margin: 0 12px 24px;1622 padding: 12px 12px 0; 1566 margin-right: 2em; 1567 margin-bottom: 1em; 1568 } 1569 .bloc-toggler { 1623 1570 text-align: center; 1624 background: #f3f3f3; 1625 border: 1px solid #ddd; 1626 cursor: pointer; 1627 border-radius: 4px; 1628 } 1629 #themes .theme-details-js label { 1630 cursor: pointer; 1631 } 1632 #themes .theme-details-js.theme-selected { 1633 background: #e7e7e7; 1634 border: 1px solid #999; 1635 } 1636 #themes .theme-details-js .theme-shot img { 1637 width: 120px; 1638 height: 105px; 1639 border: 1px solid #fff; 1640 } 1641 #themes a:focus div, #themes a:hover div, 1642 #themes a:focus div.current-theme, #themes a:hover div.current-theme { 1643 background: #bee74b; 1644 } 1571 } 1645 1572 /* ------------------------------------------------------------------ categories.php */ 1646 1573 #categories { … … 1947 1874 } 1948 1875 /* -------------------------------------------------------------------- plugins.php */ 1949 #plugins td.action {1876 .modules td.module-actions, .modules td.module-icon { 1950 1877 vertical-align: middle; 1951 1878 } 1952 .distrib img { 1879 .modules td.module-icon img:last-child { 1880 width: 16px; 1881 height: 16px; 1882 } 1883 .modules td.module-icon img.expand { 1884 margin-bottom: 3px; 1885 } 1886 .modules td.module-distrib img { 1953 1887 display: block; 1954 1888 float: right; 1955 margin-top: -1em; 1889 } 1890 .modules dt { 1891 font-weight: bold; 1892 } 1893 .modules a.module-details { 1894 background: transparent url(search.png) no-repeat 2px 2px; 1895 padding: 4px 4px 0 20px; 1896 } 1897 .modules a.module-support { 1898 background: transparent url(../images/page_help.png) no-repeat 2px 2px; 1899 padding: 4px 4px 0 20px; 1900 } 1901 #m_search { 1902 background: transparent url(search.png) no-repeat 4px center; 1903 padding-left: 20px; 1904 } 1905 .modules tr.expand, .modules td.expand { 1906 background: #f7f7f7; 1907 border-color: #bee74b; 1908 } 1909 .modules tr.expand td:first-child { 1910 font-weight: bold; 1911 background: #DFE5E7; 1912 } 1913 .modules td.expand { 1914 padding: 0; 1915 } 1916 .mod-more, .mod-more li { 1917 margin: .25em 0 0 1em; 1918 padding: 0; 1919 list-style-type: none; 1920 } 1921 .mod-more { 1922 padding-top: .5em; 1956 1923 } 1957 1924 /* ---------------------------------------------------------- post.php, page.php */ -
inc/admin/lib.dc.page.php
r2191 r2196 571 571 self::jsVar('dotclear.img_menu_on','images/menu_on.png'). 572 572 self::jsVar('dotclear.img_menu_off','images/menu_off.png'). 573 574 self::jsVar('dotclear.img_plus_theme_src','images/plus-theme.png'). 575 self::jsVar('dotclear.img_plus_theme_alt',__('uncover')). 576 self::jsVar('dotclear.img_minus_theme_src','images/minus-theme.png'). 577 self::jsVar('dotclear.img_minus_theme_alt',__('hide')). 573 578 574 579 self::jsVar('dotclear.msg.help', … … 654 659 self::jsVar('dotclear.msg.load_enhanced_uploader', 655 660 __('Loading enhanced uploader, please wait.')). 661 662 self::jsVar('dotclear.msg.module_author', 663 __('Author:')). 664 self::jsVar('dotclear.msg.module_details', 665 __('Details')). 666 self::jsVar('dotclear.msg.module_support', 667 __('Support')). 668 self::jsVar('dotclear.msg.module_help', 669 __('Help:')). 670 self::jsVar('dotclear.msg.module_section', 671 __('Section:')). 672 self::jsVar('dotclear.msg.module_tags', 673 __('Tags:')). 656 674 "\n//]]>\n". 657 675 "</script>\n"; -
inc/prepend.php
r1999 r2147 46 46 $__autoload['dcWorkspace'] = dirname(__FILE__).'/core/class.dc.workspace.php'; 47 47 $__autoload['dcPrefs'] = dirname(__FILE__).'/core/class.dc.prefs.php'; 48 $__autoload['dcRepository'] = dirname(__FILE__).'/core/class.dc.repository.php'; 49 $__autoload['dcRepositoryReader'] = dirname(__FILE__).'/core/class.dc.repository.reader.php'; 50 $__autoload['dcRepositoryParser'] = dirname(__FILE__).'/core/class.dc.repository.parser.php'; 48 51 49 52 $__autoload['rsExtPost'] = dirname(__FILE__).'/core/class.dc.rs.extensions.php'; … … 61 64 $__autoload['dcPager'] = dirname(__FILE__).'/admin/lib.pager.php'; 62 65 $__autoload['dcAdminCombos'] = dirname(__FILE__).'/admin/lib.admincombos.php'; 66 $__autoload['adminModulesList'] = dirname(__FILE__).'/admin/lib.moduleslist.php'; 67 $__autoload['adminThemesList'] = dirname(__FILE__).'/admin/lib.moduleslist.php'; 63 68 64 69 $__autoload['dcTemplate'] = dirname(__FILE__).'/public/class.dc.template.php'; -
plugins/maintenance/_admin.php
r2177 r2196 29 29 $core->addBehavior('adminAfterDashboardOptionsUpdate', array('dcMaintenanceAdmin', 'adminAfterDashboardOptionsUpdate')); 30 30 $core->addBehavior('adminPageHelpBlock', array('dcMaintenanceAdmin', 'adminPageHelpBlock')); 31 $core->addBehavior('pluginsToolsHeaders', array('dcMaintenanceAdmin', 'pluginsToolsHeaders')); 31 32 32 33 /** … … 223 224 $core->auth->user_prefs->maintenance->put('dashboard_item', !empty($_POST['maintenance_dashboard_item']), 'boolean'); 224 225 } 225 226 226 227 227 /** … … 294 294 } 295 295 } 296 297 /** 298 * Add javascript for plugin configuration. 299 * 300 * @param $core <b>dcCore</b> dcCore instance 301 * @param $module <b>mixed</b> Module ID or false if none 302 * @return <b>string</b> Header code for js inclusion 303 */ 304 public static function pluginsToolsHeaders($core, $module) 305 { 306 if ($module == 'maintenance') { 307 return dcPage::jsLoad('index.php?pf=maintenance/js/settings.js'); 308 } 309 } 296 310 } -
plugins/maintenance/index.php
r2166 r2175 27 27 $code = empty($_POST['code']) ? null : (integer) $_POST['code']; 28 28 $tab = empty($_REQUEST['tab']) ? '' : $_REQUEST['tab']; 29 30 // Save settings31 32 if (!empty($_POST['settings'])) {33 34 try {35 $core->blog->settings->maintenance->put(36 'plugin_message',37 !empty($_POST['settings_plugin_message']),38 'boolean',39 'Display alert message of late tasks on plugin page',40 true,41 true42 );43 44 foreach($tasks as $t) {45 if (!empty($_POST['settings_recall_type']) && $_POST['settings_recall_type'] == 'all') {46 $ts = $_POST['settings_recall_time'];47 }48 else {49 $ts = empty($_POST['settings_ts_'.$t->id()]) ? 0 : $_POST['settings_ts_'.$t->id()];50 }51 $core->blog->settings->maintenance->put(52 'ts_'.$t->id(),53 abs((integer) $ts),54 'integer',55 sprintf('Recall time for task %s', $t->id()),56 true,57 $t->blog()58 );59 }60 61 http::redirect($p_url.'&done=1&tab='.$tab.'#'.$tab);62 }63 catch(Exception $e) {64 $core->error->add($e->getMessage());65 }66 }67 29 68 30 // Get task object … … 287 249 '</div>'; 288 250 } 289 290 // Settings291 292 echo293 '<div id="settings" class="multi-part" title="'.__('Alert settings').'">'.294 '<h3>'.__('Alert settings').'</h3>'.295 '<form action="'.$p_url.'" method="post">'.296 297 '<h4 class="pretty-title">'.__('Activation').'</h4>'.298 '<p><label for="settings_plugin_message" class="classic">'.299 form::checkbox('settings_plugin_message', 1, $core->blog->settings->maintenance->plugin_message).300 __('Display alert messages on late tasks').'</label></p>'.301 302 '<p class="info">'.sprintf(303 __('You can place list of late tasks on your %s.'),304 '<a href="preferences.php#user-favorites">'.__('Dashboard').'</a>'305 ).'</p>'.306 307 '<h4 class="pretty-title vertical-separator">'.__('Frequency').'</h4>'.308 309 '<p class="vertical-separator">'.form::radio(array('settings_recall_type', 'settings_recall_all'), 'all').' '.310 '<label class="classic" for="settings_recall_all">'.311 '<strong>'.__('Use one recall time for all tasks').'</strong></label>'.312 313 '<p class="field wide vertical-separator"><label for="settings_recall_time">'.__('Recall time for all tasks:').'</label>'.314 form::combo('settings_recall_time', $combo_ts, 'seperate', 'recall-for-all').315 '</p>'.316 317 '<p class="vertical-separator">'.form::radio(array('settings_recall_type', 'settings_recall_separate'), 'separate', 1).' '.318 '<label class="classic" for="settings_recall_separate">'.319 '<strong>'.__('Use one recall time per task').'</strong></label>';320 321 foreach($tasks as $t)322 {323 echo324 '<div class="two-boxes">'.325 326 '<p class="field wide"><label for="settings_ts_'.$t->id().'">'.$t->task().'</label>'.327 form::combo('settings_ts_'.$t->id(), $combo_ts, $t->ts(), 'recall-per-task').328 '</p>'.329 330 '</div>';331 }332 333 echo334 '<p class="field wide"><input type="submit" value="'.__('Save this settings').'" /> '.335 form::hidden(array('tab'), 'settings').336 form::hidden(array('settings'), 1).337 $core->formNonce().'</p>'.338 '</form>'.339 '</div>';340 251 } 341 252
Note: See TracChangeset
for help on using the changeset viewer.