function generate_content(&$title) { global $serendipity; $number = $this->get_config('number'); $dateformat = $this->get_config('dateformat'); $category = $this->get_config('category', 'none'); $show_where = $this->get_config('show_where', 'both'); if ($show_where == 'extended' && (!isset($serendipity['GET']['id']) || !is_numeric($serendipity['GET']['id']))) { return false; } else { if ($show_where == 'overview' && isset($serendipity['GET']['id']) && is_numeric($serendipity['GET']['id'])) { return false; } } if ($category == '_cur') { $category = $serendipity['GET']['category']; if (empty($category) && !empty($serendipity['GET']['id'])) { $entry = serendipity_fetchEntry('id', $serendipity['GET']['id']); $category = $entry['categories'][0]['categoryid']; } } $title = $this->get_config('title', $this->title); $number_from_sw = $this->get_config('number_from'); $randomize = $this->get_config('randomize') == "yes" ? true : false; $sql_condition = array(); $sql_condition['joins'] = ''; $sql_condition['and'] = ''; if ($category != 'none' && !empty($category)) { $sql_categories = array(); if (is_numeric($category)) { $sql_categories[] = $category; } else { $sql_categories = explode('^', $category); } $category_parts = array(); foreach ($sql_categories as $sql_category) { $category_parts[] = "\n" . implode(' AND ', serendipity_fetchCategoryRange($sql_category)); } $sql_condition['and'] .= ' AND (c.category_left BETWEEN ' . implode(' OR c.category_left BETWEEN ', $category_parts) . ')'; } if (!$number || !is_numeric($number) || $number < 1) { $number = 10; } $sql_number = serendipity_db_limit_sql($number); $db = $serendipity['dbType']; switch ($number_from_sw) { case 'skip': $sql_number = serendipity_db_limit_sql(serendipity_db_limit($serendipity['fetchLimit'], $number)); break; } if (!$dateformat || strlen($dateformat) < 1) { $dateformat = '%A, %B %e %Y'; } if ($randomize) { if ($db == 'mysql' || $db == 'mysqli') { $sql_order = "ORDER BY RAND()"; } else { // SQLite and PostgreSQL support this, hooray. $sql_order = "ORDER BY RANDOM()"; } } else { $sql_order = "ORDER BY timestamp DESC "; } $sql_condition['and'] .= "AND timestamp <= " . time(); serendipity_ACL_SQL($sql_condition, $category == 'none'); if (!stristr($sql_condition['joins'], $serendipity['dbPrefix'] . 'category')) { $sql_condition['joins'] = ' LEFT OUTER JOIN ' . $serendipity['dbPrefix'] . 'category AS c ON ec.categoryid = c.categoryid ' . $sql_condition['joins']; } if (!stristr($sql_condition['joins'], $serendipity['dbPrefix'] . 'entrycat')) { $sql_condition['joins'] = ' LEFT OUTER JOIN ' . $serendipity['dbPrefix'] . 'entrycat AS ec ON id = ec.entryid ' . $sql_condition['joins']; } $entries_query = "SELECT DISTINCT id,\n title,\n timestamp,\n epm.value AS multilingual_title\n FROM {$serendipity['dbPrefix']}entries AS e\n {$sql_condition['joins']}\n\n LEFT OUTER JOIN {$serendipity['dbPrefix']}entryproperties AS epm\n ON (epm.entryid = e.id AND epm.property = 'multilingual_title_" . $serendipity['lang'] . "')\n\n WHERE isdraft = 'false' {$sql_condition['and']}\n {$sql_order}\n {$sql_number}"; $entries = serendipity_db_query($entries_query); if (is_string($entries)) { echo $entries . "<br />\n"; echo $entries_query . "<br />\n"; } if (isset($entries) && is_array($entries)) { echo '<dl>' . "\n"; foreach ($entries as $k => $entry) { if (!empty($entry['multilingual_title'])) { $entry['title'] = $entry['multilingual_title']; } $entryLink = serendipity_archiveURL($entry['id'], $entry['title'], 'serendipityHTTPPath', true, array('timestamp' => $entry['timestamp'])); if (empty($entry['title'])) { $entry['title'] = '#' . $entry['id']; } echo '<dt class="serendipity_recententries_entrylink"><a href="' . $entryLink . '" title="' . serendipity_specialchars($entry['title']) . '">' . serendipity_specialchars($entry['title']) . '</a></dt>' . "\n" . '<dd class="serendipity_recententries_entrydate serendipitySideBarDate">' . serendipity_specialchars(serendipity_strftime($dateformat, $entry['timestamp'])) . '</dd>' . "\n"; } echo '</dl>' . "\n\n"; } }
?> <br /> <br /> <div> <a href="<?php echo htmlspecialchars($_SERVER["HTTP_REFERER"]); ?> " class="serendipityPrettyButton input_button "><?php echo NOT_REALLY; ?> </a> <?php echo str_repeat(' ', 10); ?> <a href="<?php echo $newLoc; ?> " class="serendipityPrettyButton input_button"><?php echo DUMP_IT; ?> </a> </div> <?php break; case 'edit': $entry = serendipity_fetchEntry('id', $serendipity['GET']['id'], 1, 1); default: include_once S9Y_INCLUDE_PATH . 'include/functions_entries_admin.inc.php'; serendipity_printEntryForm('?', array('serendipity[action]' => 'admin', 'serendipity[adminModule]' => 'entries', 'serendipity[adminAction]' => 'save'), isset($entry) ? $entry : array()); } /* vim: set sts=4 ts=4 expandtab : */
function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks =& $bag->get('event_hooks'); $links = array(); $article_show = false; if (isset($hooks[$event])) { switch ($event) { case 'frontend_display': if (isset($serendipity['GET']['id']) && is_numeric($serendipity['GET']['id'])) { $article_show = true; $year = date('Y', serendipity_serverOffsetHour($eventData['timestamp'])); $month = date('m', serendipity_serverOffsetHour($eventData['timestamp'])); } else { break; } case 'entries_footer': if (isset($serendipity['GET']['id']) && is_numeric($serendipity['GET']['id'])) { $links[] = '<a href="' . $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/articlepdf_' . $serendipity['GET']['id'] . '">' . PLUGIN_EVENT_BLOGPDF_VIEW_ENTRY . '</a>'; } if (isset($serendipity['GET']['category'])) { $cid = explode('_', $serendipity['GET']['category']); if (is_numeric($cid[0])) { $cat = serendipity_fetchCategoryInfo($cid[0]); $links[] = '<a href="' . $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/categorypdf_' . $cid[0] . '">' . sprintf(PLUGIN_EVENT_BLOGPDF_VIEW_CATEGORY, $cat['category_name']) . '</a>'; } } if (empty($year) && empty($month) && isset($serendipity['GET']['range']) && is_numeric($serendipity['GET']['range'])) { $year = substr($serendipity['GET']['range'], 0, 4); $month = substr($serendipity['GET']['range'], 4, 2); } if (empty($year)) { $year = date('Y', serendipity_serverOffsetHour()); } if (empty($month)) { $month = date('m', serendipity_serverOffsetHour()); } $links[] = '<a href="' . $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/monthpdf_' . $year . $month . '">' . PLUGIN_EVENT_BLOGPDF_VIEW_MONTH . '</a>'; $links[] = '<a href="' . $serendipity['baseURL'] . ($serendipity['rewrite'] == 'none' ? $serendipity['indexFile'] . '?/' : '') . 'plugin/blogpdf">' . PLUGIN_EVENT_BLOGPDF_VIEW_FULL . '</a>'; if ($article_show) { $eventData['add_footer'] .= '<div class="serendipity_blogpdf">' . PLUGIN_EVENT_BLOGPDF_VIEW . implode(' | ', $links) . '</div>'; } else { echo '<div class="serendipity_blogpdf">' . PLUGIN_EVENT_BLOGPDF_VIEW . implode(' | ', $links) . '</div>'; } return true; break; case 'external_plugin': if (serendipity_db_bool($this->get_config('html2pdf'))) { include_once dirname(__FILE__) . '/html2fpdf.php'; } elseif (serendipity_db_bool($this->get_config('updf'))) { include_once dirname(__FILE__) . '/serendipity_blogupdf.inc.php'; } else { include_once dirname(__FILE__) . '/serendipity_blogpdf.inc.php'; } $cachetime = 60 * 60 * 24; // one day $parts = explode('_', $eventData); if (!empty($parts[1])) { $param = (int) $parts[1]; } else { $param = null; } $methods = array('blogpdf', 'articlepdf', 'monthpdf', 'categorypdf'); if (!in_array($parts[0], $methods)) { return; } if (serendipity_db_bool($this->get_config('html2pdf'))) { $this->pdf = new HTML2FPDF(); } else { $this->pdf = new PDF(); } $this->pdf->AliasNbPages(); switch ($parts[0]) { case 'blogpdf': $feedcache = $serendipity['serendipityPath'] . 'archives/blog.pdf'; $entries = serendipity_fetchEntries(); $this->process($feedcache, $entries); break; case 'articlepdf': $feedcache = $serendipity['serendipityPath'] . 'archives/article' . $param . '.pdf'; $this->single = true; $entry = serendipity_fetchEntry('id', $param); $this->process($feedcache, $entry); break; case 'monthpdf': $feedcache = $serendipity['serendipityPath'] . 'archives/month' . $param . '.pdf'; $entries = serendipity_fetchEntries($param); $this->process($feedcache, $entries); break; case 'categorypdf': $feedcache = $serendipity['serendipityPath'] . 'archives/category' . $param . '.pdf'; $serendipity['GET']['category'] = $param . '_category'; $entries = serendipity_fetchEntries(); $this->process($feedcache, $entries); break; } $this->pdf->Output(); return true; break; default: return false; break; } } else { return false; } }
function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks =& $bag->get('event_hooks'); if (isset($hooks[$event])) { switch ($event) { case 'backend_image_addform': if ($serendipity['version'][0] < 2) { if (class_exists('ZipArchive')) { $checkedY = ""; $checkedN = ""; $this->get_config('unzipping') ? $checkedY = ' checked="checked"' : ($checkedN = ' checked="checked"'); ?> <br /> <div> <strong><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_FILES; ?> </strong><br /> <?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_FILES_DESC; ?> <div> <input type="radio" class="input_radio" id="unzip_yes" name="serendipity[unzip_archives]" value="<?php echo YES; ?> "<?php echo $checkedY; ?> ><label for="unzip_yes"><?php echo YES; ?> </label> <input type="radio" class="input_radio" id="unzip_no" name="serendipity[unzip_archives]" value="<?php echo NO; ?> "<?php echo $checkedN; ?> ><label for="unzip_no"><?php echo NO; ?> </label> </div> </div> <?php } ?> <br /> <strong><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_QUICKBLOG; ?> :</strong><br /> <em><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_QUICKBLOG_DESC; ?> </em> <table id="quickblog_table" style="width: 50%"> <tr> <td nowrap="nowrap"><?php echo TITLE; ?> </td> <td><input class="input_textbox" name="serendipity[quickblog][title]" type="text" style="width: 90%" /></td> </tr> <tr> <td nowrap="nowrap"><?php echo ENTRY_BODY; ?> </td> <td><textarea name="serendipity[quickblog][body]" style="width: 90%; height: 200px"></textarea></td> </tr> <tr> <td nowrap="nowrap"><?php echo CATEGORY; ?> </td> <td><select name="serendipity[quickblog][category]"> <option value=""><?php echo NO_CATEGORY; ?> </option> <?php if (is_array($cats = serendipity_fetchCategories())) { $cats = serendipity_walkRecursive($cats, 'categoryid', 'parentid', VIEWMODE_THREADED); foreach ($cats as $cat) { echo '<option value="' . $cat['categoryid'] . '">' . str_repeat(' ', $cat['depth']) . $cat['category_name'] . '</option>' . "\n"; } } ?> </select></td> </tr> <tr> <td nowrap="nowrap"><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_TARGET; ?> </td> <td><select id="select_image_target" name="serendipity[quickblog][target]"> <option value="none"<?php echo serendipity_ifRemember('target', 'none', false, 'selected'); ?> ><?php echo NONE; ?> </option> <option value="js"<?php echo serendipity_ifRemember('target', 'js', false, 'selected'); ?> ><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_TARGET_JS; ?> </option> <option value="plugin"<?php echo serendipity_ifRemember('target', 'plugin', false, 'selected'); ?> ><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_TARGET_ENTRY; ?> </option> <option value="_blank"<?php echo serendipity_ifRemember('target', '_blank', false, 'selected'); ?> ><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_TARGET_BLANK; ?> </option> </select></td> </tr> <tr> <td nowrap="nowrap"><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_ASOBJECT; ?> </td> <td> <input type="radio" class="input_radio" id="image_yes" name="serendipity[quickblog][isobject]" value="<?php echo YES; ?> "><label for="image_yes"><?php echo YES; ?> </label> <input type="radio" class="input_radio" id="image_no" name="serendipity[quickblog][isobject]" value="<?php echo NO; ?> " checked="checked"><label for="image_no"><?php echo NO; ?> </label> </td> </tr> <tr> <td nowrap="nowrap"><?php echo IMAGE_SIZE; ?> </td> <td><input class="input_textbox" name="serendipity[quickblog][size]" value="<?php echo $serendipity['thumbSize']; ?> " type="text" style="width: 50px" /></td> </tr> <tr> <td align="center" colspan="2"><br /></td> </tr> </table> <div> <em><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_IMAGE_SIZE_DESC; ?> </em> </div> <?php } else { ?> <div id="imageselectorplus"> <?php if (class_exists('ZipArchive')) { $checkedY = ""; $checkedN = ""; $this->get_config('unzipping') ? $checkedY = ' checked="checked"' : ($checkedN = ' checked="checked"'); ?> <div class="clearfix radio_field"> <h4><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_FILES; ?> </h4> <?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_FILES_DESC; ?> <div> <input type="radio" class="input_radio" id="unzip_yes" name="serendipity[unzip_archives]" value="<?php echo YES; ?> "<?php echo $checkedY; ?> ><label for="unzip_yes"><?php echo YES; ?> </label> <input type="radio" class="input_radio" id="unzip_no" name="serendipity[unzip_archives]" value="<?php echo NO; ?> "<?php echo $checkedN; ?> ><label for="unzip_no"><?php echo NO; ?> </label> </div> </div> <?php } ?> <h4><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_QUICKBLOG; ?> :</h4> <em><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_QUICKBLOG_DESC; ?> </em> <div id="quickblog_tablefield" class="clearfix"> <div class="quickblog_form_field"> <label for="quickblog_titel"><?php echo TITLE; ?> </label> <input id="quickblog_title" class="input_textbox" name="serendipity[quickblog][title]" type="text"> </div> <div class="quickblog_textarea_field"> <label for="nuggets2"><?php echo ENTRY_BODY; ?> </label> <textarea id="nuggets2" class="quickblog_nugget" data-tarea="nuggets2" name="serendipity[quickblog][body]" rows="10" cols="80"></textarea> <?php if ($serendipity['wysiwyg']) { $plugins = serendipity_plugin_api::enum_plugins('*', false, 'serendipity_event_nl2br'); ?> <input name="serendipity[properties][disable_markups][]" type="hidden" value="<?php echo $plugins[0]['name']; ?> "> <?php if (!class_exists('serendipity_event_ckeditor')) { ?> <script src="<?php echo $serendipity['serendipityHTTPPath']; ?> htmlarea/ckeditor/ckeditor/ckeditor.js"></script> <?php } // just add a simple basic toolbar, since we cannot use embedded plugins here ?> <script> CKEDITOR.replace( 'nuggets2', { toolbar : [['Format'],['Bold','Italic','Underline','Superscript','-','NumberedList','BulletedList','Outdent','Blockquote'],['JustifyBlock','JustifyCenter','JustifyRight'],['Link','Unlink'],['Source']], toolbarGroups: null }); </script> <?php } ?> </div> <div class="quickblog_form_field"> <label for="quickblog_select"><?php echo CATEGORY; ?> </label> <select id="quickblog_select" name="serendipity[quickblog][category]"> <option value=""><?php echo NO_CATEGORY; ?> </option> <?php if (is_array($cats = serendipity_fetchCategories())) { $cats = serendipity_walkRecursive($cats, 'categoryid', 'parentid', VIEWMODE_THREADED); foreach ($cats as $cat) { echo '<option value="' . $cat['categoryid'] . '">' . str_repeat(' ', $cat['depth']) . $cat['category_name'] . '</option>' . "\n"; } } ?> </select> </div> <div class="quickblog_form_select"> <label for="select_image_target"><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_TARGET; ?> </label> <select id="select_image_target" name="serendipity[quickblog][target]"> <option value="none"<?php echo serendipity_ifRemember('target', 'none', false, 'selected'); ?> ><?php echo NONE; ?> </option> <option value="js"<?php echo serendipity_ifRemember('target', 'js', false, 'selected'); ?> ><?php echo MEDIA_TARGET_JS; ?> </option> <option value="plugin"<?php echo serendipity_ifRemember('target', 'plugin', false, 'selected'); ?> ><?php echo MEDIA_ENTRY; ?> </option> <option value="_blank"<?php echo serendipity_ifRemember('target', '_blank', false, 'selected'); ?> ><?php echo MEDIA_TARGET_BLANK; ?> </option> </select> </div> <div class="clearfix radio_field quickblog_radio_field"> <label><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_ASOBJECT; ?> </label> <div> <input type="radio" class="input_radio" id="image_yes" name="serendipity[quickblog][isobject]" value="<?php echo YES; ?> "><label for="image_yes"><?php echo YES; ?> </label> <input type="radio" class="input_radio" id="image_no" name="serendipity[quickblog][isobject]" value="<?php echo NO; ?> " checked="checked"><label for="image_no"><?php echo NO; ?> </label> </div> </div> <div class="quickblog_form_field"> <label for="quickblog_isize"><?php echo IMAGE_SIZE; ?> </label> <input id="quickblog_isize" class="input_textbox" name="serendipity[quickblog][size]" value="<?php echo $serendipity['thumbSize']; ?> " type="text"> </div> </div> <em><?php echo PLUGIN_EVENT_IMAGESELECTORPLUS_IMAGE_SIZE_DESC; ?> </em> </div> <?php } break; case 'backend_image_add': global $new_media; // if file is zip archive and unzipping enabled // unzip file and add all images to database // retrieve file type $target_zip = $eventData; preg_match('@(^.*/)+(.*)\\.+(\\w*)@', $target_zip, $matches); $target_dir = $matches[1]; $basename = $matches[2]; $extension = $matches[3]; $authorid = isset($serendipity['POST']['all_authors']) && $serendipity['POST']['all_authors'] == 'true' ? '0' : $serendipity['authorid']; // only if unzipping function exists, we have archive file and unzipping set to yes if (class_exists('ZipArchive') && $extension == 'zip' && $serendipity['POST']['unzip_archives'] == YES) { // now unzip $zip = new ZipArchive(); $res = $zip->open($target_zip); if ($res === TRUE) { $files_to_unzip = array(); $extracted_images = array(); for ($i = 0; $i < $zip->numFiles; $i++) { $file_to_extract = $zip->getNameIndex($i); if (file_exists($target_dir . $file_to_extract)) { echo '(' . $file_to_extract . ') ' . ERROR_FILE_EXISTS_ALREADY . '<br />'; } else { $files_to_unzip[] = $file_to_extract; $extracted_images[] = $target_dir . $file_to_extract; } } $zip->extractTo($target_dir, $files_to_unzip); $zip->close(); echo PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_OK; } else { echo PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_FAILED; } // now proceed all unzipped images foreach ($extracted_images as $target) { preg_match('@(^.*/)+(.*)\\.+(\\w*)@', $target, $matches); $real_dir = $matches[1]; $basename = $matches[2]; $extension = $matches[3]; $tfile = $basename . "." . $extension; preg_match('@' . $serendipity['uploadPath'] . '(.*/)@', $target, $matches); $image_directory = $matches[1]; // make thumbnails for new images $thumbs = array(array('thumbSize' => $serendipity['thumbSize'], 'thumb' => $serendipity['thumbSuffix'])); serendipity_plugin_api::hook_event('backend_media_makethumb', $thumbs); foreach ($thumbs as $thumb) { // Create thumbnail if ($created_thumbnail = serendipity_makeThumbnail($tfile, $image_directory, $thumb['thumbSize'], $thumb['thumb'])) { echo PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_IMAGE_FROM_ARCHIVE . " - " . THUMB_CREATED_DONE . '<br />'; } } // Insert into database $image_id = serendipity_insertImageInDatabase($tfile, $image_directory, $authorid, null, $realname); echo PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_IMAGE_FROM_ARCHIVE . " ({$tfile}) " . PLUGIN_EVENT_IMAGESELECTORPLUS_UNZIP_ADD_TO_DB . "<br />"; $new_media[] = array('image_id' => $image_id, 'target' => $target, 'created_thumbnail' => $created_thumbnail); } } case 'backend_image_addHotlink': // Re-Scale thumbnails? $max_scale = array('width' => (int) $this->get_config('thumb_max_width'), 'height' => (int) $this->get_config('thumb_max_height')); if ($max_scale['width'] > 0 || $max_scale['height'] > 0) { $this->resizeThumb($max_scale, $eventData); } if (empty($serendipity['POST']['quickblog']['title'])) { break; } $file = basename($eventData); $directory = str_replace($serendipity['serendipityPath'] . $serendipity['uploadPath'], '', dirname($eventData) . '/'); $size = (int) $serendipity['POST']['quickblog']['size']; // check default Serendipity thumbSize, to make this happen like standard image uploads, and to get one "fullsize" image instance only, // else create another quickblog image "resized" instance, to use as entries thumbnail image if ($serendipity['thumbSize'] != $size) { $oldSuffix = $serendipity['thumbSuffix']; $serendipity['thumbSuffix'] = 'quickblog'; serendipity_makeThumbnail($file, $directory, $size); $serendipity['thumbSuffix'] = $oldSuffix; } // Non-image object link generation if ($serendipity['POST']['quickblog']['isobject'] == YES) { $objfile = serendipity_parseFileName($file); $filename = $objfile[0]; $suffix = $objfile[1]; $obj_mime = serendipity_guessMime($suffix); $objpath = $serendipity['serendipityHTTPPath'] . $serendipity['uploadPath'] . $directory . $filename . '.' . $suffix; // try to know about a working environment for imagemagicks pdf preview generation if ($serendipity['magick'] === true && strtolower($suffix) == 'pdf' && $serendipity['thumbSize'] == $size) { $objpreview = $serendipity['serendipityHTTPPath'] . $serendipity['uploadPath'] . $directory . $filename . '.' . $serendipity['thumbSuffix'] . '.' . $suffix . '.png'; } else { $objpreview = serendipity_getTemplateFile('admin/img/mime_' . preg_replace('@[^0-9a-z_\\-]@i', '-', $obj_mime) . '.png'); } if (!$objpreview || empty($objpreview)) { $objpreview = serendipity_getTemplateFile('admin/img/mime_unknown.png'); } } // New draft post $entry = array(); $entry['isdraft'] = 'false'; $entry['title'] = function_exists('serendipity_specialchars') ? serendipity_specialchars($serendipity['POST']['quickblog']['title']) : htmlspecialchars($serendipity['POST']['quickblog']['title'], ENT_COMPAT, LANG_CHARSET); if (isset($objpath) && !empty($objpath)) { $entry['body'] = '<a href="' . $objpath . '"><img alt="" class="serendipity_image_left serendipity_quickblog_image" src="' . $objpreview . '">' . $filename . '</a> (-' . $obj_mime . '-)<p>' . $serendipity['POST']['quickblog']['body'] . '</p>'; } else { $entry['body'] = '<!--quickblog:' . $serendipity['POST']['quickblog']['target'] . '|' . $eventData . '-->' . $serendipity['POST']['quickblog']['body']; } $entry['authorid'] = $serendipity['authorid']; $entry['exflag'] = false; $entry['categories'][0] = function_exists('serendipity_specialchars') ? serendipity_specialchars($serendipity['POST']['quickblog']['category']) : htmlspecialchars($serendipity['POST']['quickblog']['category'], ENT_COMPAT, LANG_CHARSET); #$entry['allow_comments'] = 'true'; // both disabled #$entry['moderate_comments'] = 'false'; // to take default values $serendipity['POST']['properties']['fake'] = 'fake'; $id = serendipity_updertEntry($entry); break; case 'frontend_display': // auto resizing images based on width and/or height attributes in img tag if (serendipity_db_bool($this->get_config('autoresize'))) { if (!empty($eventData['body'])) { $eventData['body'] = $this->substituteImages($eventData['body']); } if (!empty($eventData['extended'])) { $eventData['extended'] = $this->substituteImages($eventData['extended']); } } if (empty($eventData['body'])) { return; } // displaying quickblog posts if (is_object($serendipity['smarty']) && preg_match('@<!--quickblog:(.+)-->@imsU', $eventData['body'], $filematch)) { $eventData['body'] = $this->parse_quickblog_post($filematch[1], $eventData['body']); } // displaying galleries introduced by markup foreach ($this->markup_elements as $temp) { if (serendipity_db_bool($this->get_config($temp['name'], true)) && isset($eventData[$temp['element']]) && !$eventData['properties']['ep_disable_markup_' . $this->instance] && !isset($serendipity['POST']['properties']['disable_markup_' . $this->instance])) { $element = $temp['element']; $eventData[$element] = $this->media_insert($eventData[$element], $eventData); } } return true; break; case 'backend_entry_presave': if (is_numeric($eventData['id'])) { $eventData['body'] = str_replace('{{s9yisp_entryid}}', $eventData['id'], $eventData['body']); $eventData['extended'] = str_replace('{{s9yisp_entryid}}', $eventData['id'], $eventData['extended']); $this->gotMilk = true; } else { $this->cache['body'] = $eventData['body']; $this->cache['extended'] = $eventData['extended']; } break; case 'backend_publish': case 'backend_save': if ($this->gotMilk === false) { $old = md5($this->cache['body']) . md5($this->cache['extended']); $this->cache['body'] = str_replace('{{s9yisp_entryid}}', $eventData['id'], $this->cache['body']); $this->cache['extended'] = str_replace('{{s9yisp_entryid}}', $eventData['id'], $this->cache['extended']); $new = md5($this->cache['body']) . md5($this->cache['extended']); if ($old != $new) { serendipity_db_query("UPDATE {$serendipity['dbPrefix']}entries\n SET body = '" . serendipity_db_escape_string($this->cache['body']) . "',\n extended = '" . serendipity_db_escape_string($this->cache['extended']) . "'\n WHERE id = " . (int) $eventData['id']); } } break; case 'entry_display': if ($this->selected()) { if (is_array($eventData)) { $eventData['clean_page'] = true; // This is important to not display an entry list! } else { $eventData = array('clean_page' => true); } } break; case 'entries_header': if (!$this->selected()) { return true; } if ($serendipity['version'][0] > 1) { return true; } if (!headers_sent()) { header('HTTP/1.0 200'); header('Status: 200 OK'); } $entry = serendipity_fetchEntry('id', $serendipity['GET']['id']); $imageid = $serendipity['GET']['image']; $imgsrc = ''; if (preg_match('@<a title="([^"]+)" id="s9yisp' . $imageid . '"></a>@imsU', $entry['body'], $imgmatch)) { $imgsrc = $imgmatch[1]; } elseif (preg_match('@<a title="([^"]+)" id="s9yisp' . $imageid . '"></a>@imsU', $entry['extended'], $imgmatch)) { $imgsrc = $imgmatch[1]; } else { return; } $link = '<a href="' . serendipity_archiveURL($serendipity['GET']['id'], $entry['title'], 'baseURL', true, array('timestamp' => $entry['timestamp'])) . '#s9yisp' . $imageid . '">'; echo '<div class="serendipity_Entry_Date"> <h3 class="serendipity_date">' . serendipity_formatTime(DATE_FORMAT_ENTRY, $entry['timestamp']) . '</h3>'; echo '<h4 class="serendipity_title"><a href="#">' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($entry['title']) : htmlspecialchars($entry['title'], ENT_COMPAT, LANG_CHARSET)) . '</a></h4>'; echo '<div class="serendipity_entry"><div class="serendipity_entry_body">'; echo '<div class="serendipity_center">' . $link . '<!-- s9ymdb:' . $entry['id'] . ' --><img src="' . $imgsrc . '" /></a></div>'; echo '<br />'; echo $link . '<< ' . BACK . '</a>'; echo "</div>\n</div>\n</div>\n"; return true; break; case 'frontend_image_add_unknown': case 'frontend_image_add_filenameonly': case 'frontend_image_selector_submit': case 'frontend_image_selector_more': case 'frontend_image_selector_imagecomment': case 'frontend_image_selector_imagealign': case 'frontend_image_selector_imagesize': case 'frontend_image_selector_hiddenfields': case 'frontend_image_selector_imagelink': return true; break; case 'css_backend': if ($serendipity['version'][0] > 1) { ?> #imageselectorplus .radio_field input { margin: 0 0.5em; } #quickblog_tablefield { display: table-cell; } #uploadform .quickblog_nugget { margin-left: 0; padding: 0; } #quickblog_tablefield .quickblog_form_field { margin: .375em 0; } #quickblog_tablefield .quickblog_radio_field div label, #quickblog_tablefield .radio_field label { padding-left: .5em; } #quickblog_tablefield .quickblog_form_select { margin-top: 0.75em; margin-bottom: 0.75em; } #quickblog_tablefield .quickblog_radio_field label { padding-left: 0; } #quickblog_tablefield .quickblog_radio_field div { display: inline; } #quickblog_tablefield .quickblog_radio_field input { margin-left: 0.5em; } <?php } break; case 'css': ?> #content .serendipity_quickblog_image { border: medium none transparent; } .serendipity_mediainsert_gallery { border: 1px solid #C0C0C0; margin: 0px; overflow: auto; padding: 0.4em; } <?php break; case 'frontend_image_selector': if ($serendipity['version'][0] < 2) { $eventData['finishJSFunction'] = 'serendipity_imageSelectorPlus_done(\'' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($serendipity['GET']['textarea']) : htmlspecialchars($serendipity['GET']['textarea'], ENT_COMPAT, LANG_CHARSET)) . '\')'; } else { $eventData['finishJSFunction'] = 'serendipity.serendipity_imageSelector_done(\'' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($serendipity['GET']['textarea']) : htmlspecialchars($serendipity['GET']['textarea'], ENT_COMPAT, LANG_CHARSET)) . '\')'; } return true; break; default: return false; } } else { return false; } }
serendipity_plugin_api::generate_plugins('left', 'span'); // serendipity_plugin_api::generate_plugins('right', 'span'); ?> </td> <td width="100%" valign="top" align="left" class="serendipityContent"> <?php echo $OPENSHADOW; ?> <?php // The main area switch ($serendipity["GET"]["action"]) { // User wants to read the diary case "read": if (isset($serendipity['GET']['id'])) { serendipity_printEntries(array(serendipity_fetchEntry("id", $serendipity['GET']['id'])), 1); } else { serendipity_printEntries(serendipity_fetchEntries($serendipity['range'], true, $serendipity['fetchLimit'])); } break; // User searches // User searches case "search": $r = serendipity_searchEntries($serendipity["GET"]["searchTerm"]); if (strlen($serendipity["GET"]["searchTerm"]) <= 3) { echo SEARCH_TOO_SHORT; break; } if ($r === true) { echo sprintf(NO_ENTRIES_BLAHBLAH, $serendipity['GET']['searchTerm']); 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; }
/** * Inserts a new entry into the database or updates an existing entry * * Another central function, that parses, prepares and commits changes to an entry * * @access public * @param array The new/modified entry data. * @return mixed Integer with new entry ID if successfull, a string or array if error(s). */ function serendipity_updertEntry($entry) { global $serendipity; include_once S9Y_INCLUDE_PATH . 'include/functions_entries_admin.inc.php'; $errors = array(); serendipity_plugin_api::hook_event('backend_entry_updertEntry', $errors, $entry); if (count($errors) > 0) { // Return error message(s) return implode("\n", $errors); } serendipity_plugin_api::hook_event('backend_entry_presave', $entry); $categories = $entry['categories']; unset($entry['categories']); $newEntry = 0; $exflag = 0; if (isset($entry['properties'])) { unset($entry['properties']); } if (!is_numeric($entry['timestamp'])) { $entry['timestamp'] = time(); } /* WYSIWYG-editor inserts empty ' ' for extended body; this is reversed here */ if (isset($entry['extended']) && (trim($entry['extended']) == '' || trim($entry['extended']) == '<br />' || trim($entry['extended']) == '<p></p>' || str_replace(array("\r", "\n", "\t", "", "<br />", "<p>", "</p>", "<br>"), array('', '', '', '', '', '', '', ''), trim($entry['extended'])) == '')) { $entry['extended'] = ''; } if (strlen($entry['extended'])) { $exflag = 1; } $entry['exflag'] = $exflag; if (!is_numeric($entry['id'])) { /* we need to insert */ unset($entry['id']); $entry['comments'] = 0; if (!isset($entry['last_modified']) || !is_numeric($entry['last_modified'])) { $entry['last_modified'] = $entry['timestamp']; } // New entries need an author $entry['author'] = $serendipity['user']; if (!isset($entry['authorid']) || empty($entry['authorid'])) { $entry['authorid'] = $serendipity['authorid']; } if (!$_SESSION['serendipityRightPublish']) { $entry['isdraft'] = 'true'; } if (!isset($entry['allow_comments'])) { $entry['allow_comments'] = 'false'; } if (!isset($entry['moderate_comments'])) { $entry['moderate_comments'] = 'false'; } $res = serendipity_db_insert('entries', $entry); if ($res) { $entry['id'] = $serendipity['lastSavedEntry'] = serendipity_db_insert_id('entries', 'id'); if (is_array($categories)) { foreach ($categories as $cat) { if (is_numeric($cat)) { serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}entrycat (entryid, categoryid) VALUES ({$entry['id']}, {$cat})"); } } } serendipity_insertPermalink($entry); } else { //Some error message here return ENTRIES_NOT_SUCCESSFULLY_INSERTED; } $newEntry = 1; } else { /* we need to update */ // Get settings from entry if already in DB, which should not be alterable with POST methods $_entry = serendipity_fetchEntry('id', $entry['id'], 1, 1); $entry['authorid'] = $_entry['authorid']; if (isset($serendipity['GET']['adminModule']) && $serendipity['GET']['adminModule'] == 'entries' && $entry['authorid'] != $serendipity['authorid'] && !serendipity_checkPermission('adminEntriesMaintainOthers')) { // Only chiefs and admins can change other's entry. Else update fails. return; } if (!$_SESSION['serendipityRightPublish']) { $entry['isdraft'] = 'true'; } if (is_array($categories)) { serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}entrycat WHERE entryid={$entry['id']}"); foreach ($categories as $cat) { serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}entrycat (entryid, categoryid) VALUES ({$entry['id']}, {$cat})"); } } //if (!serendipity_db_bool($entry['isdraft']) && !serendipity_db_bool($_entry['isdraft'])) { $entry['last_modified'] = time(); //} $res = serendipity_db_update('entries', array('id' => $entry['id']), $entry); $newEntry = 0; serendipity_updatePermalink($entry); } if (is_string($res)) { return $res; } // Reset session data, so that a reload to this frame should not happen! $_SESSION['save_entry']['id'] = (int) $entry['id']; if (!serendipity_db_bool($entry['isdraft'])) { serendipity_plugin_api::hook_event('frontend_display', $entry, array('no_scramble' => true, 'from' => 'functions_entries:updertEntry')); $drafted_entry = $entry; } serendipity_purgeEntry($entry['id'], $entry['timestamp']); if (!serendipity_db_bool($entry['isdraft']) && $entry['timestamp'] <= serendipity_serverOffsetHour()) { // When saving an entry, first all references need to be gathered. But trackbacks to them // shall only be send at the end of the execution flow. However, certain plugins depend on // the existance of handled references. Thus we store the current references at this point, // execute the plugins and then reset the found references to the original state. serendipity_handle_references($entry['id'], $serendipity['blogTitle'], $drafted_entry['title'], $drafted_entry['body'] . $drafted_entry['extended'], true); } // Send publish tags if either a new article has been inserted from scratch, or if the entry was previously // stored as draft and is now published $entry['categories'] =& $categories; if (!serendipity_db_bool($entry['isdraft']) && ($newEntry || serendipity_db_bool($_entry['isdraft']))) { serendipity_plugin_api::hook_event('backend_publish', $entry, $newEntry); } else { serendipity_plugin_api::hook_event('backend_save', $entry, $newEntry); } if (!serendipity_db_bool($entry['isdraft']) && $entry['timestamp'] <= serendipity_serverOffsetHour()) { // Now that plugins are executed, we go ahead into the Temple of Doom and send possibly failing trackbacks. // First, original list of references is restored (inside the function call) serendipity_handle_references($entry['id'], $serendipity['blogTitle'], $drafted_entry['title'], $drafted_entry['body'] . $drafted_entry['extended'], false); } return (int) $entry['id']; }
/** * Smarty Function: Fetch and print a single or multiple entries * * @access public * @param array Smarty parameter input array: * [FETCHING] * category: (int) The category ID (seperate multiple with ";") to fetch entries from * viewAuthor: (int) The author ID (seperate multiple with ";") to fetch entries from * page: (int) The number of the page for paginating entries * id: (int) The ID of an entry. If given, only a single entry will be fetched. If left empty, multiple entries are fetched. * range: (mixed) Restricts fetching entries to a specific timespan. Behaves differently depending on the type: * Numeric: * YYYYMMDD - Shows all entries from YYYY-MM-DD. * If DD is "00", it will show all entries from that month. * If DD is any other number, it will show entries of that specific day. * 2-Dimensional Array: * Key #0 - Specifies the start timestamp (unix seconds) * Key #1 - Specifies the end timestamp (unix seconds) * Other (null, 3-dimensional Array, ...): * Entries newer than $modified_since will be fetched * full (boolean) Indicates if the full entry will be fetched (body+extended: TRUE), or only the body (FALSE). * limit (string) Holds a "Y" or "X, Y" string that tells which entries to fetch. X is the first entry offset, Y is number of entries. If not set, the global fetchLimit will be applied (15 entries by default) * fetchDrafts (boolean) Indicates whether drafts should be fetched (TRUE) or not * modified_since (int) Holds a unix timestamp to be used in conjunction with $range, to fetch all entries newer than this timestamp * orderby (string) Holds the SQL "ORDER BY" statement. * filter_sql (string) Can contain any SQL code to inject into the central SQL statement for fetching the entry * noCache (boolean) If set to TRUE, all entries will be fetched from scratch and any caching is ignored * noSticky (boolean) If set to TRUE, all sticky entries will NOT be fetched. * select_key (string) Can contain a SQL statement on which keys to select. Plugins can also set this, pay attention! * group_by (string) Can contain a SQL statement on how to group the query. Plugins can also set this, pay attention! * returncode (string) If set to "array", the array of entries will be returned. "flat-array" will only return the articles without their entryproperties. "single" will only return a 1-dimensional array. "query" will only return the used SQL. * joinauthors (bool) Should an SQL-join be made to the AUTHORS DB table? * joincategories (bool) Should an SQL-join be made to the CATEGORIES DB table? * joinown (string) SQL-Parts to add to the "JOIN" query * entryprops (string) Condition list of commaseparated entryproperties that an entry must have to be displayed (example: "ep_CustomField='customVal',ep_CustomField2='customVal2'") * * [PRINTING] * template: (string) Name of the template file to print entries with * preview: (boolean) Indicates if this is a preview * block (string The name of the SMARTY block that this gets parsed into * use_hooks (boolean Indicates whether to apply footer/header event hooks * use_footer (boolean Indicates whether the pagination footer should be displayed * groupmode (string Indicates whether the input $entries array is already grouped in preparation for the smarty $entries output array [TRUE], or if it shall be grouped by date [FALSE] * skip_smarty_hooks (boolean) If TRUE, no plugins will be executed at all * skip_smarty_hook (mixed) Can be set to an array of plugin hooks to NOT execute * prevent_reset (boolean) If set to TRUE, the smarty $entries array will NOT be cleared. (to prevent possible duplicate output of entries) * @param object Smarty object * @return string The Smarty HTML response */ function serendipity_smarty_fetchPrintEntries($params, &$smarty) { global $serendipity; static $entrycount = 0; static $restore_var_GET_keys = array('category', 'viewAuthor', 'page', 'hide_category'); // A counter variable to not assign template files multiple times $entrycount++; // Default values for function calls if (empty($params['template'])) { $params['template'] = 'entries.tpl'; } if (empty($params['range'])) { $params['range'] = null; } if (empty($params['full'])) { $params['full'] = true; } if (empty($params['fetchDrafts'])) { $params['fetchDrafts'] = false; } if (!empty($params['entryprops'])) { if (preg_match_all('@(.*)(!)?=[\'"]*([^\'"]+)[\'"]*(,|$)@imsU', $params['entryprops'], $m)) { foreach ($m[0] as $idx => $p) { $params['joinown'] .= "\n JOIN {$serendipity['dbPrefix']}entryproperties \n AS ep" . $idx . " \n ON (ep" . $idx . ".entryid = e.id AND \n ep" . $idx . ".property = '" . serendipity_db_escape_string($m[1][$idx]) . "' AND \n ep" . $idx . ".value " . $m[2][$idx] . "= '" . serendipity_db_escape_string($m[3][$idx]) . "') \n"; } } } if (empty($params['modified_since'])) { $params['modified_since'] = false; } if (empty($params['orderby'])) { $params['orderby'] = 'timestamp DESC'; } if (empty($params['noCache'])) { $params['noCache'] = false; } if (empty($params['noSticky'])) { $params['noSticky'] = false; } if (empty($params['preview'])) { $params['preview'] = false; } if (empty($params['block'])) { $params['block'] = 'smarty_entries_' . $entrycount; } if (empty($params['use_hooks'])) { $params['use_hooks'] = false; } if (empty($params['use_footer'])) { $params['use_footer'] = false; } if (empty($params['groupmode'])) { $params['groupmode'] = 'date'; } if (empty($params['skip_smarty_hooks'])) { $params['skip_smarty_hooks'] = true; } if (empty($params['skip_smarty_hook'])) { $params['skip_smarty_hook'] = array(); } if (empty($params['prevent_reset'])) { $params['prevent_reset'] = false; } if (empty($params['select_key'])) { $params['select_key'] = null; } if (empty($params['group_by'])) { $params['group_by'] = null; } if (empty($params['returncode'])) { $params['returncode'] = 'array'; } if (empty($params['joinauthors'])) { $params['joinauthors'] = true; } if (empty($params['joincategories'])) { $params['joincategories'] = true; } // Some functions deal with the $serendipity array. To modify them, we need to store // their original contents. $old_var = array(); if (!empty($params['short_archives'])) { $old_var['short_archives'] = $serendipity['short_archives']; $serendipity['short_archives'] = $params['short_archives']; } $old_var['skip_smarty_hooks'] = $serendipity['skip_smarty_hooks']; $serendipity['skip_smarty_hooks'] = $params['skip_smarty_hooks']; $old_var['skip_smarty_hook'] = $serendipity['skip_smarty_hook']; $serendipity['skip_smarty_hook'] = $params['skip_smarty_hook']; foreach ($restore_var_GET_keys as $key) { if (!empty($params[$key])) { $old_var['GET'][$key] = $serendipity['GET'][$key]; $serendipity['GET'][$key] = $params[$key]; } } if (!empty($params['id'])) { $entry = serendipity_fetchEntry('id', (int) $params['id'], $params['full'], $params['fetchDrafts']); } else { $entry = serendipity_fetchEntries($params['range'], $params['full'], $params['limit'], $params['fetchDrafts'], $params['modified_since'], $params['orderby'], $params['filter_sql'], $params['noCache'], $params['noSticky'], $params['select_key'], $params['group_by'], $params['returncode'], $params['joinauthors'], $params['joincategories'], $params['joinown']); // Check whether the returned entries shall be grouped specifically switch ($params['groupmode']) { case 'date': // No regrouping required, printEntries() does it for us. break; case 'category': // Regroup by primary category $groupdata = array(); foreach ($entry as $k => $_entry) { if (is_array($entry['categories'])) { $groupkey = $entry['categories'][0]; } else { $groupkey = 'none'; } $groupdata[$groupkey]['entries'] =& $_entry; } $entry =& $groupdata; break; } } if ($params['returncode'] == 'query') { return print_r($entry, true); } serendipity_printEntries($entry, !empty($params['id']) ? true : false, $params['preview'], 'ENTRIES', false, $params['use_hooks'], $params['use_footer'], $params['groupmode'] == 'date' ? false : true); // Restore the $serendipity array after our modifications. if (isset($old_var['short_archives'])) { $serendipity['short_archives'] = $old_var['short_archives']; } if (is_array($old_var['GET'])) { foreach ($old_var['GET'] as $key => $val) { $serendipity['GET'][$key] = $val; } } $out = serendipity_smarty_fetch($params['block'], $params['template']); // Reset array list, because we might be in a nested code call. if ($params['prevent_reset'] == false) { $serendipity['smarty']->assign('entries', array()); } $serendipity['skip_smarty_hook'] = $old_var['skip_smarty_hook']; $serendipity['skip_smarty_hooks'] = $old_var['skip_smarty_hooks']; return $out; }
function metaWeblog_getPostCategories($message) { $val = $message->params[0]; $postid = $val->getval(); $val = $message->params[1]; $username = $val->getval(); $val = $message->params[2]; $password = $val->getval(); if (!serendipity_authenticate_author($username, $password)) { return new XML_RPC_Response('', XMLRPC_ERR_CODE_AUTHFAILED, XMLRPC_ERR_NAME_AUTHFAILED); } $entry = serendipity_fetchEntry('id', (int) $postid, true, 'true'); $categories = array(); if (is_array($entry['categories'])) { foreach ($entry['categories'] as $i => $cat) { $categories[] = new XML_RPC_Value(array('categoryId' => new XML_RPC_Value($cat['categoryid'], 'string'), 'categoryName' => new XML_RPC_Value($cat['category_name'], 'string')), 'struct'); } } return new XML_RPC_Response(new XML_RPC_Value($categories, 'array')); }
if ((empty($uri_addData['uriargs']) || trim($uri_addData['uriargs']) == $serendipity['indexFile']) && empty($serendipity['GET']['subpage'])) { $uri_addData['startpage'] = true; } $serendipity['plugindata']['smartyvars'] = $uri_addData; // Plugins can change this global variable serendipity_plugin_api::hook_event('genpage', $uri, $uri_addData); serendipity_smarty_init($serendipity['plugindata']['smartyvars']); $leftSidebarElements = serendipity_plugin_api::count_plugins('left'); $rightSidebarElements = serendipity_plugin_api::count_plugins('right'); $serendipity['smarty']->assignByRef('leftSidebarElements', $leftSidebarElements); $serendipity['smarty']->assignByRef('rightSidebarElements', $rightSidebarElements); switch ($serendipity['GET']['action']) { // User wants to read the diary case 'read': if (isset($serendipity['GET']['id'])) { $entry = array(serendipity_fetchEntry('id', $serendipity['GET']['id'])); if (!is_array($entry) || count($entry) < 1 || !is_array($entry[0])) { unset($serendipity['GET']['id']); $entry = array(array()); $serendipity['head_title'] = serendipity_specialchars($serendipity['blogTitle']); $serendipity['head_subtitle'] = ''; $serendipity['smarty']->assign('head_title', $serendipity['head_title']); $serendipity['smarty']->assign('head_subtitle', $serendipity['head_subtitle']); $serendipity['view'] = '404'; serendipity_header('HTTP/1.0 404 Not found'); serendipity_header('Status: 404 Not found'); } serendipity_printEntries($entry, 1); } else { serendipity_printEntries(serendipity_fetchEntries($serendipity['range'], true, $serendipity['fetchLimit'])); }
function parseCallback($buffer) { global $serendipity; if (!isset($buffer[3]) || empty($buffer[3])) { $buffer[3] = 'body'; } $id = (int) $buffer[2]; switch ($buffer[1]) { case 's9y-include-block': $this->fetchStaticBlock($id); if ($buffer[3] == 'template') { $newbuf = $this->smartyParse($this->staticblock['template']); } else { $newbuf = $this->staticblock[$buffer[3]]; } break; default: case 's9y-include-entry': if (preg_match('/^prop[=:]/', $buffer[3])) { $entry = serendipity_fetchEntryProperties($id); $propname = preg_replace('/^prop[=:]/', '', $buffer[3]); $newbuf = $entry[$propname]; } else { $entry = serendipity_fetchEntry('id', $id, true, 'true'); $newbuf = $entry[$buffer[3]]; } break; } return $newbuf; }
function generateDelayed() { global $serendipity; $this->upgradeCheck(); $sql = "SELECT id, timestamp\n FROM\n {$serendipity['dbPrefix']}delayed_trackbacks"; $entries = serendipity_db_query($sql); if (is_array($entries) && !empty($entries)) { foreach ($entries as $entry) { if ($entry['timestamp'] <= serendipity_serverOffsetHour()) { include_once S9Y_INCLUDE_PATH . 'include/functions_trackbacks.inc.php'; $stored_entry = serendipity_fetchEntry('id', $entry['id'], 1, 1); if (isset($_SESSION['serendipityRightPublish'])) { $oldPublighRights = $_SESSION['serendipityRightPublish']; } else { $oldPublighRights = 'unset'; } $_SESSION['serendipityRightPublish'] = true; #remove unnatural entry-data which let the update fail if (isset($stored_entry['loginname'])) { unset($stored_entry['loginname']); } if (isset($stored_entry['email'])) { unset($stored_entry['email']); } # Convert fetched categories to storable categories. $current_cat = $stored_entry['categories']; $stored_entry['categories'] = array(); foreach ($current_cat as $categoryidx => $category_data) { $stored_entry['categories'][$category_data['categoryid']] = $category_data['categoryid']; } ob_start(); serendipity_updertEntry($stored_entry); ob_end_clean(); if ($oldPublighRights == 'unset') { unset($_SESSION['serendipityRightPublish']); } else { $_SESSION['serendipityRightPublish'] = $oldPublighRights; } #the trackbacks are now generated $this->removeDelayed($entry['id']); } } } }
function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks =& $bag->get('event_hooks'); if (isset($hooks[$event])) { switch ($event) { case 'backend_entry_updertEntry': if (isset($serendipity['POST']['no_save'])) { $eventData['error'] = true; } return true; break; case 'backend_entry_presave': if (!isset($serendipity['POST']['properties']) || !is_array($serendipity['POST']['properties']) || !isset($eventData['id']) || empty($serendipity['POST']['properties']['lang_selected'])) { return true; } // Restore native language version, ONLY if a different language is being submitted. $restore = serendipity_db_query("SELECT title, body, extended FROM {$serendipity['dbPrefix']}entries WHERE id = " . (int) $eventData['id']); if (is_array($restore)) { foreach ($restore as $row) { foreach ($this->switch_keys as $restorekey) { $eventData[$restorekey] = $row[$restorekey]; } } } break; case 'backend_publish': case 'backend_save': if (!isset($serendipity['POST']['properties']) || !is_array($serendipity['POST']['properties']) || !isset($eventData['id']) || empty($serendipity['POST']['properties']['lang_selected'])) { return true; } $ls =& $serendipity['POST']['properties']['lang_selected']; $this->supported_properties[] = 'multilingual_title_' . $ls; $serendipity['POST']['properties']['multilingual_title_' . $ls] = $serendipity['POST']['title']; $this->supported_properties[] = 'multilingual_body_' . $ls; $serendipity['POST']['properties']['multilingual_body_' . $ls] = $serendipity['POST']['body']; $this->supported_properties[] = 'multilingual_extended_' . $ls; $serendipity['POST']['properties']['multilingual_extended_' . $ls] = $serendipity['POST']['extended']; // Get existing data $property = serendipity_fetchEntryProperties($eventData['id']); foreach ($this->supported_properties as $prop_key) { $prop_val = isset($serendipity['POST']['properties'][$prop_key]) ? $serendipity['POST']['properties'][$prop_key] : null; if (!isset($property[$prop_key]) && !empty($prop_val)) { $q = "INSERT INTO {$serendipity['dbPrefix']}entryproperties (entryid, property, value) VALUES (" . (int) $eventData['id'] . ", '" . serendipity_db_escape_string($prop_key) . "', '" . serendipity_db_escape_string($prop_val) . "')"; } elseif ($property[$propkey] != $prop_val && !empty($prop_val)) { $q = "UPDATE {$serendipity['dbPrefix']}entryproperties SET value = '" . serendipity_db_escape_string($prop_val) . "' WHERE entryid = " . (int) $eventData['id'] . " AND property = '" . serendipity_db_escape_string($prop_key) . "'"; } else { $q = "DELETE FROM {$serendipity['dbPrefix']}entryproperties WHERE entryid = " . (int) $eventData['id'] . " AND property = '" . serendipity_db_escape_string($prop_key) . "'"; } serendipity_db_query($q); } return true; break; case 'genpage': if (!is_object($serendipity['smarty'])) { // never init in genpage without adding previously set $vars, which is $view etc! serendipity_smarty_init($serendipity['plugindata']['smartyvars']); } if (!defined('Smarty::SMARTY_VERSION')) { $this->tag_title(); // in Smarty 2 only // check this deeply! - since at least for the non-tag banner entry_title this seems to not work here with Smarty 3 - see workaround in frontent_display } if ($serendipity['version'][0] < 2) { $serendipity['smarty']->register_modifier('multilingual_lang', array($this, 'strip_langs')); } else { $serendipity['smarty']->registerPlugin('modifier', 'multilingual_lang', array($this, 'strip_langs')); } return true; break; case 'backend_entryform': if (!empty($this->showlang)) { // language is given (he wants a translation) $props = serendipity_fetchEntryProperties($eventData['id']); // this is a language change, not a save -- we want the DB values // unless the user chooses to retain previous language content if (isset($serendipity['POST']['no_save'])) { foreach ($this->switch_keys as $key) { if (!serendipity_db_bool($this->get_config('copytext', 'true')) || !empty($props['multilingual_' . $key . '_' . $this->showlang])) { $eventData[$key] = $props['multilingual_' . $key . '_' . $this->showlang]; } } } } elseif (!empty($eventData['id'])) { // language is NOT given (he wants the default language) $props = serendipity_fetchEntry('id', $eventData['id'], 1, 1); if (!is_array($props)) { return true; } // this is a language change, not a save -- we want the DB values if (isset($serendipity['POST']['no_save'])) { foreach ($this->switch_keys as $key) { $eventData[$key] = $props[$key]; } } } return true; break; case 'css': if (strpos($eventData, '.serendipity_multilingualInfo')) { // class exists in CSS, so a user has customized it and we don't need default return true; } ?> .serendipity_multilingualInfo { margin-left: auto; margin-right: 0px; text-align: right; font-size: 7pt; display: block; margin-top: 5px; margin-bottom: 0px; } .serendipity_multilingualInfo a { font-size: 7pt; text-decoration: none; } .serendipity_multilingualInfo a:hover { color: green; } <?php return true; break; case 'frontend_display': // cannot use tag_title() method here and use with Smarty3+ only // check for single entry multilingual context only, to set the correct themes banner title if (defined('Smarty::SMARTY_VERSION') && isset($eventData['properties']['multilingual_title_' . $this->showlang]) && serendipity_db_bool($this->get_config('tagged_title', 'true')) && $serendipity['view'] == 'entry') { $serendipity['smarty']->assign('head_title', $eventData['title']); } break; case 'entry_display': if (!is_array($eventData)) { return false; } $place = $this->get_config('placement', 'add_footer'); $msg = '<div class="serendipity_multilingualInfo">' . PLUGIN_EVENT_MULTILINGUAL_SWITCH . ': %s</div>'; if ($addData['extended'] || $addData['preview']) { if ($langs = $this->getLang($eventData[0]['id'], $eventData[0]['properties'])) { if (!empty($this->showlang)) { $props =& $eventData[0]['properties']; foreach ($this->switch_keys as $key) { if (!empty($props['multilingual_' . $key . '_' . $this->showlang])) { $eventData[0][$key] = $props['multilingual_' . $key . '_' . $this->showlang]; } } unset($eventData[0]['properties']['ep_cache_body']); unset($eventData[0]['properties']['ep_cache_extended']); } $eventData[0][$place] .= sprintf($msg, $langs); } } else { $elements = count($eventData); // Walk entry array and insert karma voting line. for ($i = 0; $i < $elements; $i++) { if (!isset($eventData[$i][$place])) { $eventData[$i][$place] = ''; } if (!empty($this->lang_display)) { $this->showlang = $this->lang_display; } if (!empty($this->showlang)) { // Not sure if it's the best way to get translations shown instead of the // original entries $props =& $eventData[$i]['properties']; foreach ($this->switch_keys as $key) { if (!empty($props['multilingual_' . $key . '_' . $this->showlang])) { $eventData[$i][$key] = $props['multilingual_' . $key . '_' . $this->showlang]; } } unset($eventData[$i]['properties']['ep_cache_body']); unset($eventData[$i]['properties']['ep_cache_extended']); } if ($langs = $this->getLang($eventData[$i]['id'], $eventData[$i]['properties'])) { $eventData[$i][$place] .= sprintf($msg, $langs); // this may throw two for the same, eg. when already linked as <en>, them set to POST cookie <en> too in the sidebar selection. // In this case the lang link and the default lang link are both named 'english' } } } // Tagged translation of Blog title and description $this->tag_title(); if (serendipity_db_bool($this->get_config('tagged_entries', 'true'))) { foreach ($eventData as $key => $entry) { if (isset($eventData[$key]['title'])) { $eventData[$key]['title'] = $this->strip_langs($eventData[$key]['title']); $eventData[$key]['body'] = $this->strip_langs($eventData[$key]['body']); if (is_array($eventData[$key]['categories'])) { foreach ($eventData[$key]['categories'] as $ec_key => $ec_val) { $eventData[$key]['categories'][$ec_key]['category_name'] = $this->strip_langs($ec_val['category_name']); } } } } } return true; break; case 'backend_display': if (isset($serendipity['POST']['properties']['lang_selected'])) { $lang_selected = $serendipity['POST']['properties']['lang_selected']; } else { $lang_selected = ''; } $use_lang = $serendipity['languages']; unset($use_lang[$serendipity['lang']]); // Unset 'default' language. Easier handling. $langs = ''; //asort($use_lang); //sorts by value ASC, but if so we should do it everywhere though foreach ($use_lang as $code => $desc) { $langs .= '<option value="' . $code . '" ' . ($lang_selected == $code ? 'selected="selected"' : '') . '>' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($desc) : htmlspecialchars($desc, ENT_COMPAT, LANG_CHARSET)) . '</option>' . "\n"; } if ($serendipity['version'][0] < 2) { ?> <fieldset style="margin: 5px"> <legend><?php echo PLUGIN_EVENT_MULTILINGUAL_TITLE; ?> </legend> <div class="form_field"> <?php } else { ?> <fieldset id="edit_entry_multilingual" class="entryproperties_multilingual" style="margin: 1em 0"> <span class="wrap_legend"><legend><?php echo PLUGIN_EVENT_MULTILINGUAL_TITLE; ?> </legend></span> <div class="form_field"> <?php } if (isset($eventData['id'])) { ?> <label for="serendipity[properties][lang_selected]"><?php echo PLUGIN_EVENT_MULTILINGUAL_CURRENT; ?> </label><br /> <select name="serendipity[properties][lang_selected]" id="properties_lang_selected" /> <option value=""><?php echo USE_DEFAULT; ?> </option> <?php echo $langs; ?> </select> <input class="serendipityPrettyButton input_button" type="submit" name="serendipity[no_save]" value="<?php echo PLUGIN_EVENT_MULTILINGUAL_SWITCH; ?> " /> <?php } else { echo '<span class="msg_notice"><span class="icon-info-circled"></span> ' . PLUGIN_EVENT_MULTILINGUAL_NEEDTOSAVE . "</span>\n"; } ?> </div> </fieldset> <?php return true; break; case 'frontend_entryproperties': if (class_exists('serendipity_event_entryproperties')) { // Fetching of properties is already done there, so this is just for poor users who don't have the entryproperties plugin enabled return true; } $q = "SELECT entryid, property, value FROM {$serendipity['dbPrefix']}entryproperties WHERE entryid IN (" . implode(', ', array_keys($addData)) . ") AND property LIKE '%multilingual_%'"; $properties = serendipity_db_query($q); if (!is_array($properties)) { return true; } foreach ($properties as $idx => $row) { $eventData[$addData[$row['entryid']]]['properties'][$row['property']] = $row['value']; } return true; break; case 'frontend_entries_rss': if (is_array($eventData)) { foreach ($eventData as $i => $entry) { if (!empty($this->lang_display)) { $this->showlang = $this->lang_display; } if (!empty($this->showlang)) { // Not sure if it's the best way to get translations shown instead of the // original entries $props =& $eventData[$i]['properties']; foreach ($this->switch_keys as $key) { if (!empty($props['multilingual_' . $key . '_' . $this->showlang])) { $eventData[$i][$key] = $props['multilingual_' . $key . '_' . $this->showlang]; } } unset($eventData[$i]['properties']['ep_cache_body']); unset($eventData[$i]['properties']['ep_cache_extended']); } } } if (serendipity_db_bool($this->get_config('tagged_entries', 'true'))) { foreach ($eventData as $key => $entry) { $eventData[$key]['title'] = $this->strip_langs($eventData[$key]['title']); $eventData[$key]['body'] = $this->strip_langs($eventData[$key]['body']); } } break; case 'frontend_fetchentries': case 'frontend_fetchentry': if (!empty($this->lang_display)) { $this->showlang = $this->lang_display; } if ($addData['source'] == 'search' && empty($this->showlang) && !empty($_SESSION['last_lang'])) { header('X-SearchLangOverride: ' . $_SESSION['last_lang']); $this->showlang = $_SESSION['last_lang']; } if (empty($this->showlang)) { return; } $cond = "multilingual_body.value AS multilingual_body,\n"; $cond .= "multilingual_extended.value AS multilingual_extended,\n"; $cond .= "multilingual_title.value AS multilingual_title,\n"; if (empty($eventData['addkey'])) { $eventData['addkey'] = $cond; } else { $eventData['addkey'] .= $cond; } $cond = "\nLEFT OUTER JOIN {$serendipity['dbPrefix']}entryproperties multilingual_body\n ON (e.id = multilingual_body.entryid AND multilingual_body.property = 'multilingual_body_" . $this->showlang . "')"; $cond .= "\nLEFT OUTER JOIN {$serendipity['dbPrefix']}entryproperties multilingual_extended\n ON (e.id = multilingual_extended.entryid AND multilingual_extended.property = 'multilingual_extended_" . $this->showlang . "')"; $cond .= "\nLEFT OUTER JOIN {$serendipity['dbPrefix']}entryproperties multilingual_title\n ON (e.id = multilingual_title.entryid AND multilingual_title.property = 'multilingual_title_" . $this->showlang . "')"; if (!empty($this->lang_display)) { // If lang_display is set - we want ONLY the entries which have translation $eventData['and'] .= " AND multilingual_body.value IS NOT NULL"; } if (empty($eventData['joins'])) { $eventData['joins'] = $cond; } else { $eventData['joins'] .= $cond; } if ($addData['source'] == 'search' && isset($eventData['find_part'])) { $term =& $addData['term']; $cond =& $eventData; if ($serendipity['dbType'] == 'postgres') { $cond['find_part'] .= " OR (multilingual_body.value ILIKE '%{$term}%' OR multilingual_extended.value ILIKE '%{$term}%' OR multilingual_title.value ILIKE '%{$term}%')"; } elseif ($serendipity['dbType'] == 'sqlite') { $term = serendipity_mb('strtolower', $term); $cond['find_part'] .= " OR (lower(multilingual_body.value) LIKE '%{$term}%' OR lower(multilingual_extended.value) LIKE '%{$term}%' OR lower(multilingual_title.value) LIKE '%{$term}%')"; } else { if (preg_match('@["\\+\\-\\*~<>\\(\\)]+@', $term)) { $bool = ' IN BOOLEAN MODE'; } else { $bool = ''; } $cond['find_part'] .= " OR (\n MATCH(multilingual_body.value) AGAINST('{$term}' {$bool})\n OR MATCH(multilingual_extended.value) AGAINST('{$term}' {$bool})\n OR MATCH(multilingual_title.value) AGAINST('{$term}' {$bool})\n )"; } } return true; break; case 'frontend_comment': if (serendipity_db_bool($this->get_config('tagged_entries', 'true'))) { $serendipity['smarty']->assign('head_title', $this->strip_langs($serendipity['head_title'])); } if (serendipity_db_bool($this->get_config('tagged_title', 'true'))) { $serendipity['smarty']->assign('head_subtitle', $this->strip_langs($serendipity['head_subtitle'])); } return true; break; case 'frontend_sidebar_plugins': if (serendipity_db_bool($this->get_config('tagged_sidebar', 'true'))) { foreach ($eventData as $key => $entry) { $eventData[$key]['title'] = $this->strip_langs($eventData[$key]['title']); $eventData[$key]['content'] = $this->strip_langs($eventData[$key]['content']); } } return true; break; default: return false; break; } } else { return false; } }
function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks =& $bag->get('event_hooks'); if (isset($hooks[$event])) { switch ($event) { case 'backend_publish': case 'backend_save': // Purge, so that the data within the entry takes precedence over other changes serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}wikireferences WHERE entryid = " . (int) $eventData['id']); break; case 'backend_sidebar_entries': $this->setupDB(); echo '<li class="serendipitySideBarMenuLink serendipitySideBarMenuEntryLinks"><a href="?serendipity[adminModule]=event_display&serendipity[adminAction]=wikireferences">' . PLUGIN_EVENT_WIKILINKS_MAINT . '</a></li>'; break; case 'backend_sidebar_entries_event_display_wikireferences': $entries = serendipity_db_query("SELECT id, refname FROM {$serendipity['dbPrefix']}wikireferences ORDER BY refname ASC"); echo '<p>' . PLUGIN_EVENT_WIKILINKS_MAINT_DESC . '</p>'; echo '<form action="serendipity_admin.php" method="post" name="serendipityEntry">'; echo '<input type="hidden" name="serendipity[adminModule]" value="event_display" />'; echo '<input type="hidden" name="serendipity[adminAction]" value="wikireferences" />'; echo '<select name="serendipity[wikireference]">'; echo '<option value="">...</option>'; foreach ((array) $entries as $idx => $row) { echo '<option value="' . $row['id'] . '" ' . ($row['id'] == $serendipity['POST']['wikireference'] ? 'selected="selected"' : '') . '>' . $row['refname'] . '</option>' . "\n"; } echo '</select>'; echo '<input type="submit" class="serendipityPrettyButton input_button" name="serendipity[typeSubmit]" value="' . GO . '" />'; echo '<br /><br />'; if ($serendipity['POST']['wikireference'] > 0) { if ($serendipity['POST']['saveSubmit']) { serendipity_db_update('wikireferences', array('id' => $serendipity['POST']['wikireference']), array('refname' => $serendipity['POST']['wikireference_refname'], 'ref' => $serendipity['POST']['wikireference_ref'])); echo '<div class="serendipityAdminMsgSuccess"><img style="height: 22px; width: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_success.png') . '" alt="" />' . DONE . ': ' . sprintf(SETTINGS_SAVED_AT, serendipity_strftime('%H:%M:%S')) . '</div>'; } $ref = serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}wikireferences WHERE id = " . (int) $serendipity['POST']['wikireference'], true, 'assoc'); $entry = serendipity_fetchEntry('id', $ref['entryid']); echo '<div>'; echo '<label>' . PLUGIN_EVENT_WIKILINKS_DB_REFNAME . '</label><br />'; echo '<input type="text" name="serendipity[wikireference_refname]" value="' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($ref['refname']) : htmlspecialchars($ref['refname'], ENT_COMPAT, LANG_CHARSET)) . '" />'; echo '<input type="submit" class="serendipityPrettyButton input_button" name="serendipity[saveSubmit]" value="' . SAVE . '" />'; echo '</div>'; echo '<div>'; echo '<label>' . PLUGIN_EVENT_WIKILINKS_DB_REF . '</label><br />'; echo '<textarea cols="80" rows="20" name="serendipity[wikireference_ref]">' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($ref['ref']) : htmlspecialchars($ref['ref'], ENT_COMPAT, LANG_CHARSET)) . '</textarea>'; echo '</div>'; echo '<div>'; echo '<label>' . PLUGIN_EVENT_WIKILINKS_DB_ENTRYDID . '</label>'; echo '<a href="' . serendipity_archiveUrl($ref['entryid'], $entry['title']) . '">' . $entry['title'] . '</a>'; echo '<p><a class="serendipityPrettyButton" href="?serendipity[action]=admin&serendipity[adminModule]=entries&serendipity[adminAction]=edit&serendipity[id]=' . $entry['id'] . '">' . EDIT_ENTRY . '</a></p>'; echo '</div>'; } echo '</form>'; break; case 'frontend_display': $this->out_references = array(); foreach ($this->markup_elements as $temp) { if (serendipity_db_bool($this->get_config($temp['name'], true)) && isset($eventData[$temp['element']]) && !$eventData['properties']['ep_disable_markup_' . $this->instance] && !isset($serendipity['POST']['properties']['disable_markup_' . $this->instance])) { $element = $temp['element']; $is_body = false; if ($element == 'body' || $element == 'extended') { $source =& $this->getFieldReference($element, $eventData); if ($source === '') { // Prevent bug from serendipity 0.9 $source =& $eventData[$element]; } $is_body = true; } else { $source =& $eventData[$element]; } $this->references = $this->refcount = array(); $this->ref_entry = $eventData['id']; $source = preg_replace_callback('^' . $this->get_config('reference_match') . '^imsU', array($this, '_reference'), $source); $source = preg_replace_callback("#(\\[\\[|\\(\\(|\\{\\{)(.+)(\\]\\]|\\)\\)|\\}\\})#isUm", array($this, '_wikify'), $source); $source .= $this->reference_parse(); if ($is_body) { if (!is_array($eventData['properties']['references'])) { $eventData['properties']['references'] = array(); } $eventData['properties']['references'] += $this->references; } } } return true; break; case 'external_plugin': $what = ''; if ($eventData == 'popup_choose_entry') { $what = 'body'; } elseif ($eventData == 'popup_choose_entrybody') { $what = 'body'; } elseif ($eventData == 'popup_choose_entryextended') { $what = 'extended'; } elseif (preg_match('/^popup_choose_entry(.*)$/i', $eventData, $matches)) { // get the custom thing that is to be selected, for example a nugget $what = $matches[1]; } if (empty($what)) { return false; } ?> <html> <head> <title><?php echo PLUGIN_EVENT_WIKILINKS_LINKENTRY; ?> </title> <meta http-equiv="Content-Type" content="text/html; charset=<?php echo LANG_CHARSET; ?> " /> <link rel="stylesheet" type="text/css" href="<?php echo 'serendipity.css.php?serendipity[css_mode]=serendipity_admin.css'; ?> " /> <link rel="stylesheet" type="text/css" href="<?php echo serendipity_getTemplateFile('admin/pluginmanager.css'); ?> " /> </head> <body id="serendipity_admin_page"> <div id="serendipityAdminFrame"> <div id="serendipityAdminBanner"> <h1><?php echo SERENDIPITY_ADMIN_SUITE; ?> </h1> <h2><?php echo PLUGIN_EVENT_WIKILINKS_LINKENTRY_DESC; ?> </h2> </div> <div id="serendipityAdminContent"> <ul> <?php $sql = "SELECT *\n FROM {$serendipity['dbPrefix']}entries\n ORDER BY timestamp DESC"; $e = serendipity_db_query($sql); if (is_array($e)) { foreach ($e as $entry) { $link = serendipity_archiveURL($entry['id'], $entry['title'], 'serendipityHTTPPath', true, array('timestamp' => $entry['timestamp'])); $jslink = "'<a href=\\'{$link}\\'>" . (function_exists('serendipity_specialchars') ? serendipity_specialchars($entry['title']) : htmlspecialchars($entry['title'], ENT_COMPAT, LANG_CHARSET)) . "<' + '/a>'"; echo '<li style="margin-bottom: 10px">' . '<a href="javascript:parent.self.opener.use_link_' . $what . '(' . $jslink . '); self.close();" title="' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($entry['title']) : htmlspecialchars($entry['title'], ENT_COMPAT, LANG_CHARSET)) . '"><strong>' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($entry['title']) : htmlspecialchars($entry['title'], ENT_COMPAT, LANG_CHARSET)) . '</strong></a> (<a href="' . $link . '" title="' . (function_exists('serendipity_specialchars') ? serendipity_specialchars($entry['title']) : htmlspecialchars($entry['title'], ENT_COMPAT, LANG_CHARSET)) . '">#' . $entry['id'] . '</a>)<br />' . POSTED_BY . ' ' . $entry['author'] . ' ' . ON . ' ' . serendipity_formatTime(DATE_FORMAT_SHORT, $entry['timestamp']) . ($entry['isdraft'] != 'false' ? ' (' . DRAFT . ')' : '') . '</a></li>' . "\n"; } } ?> </ul> </div> </div> </body> </html> <?php return true; case 'backend_entry_toolbar_extended': if (!isset($txtarea)) { $txtarea = 'serendipity[extended]'; $func = 'extended'; } case 'backend_entry_toolbar_body': if (!isset($txtarea)) { if (isset($eventData['backend_entry_toolbar_body:textarea'])) { // event caller has given us the name of the textarea converted // into a wysiwg editor(for example, the staticpages plugin) $txtarea = $eventData['backend_entry_toolbar_body:textarea']; } else { // default value $txtarea = 'serendipity[body]'; } if (isset($eventData['backend_entry_toolbar_body:nugget'])) { $func = $eventData['backend_entry_toolbar_body:nugget']; } else { $func = 'body'; } } // CKEDITOR needs this little switch if (preg_match('@^nugget@i', $func)) { $cke_txtarea = $func; } else { $cke_txtarea = $txtarea; } if (!isset($popcl)) { $popcl = ' serendipityPrettyButton'; } if (!isset($style)) { $style = 'text-align: right; margin-top: 5px'; } ?> <script type="text/javascript"> <!-- function use_link_<?php echo $func; ?> (txt) { // use the shared insert function instead of the wikilinks provided function // the shared JS function implements all the wikilinks functionality + NO WYSIWYG insertion serendipity_imageSelector_addToBody(txt, '<?php echo $func; ?> ' ); return; if(typeof(CKEDITOR) != 'undefined') { var oEditor = CKEDITOR.instances['<?php echo $cke_txtarea; ?> ']; oEditor.insertHtml(txt); } else if(typeof(FCKeditorAPI) != 'undefined') { var oEditor = FCKeditorAPI.GetInstance('<?php echo $txtarea; ?> ') ; oEditor.InsertHtml(txt); } else if(typeof(xinha_editors) != 'undefined') { if(typeof(xinha_editors['<?php echo $txtarea; ?> ']) != 'undefined') { // this is good for the two default editors (body & extended) xinha_editors['<?php echo $txtarea; ?> '].insertHTML(txt); } else if(typeof(xinha_editors['<?php echo $func; ?> ']) != 'undefined') { // this should work in any other cases than previous one xinha_editors['<?php echo $func; ?> '].insertHTML(txt); } else { // this is the last chance to retrieve the instance of the editor ! // editor has not been registered by the name of it's textarea // so we must iterate over editors to find the good one for (var editorName in xinha_editors) { if('<?php echo $txtarea; ?> ' == xinha_editors[editorName]._textArea.name) { xinha_editors[editorName].insertHTML(txt); return; } } // not found ?!? } } else if(typeof(HTMLArea) != 'undefined') { if(typeof(editor<?php echo $func; ?> ) != 'undefined') editor<?php echo $func; ?> .insertHTML(txt); else if(typeof(htmlarea_editors) != 'undefined' && typeof(htmlarea_editors['<?php echo $func; ?> ']) != 'undefined') htmlarea_editors['<?php echo $func; ?> '].insertHTML(txt); } else if(typeof(TinyMCE) != 'undefined') { //tinyMCE.execCommand('mceInsertContent', false, txt); tinyMCE.execInstanceCommand('<?php echo $txtarea; ?> ', 'mceInsertContent', false, txt); } else { // default case: no wysiwyg editor txtarea = document.getElementById('<?php echo $txtarea; ?> '); if (txtarea.createTextRange && txtarea.caretPos) { caretPos = txtarea.caretPos; caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? caretPos.text + ' ' + txt + ' ' : caretPos.text + ' ' + txt + ' '; } else { txtarea.value += ' ' + txt + ' '; } // alert(obj); txtarea.focus(); } } //--> </script> <?php echo '<input type="button" class="serendipityPrettyButton input_button" onclick="entrypopup = window.open(\'' . $serendipity['baseURL'] . $serendipity['indexFile'] . '?/plugin/popup_choose_entry' . $func . '\', \'js_entrypopup\', \'width=800,height=600,toolbar=no,scrollbars=1,scrollbars,resize=1,resizable=1\')" value="' . PLUGIN_EVENT_WIKILINKS_LINKENTRY . '" />'; return true; default: return false; } } else { return false; } }