if (!empty($plug['changelog'])) { $pluginInfo[] = '<a href="' . htmlspecialchars($plug['changelog']) . '">' . PLUGIN_DOCUMENTATION_CHANGELOG . '</a>'; } if (!empty($plug['upgrade_version']) && $plug['upgrade_version'] != $plug['version']) { $pluginInfo[] = sprintf(UPGRADE_TO_VERSION, $plug['upgrade_version']); } if (!empty($plug['pluginlocation']) && $plug['pluginlocation'] != 'local') { $pluginInfo[] = '(' . htmlspecialchars($plug['pluginlocation']) . ')'; $installimage = serendipity_getTemplateFile('admin/img/install_now_' . strtolower($plug['pluginlocation']) . '.png'); } else { $installimage = serendipity_getTemplateFile('admin/img/install_now.png'); } if (!isset($plug['customURI'])) { $plug['customURI'] = ''; } if (!empty($plug['requirements']['serendipity']) && version_compare($plug['requirements']['serendipity'], serendipity_getCoreVersion($serendipity['version']), '>')) { $notice['requirements_failures'][] = 's9y ' . $plug['requirements']['serendipity']; } if (!empty($plug['requirements']['php']) && version_compare($plug['requirements']['php'], phpversion(), '>')) { $notice['requirements_failures'][] = 'PHP ' . $plug['requirements']['php']; } /* Enable after Smarty 2.6.7 upgrade. * TODO: How can we get current Smarty version here? $smarty is not created! if ( !empty($plug['requirements']['smarty']) && version_compare($plug['requirements']['smarty'], '2.6.7', '>') ) { $notice['requirements_failures'][] = 'Smarty: ' . $plug['requirements']['smarty']; } */ if (count($notice['requirements_failures']) > 0) { $plug['requirements_fail'] = true; } ?>
function inspectConfig($is_smarty, $what, $elcount, $config_item, $config_value, $type, $cname, $cdesc, $value, $default, $lang_direction, $hvalue, $radio, $radio2, $select, $per_row, $per_row2) { global $serendipity; if ($is_smarty && $what == 'desc') { echo $cdesc; return true; } if ($is_smarty && $what == 'name') { echo $cname; return true; } switch ($type) { case 'seperator': ?> <tr> <td colspan="2"><hr noshade="noshade" size="1" /></td> </tr> <?php break; case 'select': if (!$is_smarty) { ?> <tr> <td style="border-bottom: 1px solid #000000; vertical-align: top"><strong><?php echo $cname; ?> </strong> <?php if ($cdesc != '') { ?> <br><span style="color: #5E7A94; font-size: 8pt;"> <?php echo $cdesc; ?> </span> <?php } ?> </td> <td style="border-bottom: 1px solid #000000; vertical-align: middle" width="250"> <div> <?php } ?> <select class="direction_<?php echo $lang_direction; ?> " name="serendipity[plugin][<?php echo $config_item; ?> ]"> <?php foreach ($select as $select_value => $select_desc) { $id = function_exists('serendipity_specialchars') ? serendipity_specialchars($config_item . $select_value) : htmlspecialchars($config_item . $select_value, ENT_COMPAT, LANG_CHARSET); ?> <option title="<?php echo function_exists('serendipity_specialchars') ? serendipity_specialchars($select_desc) : htmlspecialchars($select_desc, ENT_COMPAT, LANG_CHARSET); ?> "<?php echo $select_value == $hvalue ? ' selected="selected"' : ''; ?> value="<?php echo $select_value; ?> "><?php echo function_exists('serendipity_specialchars') ? serendipity_specialchars($select_desc) : htmlspecialchars($select_desc, ENT_COMPAT, LANG_CHARSET); ?> </option> <?php } ?> </select> <?php if (!$is_smarty) { ?> </div> </td> </tr> <?php } break; case 'tristate': $per_row = 3; $radio['value'][] = 'default'; $radio['desc'][] = USE_DEFAULT; case 'boolean': $radio['value'][] = 'true'; $radio['desc'][] = YES; $radio['value'][] = 'false'; $radio['desc'][] = NO; case 'radio': if (!count($radio) > 0) { $radio = $radio2; } if (empty($per_row)) { $per_row = $per_row2; if (empty($per_row)) { $per_row = 2; } } if (!$is_smarty) { ?> <tr> <td style="border-bottom: 1px solid #000000; vertical-align: top"><strong><?php echo $cname; ?> </strong> <?php if ($cdesc != '') { ?> <br /><span style="color: #5E7A94; font-size: 8pt;"> <?php echo $cdesc; ?> </span> <?php } ?> </td> <td style="border-bottom: 1px solid #000000; vertical-align: middle;" width="250"> <?php } $counter = 0; foreach ($radio['value'] as $radio_index => $radio_value) { $id = function_exists('serendipity_specialchars') ? serendipity_specialchars($config_item . $radio_value) : htmlspecialchars($config_item . $radio_value, ENT_COMPAT, LANG_CHARSET); $counter++; $checked = ""; if ($radio_value == 'true' && ($hvalue === '1' || $hvalue === 'true')) { $checked = " checked"; } elseif ($radio_value == 'false' && ($hvalue === '' || $hvalue === '0' || $hvalue === 'false')) { $checked = " checked"; } elseif ($radio_value == $hvalue) { $checked = " checked"; } if ($counter == 1) { ?> <div> <?php } ?> <input class="input_radio direction_<?php echo $lang_direction; ?> " type="radio" id="serendipity_plugin_<?php echo $id; ?> " name="serendipity[plugin][<?php echo $config_item; ?> ]" value="<?php echo $radio_value; ?> " <?php echo $checked; ?> title="<?php echo function_exists('serendipity_specialchars') ? serendipity_specialchars($radio['desc'][$radio_index]) : htmlspecialchars($radio['desc'][$radio_index], ENT_COMPAT, LANG_CHARSET); ?> " /> <label for="serendipity_plugin_<?php echo $id; ?> "><?php echo function_exists('serendipity_specialchars') ? serendipity_specialchars($radio['desc'][$radio_index]) : htmlspecialchars($radio['desc'][$radio_index], ENT_COMPAT, LANG_CHARSET); ?> </label> <?php if ($counter == $per_row) { $counter = 0; ?> </div> <?php } } if (!$is_smarty) { ?> </td> </tr> <?php } break; case 'string': if (!$is_smarty) { ?> <tr> <td style="border-bottom: 1px solid #000000"> <strong><?php echo $cname; ?> </strong> <br><span style="color: #5E7A94; font-size: 8pt;"> <?php echo $cdesc; ?> </span> </td> <td style="border-bottom: 1px solid #000000" width="250"> <div> <?php } ?> <input class="input_textbox direction_<?php echo $lang_direction; ?> " type="text" name="serendipity[plugin][<?php echo $config_item; ?> ]" value="<?php echo $hvalue; ?> " size="30" /> <?php if (!$is_smarty) { ?> </div> </td> </tr> <?php } break; case 'html': case 'text': if (!$is_smarty) { echo '<tr>'; } if (!$serendipity['wysiwyg']) { if (!$is_smarty) { ?> <td><strong><?php echo $cname; ?> </strong> <span style="color: #5E7A94; font-size: 8pt;"> <?php echo $cdesc; ?> </span></td> <td align="right"> <?php } if (!$serendipity['wysiwyg']) { ?> <nobr><span id="tools_<?php echo $config_item; ?> " style="display: none"> <?php if ($serendipity['nl2br']['iso2br']) { ?> <input type="button" class="serendipityPrettyButton input_button" name="insX" value="NoBR" accesskey="x" style="font-style: italic" onclick="wrapSelection(document.forms['serendipityEntry']['serendipity[plugin][<?php echo $config_item; ?> ]'],'<nl>','</nl>')" /> <?php } ?> <input type="button" class="serendipityPrettyButton input_button wrap_selection" name="insI" value="I" accesskey="i" data-tarea="nuggets<?php echo $elcount; ?> " data-tag="em" style="font-style: italic" onclick="wrapSelection(document.forms['serendipityEntry']['serendipity[plugin][<?php echo $config_item; ?> ]'],'<em>','</em>')" /> <input type="button" class="serendipityPrettyButton input_button wrap_selection" name="insB" value="B" accesskey="b" data-tarea="nuggets<?php echo $elcount; ?> " data-tag="strong" style="font-weight: bold" onclick="wrapSelection(document.forms['serendipityEntry']['serendipity[plugin][<?php echo $config_item; ?> ]'],'<strong>','</strong>')" /> <input type="button" class="serendipityPrettyButton input_button wrap_selection" name="insU" value="U" accesskey="u" data-tarea="nuggets<?php echo $elcount; ?> " data-tag="u" style="text-decoration: underline;" onclick="wrapSelection(document.forms['serendipityEntry']['serendipity[plugin][<?php echo $config_item; ?> ]'],'<u>','</u>')" /> <input type="button" class="serendipityPrettyButton input_button wrap_selection" name="insQ" value="<?php echo QUOTE; ?> " accesskey="q" data-tarea="nuggets<?php echo $elcount; ?> " data-tag="blockquote" style="font-style: italic" onclick="wrapSelection(document.forms['serendipityEntry']['serendipity[plugin][<?php echo $config_item; ?> ]'],'<blockquote>','</blockquote>')" /> <input type="button" class="serendipityPrettyButton input_button wrap_insimg" name="insJ" value="img" accesskey="j" data-tarea="nuggets<?php echo $elcount; ?> " onclick="wrapInsImage(document.forms['serendipityEntry']['serendipity[plugin][<?php echo $config_item; ?> ]'])" /> <?php if (version_compare(serendipity_getCoreVersion($serendipity['version']), "2.0", ">=")) { ?> <button class="wrap_insmedia" type="button" name="insImage" data-tarea="nuggets<?php echo $elcount; ?> "><?php echo MEDIA; ?> </button> <?php } else { ?> <input type="button" class="serendipityPrettyButton input_button wrap_insmedia" name="insImage" value="<?php echo MEDIA; ?> " style="" onclick="window.open('serendipity_admin_image_selector.php?serendipity[textarea]=<?php echo urlencode('serendipity[plugin][' . $config_item . ']'); ?> ', 'ImageSel', 'width=800,height=600,toolbar=no,scrollbars=1,scrollbars,resize=1,resizable=1');" /> <?php } ?> <input type="button" class="serendipityPrettyButton input_button wrap_insurl" name="insU" value="URL" accesskey="l" data-tarea="nuggets<?php echo $elcount; ?> " style="color: blue; text-decoration: underline;" onclick="wrapSelectionWithLink(document.forms['serendipityEntry']['serendipity[plugin][<?php echo $config_item; ?> ]'])" /> </span></nobr> <?php } ?> <script type="text/javascript" language="JavaScript"> var tb_<?php echo $config_item; ?> = document.getElementById('tools_<?php echo $config_item; ?> '); tb_<?php echo $config_item; ?> .style.display = ''; </script> <?php if (version_compare(serendipity_getCoreVersion($serendipity['version']), "2.0", ">=")) { ?> <script src="<?php echo serendipity_getTemplateFile('admin/js/jquery.magnific-popup.js'); ?> "></script><?php } // add extra data in the entry's array so that emoticonchooser plugin // behaves well with wysiwyg editors, then clean up ;-) (same apply below) $entry['backend_entry_toolbar_body:nugget'] = 'nuggets' . $elcount; $entry['backend_entry_toolbar_body:textarea'] = 'serendipity[plugin][' . $config_item . ']'; serendipity_plugin_api::hook_event('backend_entry_toolbar_body', $entry); unset($entry['backend_entry_toolbar_body:textarea']); unset($entry['backend_entry_toolbar_body:nugget']); } else { if (!$is_smarty) { ?> <td colspan="2"><strong><?php echo $cname; ?> </strong> <span style="color: #5E7A94; font-size: 8pt;"> <?php echo $cdesc; ?> </span></td> <td> <?php } if (version_compare(serendipity_getCoreVersion($serendipity['version']), "2.0", ">=")) { serendipity_emit_htmlarea_code("nuggets{$elcount}", ""); ?> <script src="<?php echo serendipity_getTemplateFile('admin/js/jquery.magnific-popup.js'); ?> "></script><?php } $entry['backend_entry_toolbar_body:nugget'] = 'nuggets' . $elcount; $entry['backend_entry_toolbar_body:textarea'] = 'serendipity[plugin][' . $config_item . ']'; serendipity_plugin_api::hook_event('backend_entry_toolbar_body', $entry); unset($entry['backend_entry_toolbar_body:textarea']); unset($entry['backend_entry_toolbar_body:nugget']); ?> <?php } if (!$is_smarty) { ?> </td> </tr> <tr> <td colspan="2"> <?php } ?> <div> <textarea class="direction_<?php echo $lang_direction; ?> " style="width: 100%" id="nuggets<?php echo $elcount; ?> " name="serendipity[plugin][<?php echo $config_item; ?> ]" rows="20" cols="80"><?php echo $hvalue; ?> </textarea> </div> <?php if (!$is_smarty) { ?> </td> </tr> <?php } if ($type == 'html') { $this->htmlnugget[] = $elcount; if (version_compare(preg_replace('@[^0-9\\.]@', '', $serendipity['version']), '0.9', '<')) { serendipity_emit_htmlarea_code('nuggets' . $elcount, 'nuggets' . $elcount); } else { serendipity_emit_htmlarea_code('nuggets', 'nuggets', true); } } break; case 'content': if (!$is_smarty) { ?> <tr><td colspan="2"><?php echo $default; ?> </td></tr><?php } else { echo $default; } break; case 'hidden': if (!$is_smarty) { ?> <tr><td colspan="2"><?php } ?> <input class="direction_<?php echo $lang_direction; ?> " type="hidden" name="serendipity[plugin][<?php echo $config_item; ?> ]" value="<?php echo $value; ?> " /><?php if (!$is_smarty) { ?> </td></tr><?php } break; case 'timestamp': if (!$is_smarty) { ?> <tr> <td style="border-bottom: 1px solid #000000"> <strong><?php echo $cname; ?> </strong> <br><span style="color: #5E7A94; font-size: 8pt;"> <?php echo $cdesc; ?> </span> </td> <td style="border-bottom: 1px solid #000000" width="250"> <div> <?php } ?> <input class="input_textbox direction_<?php echo $lang_direction; ?> " type="text" name="serendipity[plugin][<?php echo $config_item; ?> ]" value="<?php echo serendipity_strftime(DATE_FORMAT_SHORT, $hvalue); ?> " size="30" /> <?php if (!$is_smarty) { ?> </div> </td> </tr> <?php } break; } }
function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks =& $bag->get('event_hooks'); if (isset($hooks[$event])) { switch ($event) { case 'backend_entry_presave': if (isset($serendipity['POST']['shadowed']) && is_numeric($serendipity['POST']['shadowed'])) { // update last_modified to make sure the shadow copy is more recent than the original post $eventData['last_modified'] = time(); } break; case 'backend_save': // dirty hack to confirm an entry has been saved $this->saveSuccessfull = true; // entry has been successfully saved, delete shadow copies of it (if any) // REM: this hook is also called when saving the shadow copy $ret = serendipity_db_query("SELECT value FROM {$serendipity['dbPrefix']}entryproperties " . "WHERE entryid={$eventData['id']} AND property='" . PLUGIN_EVENT_AUTOSAVE_PROP_SHADOW . "'", true); if (is_array($ret)) { // drop shadow copy and extra properties serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}entries WHERE id=" . (int) current($ret)); serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}entryproperties " . "WHERE entryid={$eventData['id']} AND property='" . PLUGIN_EVENT_AUTOSAVE_PROP_SHADOW . "'", true); } break; case 'backend_entryform': if (version_compare(serendipity_getCoreVersion($serendipity['version']), "2.0", ">=")) { // Autosave plugin no longer supported echo '<p>The serendipity_event_autosave Plugin is no longer supported in Serendipity 2.0 - you should remove it from your installation.</p>'; echo '<p>Please note that Serendipity 2.0 will save your written entry in the browser, and restore it upon crash.</p>'; return true; } ?> <script type="text/javascript" src="<?php echo $this->get_config('path'); ?> /js/prototype.js"></script> <script type="text/javascript" src="<?php echo $this->get_config('path'); ?> /js/rico.js"></script> <script type="text/javascript"> // global variables var autosaveIsAlreadyRunning = false; var autosaveUseShadowCopy = false; var autosaveShadowCanRecover = false; var autosaveShadowCopyId = 0; <?php // when editing an already published post, autosave shouldn't overwrite the existing entry // (because it would toggle the draft status, which would make the entry disappear suddenly // from the frontend and it would update post with partial data ... bad trip !) // in that case, we use a "shadow copy" of the entry for saving (another entry saved as // draft) and attach a property to the real entry in order to link the two // (the fake entry will be deleting when saving the real entry) if ($eventData['isdraft'] !== 'true' && is_numeric($eventData['id'])) { // enable shadow copy echo "autosaveUseShadowCopy=true;\n"; // search a shadowed copy of this post if it exists (needed for example when previewing) // REM: join on the entries table to make sure this is not garbage data which should have been deleted previously $ret = serendipity_db_query("SELECT ep.value, e.id, e.last_modified " . "FROM {$serendipity['dbPrefix']}entryproperties ep " . "LEFT JOIN {$serendipity['dbPrefix']}entries e ON ep.value=e.id " . "WHERE ep.entryid={$eventData['id']} AND ep.property='" . PLUGIN_EVENT_AUTOSAVE_PROP_SHADOW . "'", true); // found a matching row, this should be the id of the associated shadow copy ... // if no row found, a new shadow entry will be created on first ajax call if (is_array($ret)) { if ($ret[1] == NULL) { // oh oh, this was garbage data not linked to any entry, delete it now serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}entryproperties " . "WHERE entryid={$eventData['id']} AND property='" . PLUGIN_EVENT_AUTOSAVE_PROP_SHADOW . "'"); } else { // autosaved data exists, recovering is possible ... echo "autosaveShadowCopyId=" . (int) current($ret) . ";\n"; if (!isset($serendipity['POST']['preview']) || $serendipity['POST']['preview'] !== 'true') { // user is not previewing, he must be editing an already published post for the first time if ((int) $ret[2] > $eventData['last_modified']) { // autosaved data are more recent than original post // propose a link to recover autosaved data "inline" echo 'autosaveShadowCanRecover=true;'; } } } // end if } } ?> // helper functions function red(mesg) { return '<span style="color: red;">' + mesg + '</span>'; } function green(mesg) { return '<span style="color: green;">' + mesg + '</span>'; } // register ajax stuff once the page is loaded (addLoadEvent() is provided by serendipity ;-)) addLoadEvent(function() { //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // This object is a listener that will be used to dynamically // update the page when an ajax query (response in fact :-)) comes back //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- var AutosaveUpdater = Class.create(); AutosaveUpdater.prototype = { // "constructor" initialize: function() { }, // call by the engine when server has replied ajaxUpdate: function(ajaxResponse) { try { var tag = document.getElementById('autosaveResult'); var obj = ajaxResponse.childNodes[0]; if(obj == null ||typeof(obj) == 'undefined') { tag.innerHTML = red('<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_AJAX_ERROR); ?> '); } else { // depending on the name of the received xml element, // different actions are taken (one object for multiple purpose) if(obj.tagName == 'save') { //-------------------------------------------------- // entry has been saved, update important fields //-------------------------------------------------- var entryId = obj.getAttribute('id'); if(entryId == 0) { tag.innerHTML = red('<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_SAVE_ERROR); ?> '); } else { if(autosaveUseShadowCopy) autosaveShadowCopyId = entryId; else //document.getElementById('entryid').value = entryId; document.forms[0].elements['serendipity[id]'].value = entryId; // tell the user that save succeeded :-) tag.innerHTML = green(entryId + ' : <?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_SAVED); ?> '); } } /*else if(obj.tagName == 'restore') { //-------------------------------------------------- // received the shadow copy for « inline updating » //-------------------------------------------------- var f = document.forms['serendipityEntry']; f.elements['serendipity[title]'].value = obj.getAttribute('title'); f.elements['serendipity[body]'].value = obj.getAttribute('body'); f.elements['serendipity[extended]'].value = obj.getAttribute('extended'); // TODO: update other (less important) fields here ... // moves the contents from the form elements to the editors if(typeof(tinyMCE) != 'undefined') { // TinyMCE has some nice helper functions tinyMCE.updateContent('serendipity[body]'); tinyMCE.updateContent('serendipity[extended]'); } else if(typeof(HTMLArea) != 'undefined') { alert(document.getElementsByTagName('iframe').length); // HtmlAREA need some tricky coding: the object instances are not // stored in variables (arg!) so we must find a way to update editors // from fields contents ... var f = document.forms['serendipityEntry']; try { f.onreset(); // not enough, only the first editor is updated ! } catch(e) {} } else { // unknown wysiwyg editor (winha falls here for the moment !) tag.innerHTML = red('<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_UNSUPPORTED_EDITOR); ?> '); return; } // warn the user everything went well tag.innerHTML = green('<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_RESTORED); ?> '); }*/ else { //-------------------------------------------------- // unknown response ... //-------------------------------------------------- tag.innerHTML = red('<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_BAD_RESPONSE); ?> '); } // end if } } catch(e) {} } }; <?php // build the url for the external_plugin event $url = $serendipity['serendipityHTTPPath'] . $serendipity['indexFile'] . '?/' . PATH_PLUGIN . '/autosave&'; ?> try { ajaxEngine.registerRequest('autosave', '<?php echo $url; ?> '); ajaxEngine.registerAjaxObject('autosaveUpdater', new AutosaveUpdater()); var link = document.getElementById('autosaveLink'); link.innerHTML = '<a href="javascript:doSave();"><?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_ACTIVATED); ?> </a>'; if(autosaveShadowCanRecover && autosaveShadowCopyId) { /*link.innerHTML += '<br /><em><a href="javascript:doRecover(autosaveShadowCopyId);">' + '<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_RECOVER); ?> ' + '</a></em>';*/ // handled by the 'backend_entryform' hook link.innerHTML += '<br /><em style="padding-left: 1em;">' + '<a href="#" onclick="doRecover(<?php echo (int) $eventData['id']; ?> );">' + '<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_RECOVER); ?> ' + '</a></em>'; } // used to enable autosaving periodically <?php if (($freq = (int) $this->get_config('frequency')) != 0) { ?> var periodicalExecuter = new PeriodicalExecuter(doSave, <?php echo $freq; ?> ); <?php } ?> } catch(e) { // AJAX engine is not properly initialized ... mesg = '/!\\ <?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_INIT_FAILED); ?> :-('; alert(mesg + '\r\n' + 'Source: ' + e); var link = document.getElementById('autosaveLink'); link.innerHTML = '<span style="color: red; font-weihgt: bold;">'+mesg+'</span>'; } }); // do the recovering job function doRecover(entryid) { if(confirm('<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_CONFIRM); ?> ')) { document.location.href='<?php echo $serendipity['serendipityHTTPPath']; ?> ' + '/' + 'serendipity_admin.php?serendipity[action]=admin&' + 'serendipity[adminModule]=entries&serendipity[adminAction]=edit&' + 'serendipity[id]=' + entryid + '&autosave[id]=' + autosaveShadowCopyId; } // ARGGG: "inline recovering" is impossible due to some bugs and a lack of support // in wysiwyg editors ;-( only TinyMCE handles it nicely ... so give up ajax for the moment /* if(autosaveIsAlreadyRunning) return; autosaveIsAlreadyRunning = true; // some visual feedback for the user var resultTag = document.getElementById('autosaveResult'); resultTag.innerHTML = '<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_RESTORING); ?> '; // build query string and send request var postData = 'serendipity[adminAction]=restore&serendipity[entryid]=' + parseInt(id); ajaxEngine.sendRequest('autosave', {parameters : postData, method: 'post'}); autosaveIsAlreadyRunning = false; return; */ } // do the saving job function doSave() { // just in case ... (don't return false or // the browser will show a blank page with only // 'false' written in the upper left corner, // simply return from the function) if(!checkSave()) return; // don't work too much ;-) if(autosaveIsAlreadyRunning) return; autosaveIsAlreadyRunning = true; var resultTag = document.getElementById('autosaveResult'); resultTag.innerHTML = '<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_STARTING); ?> ';; try { var f = document.forms['serendipityEntry']; // DIRTY HACK : when using a wysiwyg editor, data has to be flushed from // the editor to the form element before being submitted. This is usually (always ?) // done transparently by the editor that register a function "into" the onsubmit() // event of the form (at least, it is the case for the HtmlArea default editor). // So we call manually the onsubmit() handler (hoping this won't have // some nasty side effect) to flush data before serializing fields. // Hint: TinyMCE work slightly differently, if overrides the sumbit() function, // not the event handler. This is not very usefull to us since it will force // a reload of the whole page ;-(. Happilly, tinyMCE provides a triggerSave() // that will do the job ;-) What about Xhina ?!? Duno but don't use ;-) // If someone could tell me ... if(typeof(tinyMCE) != 'undefined') tinyMCE.triggerSave(); else if(typeof(f.onsubmit) == 'function') f.onsubmit(); // save draft status before serialization and restore just after var draftStatus = f.elements['serendipity[isdraft]'].selectedIndex; // save f.elements['serendipity[isdraft]'].selectedIndex = 1; // tweak // prototype knows how to serialize a form ;-) // REM: ANY field is serialized, this sould enable "unknown" // extensions to be saved properly as well :-) (to be tested though !) var postData = Form.serialize('serendipityEntry'); f.elements['serendipity[isdraft]'].selectedIndex = draftStatus; // restore if(autosaveUseShadowCopy) { // we're using a shadow entry for saving purpose postData += "&serendipity[shadowed]=" + autosaveShadowCopyId; } // send (asynchroneous) request ajaxEngine.sendRequest('autosave', {parameters : postData, method: 'post'}); } catch(e) { resultTag.innerHTML = red('<?php echo addslashes(PLUGIN_EVENT_AUTOSAVE_AJAX_ERROR); ?> ' + ' [' + e + ']'); } autosaveIsAlreadyRunning = false; return; } </script> <span id="autosaveLink"><?php echo PLUGIN_EVENT_AUTOSAVE_ACTIVATING; ?> </span><br /> <span id="autosaveResult"><?php // the recover handling (is it really the right place to do this ?!?) if (isset($serendipity['GET']) && isset($serendipity['GET']['id']) && is_numeric($serendipity['GET']['id']) && isset($_GET['autosave']['id']) && is_numeric($_GET['autosave']['id'])) { // SANITY CHECK: verify $autosave['id'] is really the shadow copy of given entry (just to be sure) $ret = serendipity_db_query("SELECT e.id " . "FROM {$serendipity['dbPrefix']}entryproperties ep " . "LEFT JOIN {$serendipity['dbPrefix']}entries e ON ep.value=e.id " . "WHERE ep.entryid={$serendipity['GET']['id']} AND ep.property='" . PLUGIN_EVENT_AUTOSAVE_PROP_SHADOW . "'", true); if (!is_array($ret) || current($ret) == NULL || (int) current($ret) != (int) $_GET['autosave']['id']) { echo '<span style="color: red;">' . PLUGIN_EVENT_AUTOSAVE_BAD_SHADOW . '</span>'; } else { // fetch the autosaved entry and replace the original one by the shadow copy "on the fly" :-) $entry = serendipity_fetchEntry('id', $_GET['autosave']['id'], 1, 1); if (is_array($entry)) { // modify (partly) the entry on the fly with backed up data :-) foreach ($entry as $key => $value) { if ($key != 'id' && $key != 'isdraft') { $eventData[$key] = $value; } } } else { echo '<span style="color: red;">' . PLUGIN_EVENT_AUTOSAVE_RECOVER_FAILED; echo (strlen(trim($entry)) ? ' (' . $entry . ')' : '') . '</span>'; } } } // end if ?> </span><br /> <?php break; case 'external_plugin': // first check the event is really for us :-) // $eventData looks like "autosave&param=value" if (strncmp($eventData, 'autosave&', 13) != 0) { return false; } // REM: $serendipity['GET']['adminAction'] is always set in // serendipity_config.inc.php whatever the http method used if (!isset($serendipity['GET']['adminAction'])) { return false; } // IMPORTANT: make sure the client knows it will receive xml header('Content-Type: text/xml'); if (strncmp($serendipity['GET']['adminAction'], 'restore', 7) == 0 && is_numeric($serendipity['POST']['entryid'])) { //----------------------------------------------------------- // restoring an entry from it's shadow copy //----------------------------------------------------------- // TODO: load the entry using a statement like (see function_entries.inc.php) // $entry = serendipity_fetchEntry('id', $serendipity['POST']['entryid'], true /*full*/, true /*drafts*/); ob_start(); // send response echo '<ajax-response><response type="object" id="autosaveUpdater">'; echo '<restore title="from ajax" body="body here" extended="extended here" />'; echo '</response></ajax-response>'; $fd = fopen(dirname(__FILE__) . '/debug.log', 'w'); fwrite($fd, ob_get_contents()); fclose($fd); ob_end_flush(); } elseif (strncmp($serendipity['GET']['adminAction'], 'save', 4) == 0) { //----------------------------------------------------------- // saving an entry //----------------------------------------------------------- // handling of shadow copies if (isset($serendipity['POST']['shadowed']) && is_numeric($serendipity['POST']['shadowed'])) { // save the id of the "real" post (should be a valid id !) $realEntryId = (int) $serendipity['POST']['id']; // prevent overwritting of published post $serendipity['POST']['id'] = (int) $serendipity['POST']['shadowed']; if ($serendipity['POST']['id'] == 0) { $serendipity['POST']['id'] = ''; } } // just to be sure the user is aware that it is an autosaved entry :-) if (strncmp($serendipity['POST']['title'], PLUGIN_EVENT_AUTOSAVE_PREFIX, strlen(PLUGIN_EVENT_AUTOSAVE_PREFIX)) != 0) { $serendipity['POST']['title'] = PLUGIN_EVENT_AUTOSAVE_PREFIX . $serendipity['POST']['title']; } // save entry here (just including the file will do it :-)) but discard output // (althoug we won't get a precise message if an error occurs ;-() ob_start(); // /!\ awfull hack: there's no simple way (?) to know if an entry has been // successfully saved, so we use a flag that is toggled when backend_save is // called since backend_save is the latest event hook called when "upderting" // an entry (see serendipity_updertEntry() in functions_entries.inc.php) $this->saveSuccessfull = false; require_once S9Y_INCLUDE_PATH . 'include/admin/entries.inc.php'; if (false == $this->saveSuccessfull) { $entry = array('id' => 0); } ob_end_clean(); if (isset($realEntryId) && is_numeric($realEntryId)) { // "updert" a property on original entry to link it to the shadow copy serendipity_db_query("UPDATE {$serendipity['dbPrefix']}entryproperties SET value=" . (int) $entry['id'] . " " . "WHERE entryid=" . (int) $realEntryId . " AND property='" . PLUGIN_EVENT_AUTOSAVE_PROP_SHADOW . "'"); serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}entryproperties (entryid,property,value) " . "VALUES (" . (int) $realEntryId . ", '" . PLUGIN_EVENT_AUTOSAVE_PROP_SHADOW . "'," . (int) $entry['id'] . ")"); } // send back the generated id to the client (or 0 if save failed, whatever the reason) echo '<ajax-response><response type="object" id="autosaveUpdater">'; echo '<save id="' . (is_array($entry) && isset($entry['id']) && 0 !== (int) $entry['id'] ? $entry['id'] : 0) . '" />'; echo '</response></ajax-response>'; } exit; break; default: return false; break; } // event has been handled :-) return true; } return false; }
} if (file_exists($serendipity['serendipityPath'] . $serendipity['templatePath'] . $theme . '/preview.png')) { $preview .= '<img src="' . $serendipity['templatePath'] . $theme . '/preview.png" width="100" style="border: 1px #000000 solid" />'; } elseif (!empty($info['previewURL'])) { $preview .= '<img src="' . $info['previewURL'] . '" width="100" style="border: 1px #000000 solid" />'; } else { $preview .= ' '; } if ($preview_link) { $preview .= '</a>'; } if (empty($info['customURI'])) { $info['customURI'] = ''; } $unmetRequirements = array(); if (isset($info['require serendipity']) && version_compare($info['require serendipity'], serendipity_getCoreVersion($serendipity['version']), '>')) { $unmetRequirements[] = 'Serendipity ' . $info['require serendipity']; } /* TODO: Smarty versioncheck */ $class = $i % 2 == 0 ? 'even' : 'uneven'; ?> <div class="serendipity_admin_list_item serendipity_admin_list_item_<?php echo $class; ?> "> <table width="100%" id="serendipity_theme_<?php echo $theme; ?> "> <tr> <td colspan="2"><span class="serendipityTemplateSelectName"><strong><?php