[Php-blog-plugin-cvs] additional_plugins/serendipity_event_spamblock_bayes ChangeLog, 1.7, 1.8 bay
A reliable, secure & extensible PHP blog | Not mainstream since 2002
Brought to you by:
garvinhicking,
jhermanns
From: onli <on...@us...> - 2010-06-14 14:24:03
|
Update of /cvsroot/php-blog/additional_plugins/serendipity_event_spamblock_bayes In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv15582 Modified Files: ChangeLog bayes_commentlist.js lang_de.inc.php lang_en.inc.php serendipity_event_spamblock_bayes.css serendipity_event_spamblock_bayes.js serendipity_event_spamblock_bayes.php Log Message: Update to 0.3.7, see Changelog Index: lang_de.inc.php =================================================================== RCS file: /cvsroot/php-blog/additional_plugins/serendipity_event_spamblock_bayes/lang_de.inc.php,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- lang_de.inc.php 23 May 2010 12:02:37 -0000 1.7 +++ lang_de.inc.php 14 Jun 2010 14:23:51 -0000 1.8 @@ -51,5 +51,9 @@ @define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DESC', 'Sollen abgewiesen Kommentare im Papierkorb gespeichert werden?'); @define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_EMPTY', 'Papierkorb leeren'); @define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RESTORE', 'Wiederherstellen'); +@define('PLUGIN_EVENT_SPAMBLOCK_BAYES_MENU_ANALYSIS', 'Analyse'); +@define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DELETE', 'Papierkorbgrenze'); +@define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DELETE_DESC', 'Ab welcher Bewertung soll ein Kommentar direkt gelöscht statt in den Papierkorb geschoben werden? Beispiel: "98".'); + ?> Index: serendipity_event_spamblock_bayes.php =================================================================== RCS file: /cvsroot/php-blog/additional_plugins/serendipity_event_spamblock_bayes/serendipity_event_spamblock_bayes.php,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- serendipity_event_spamblock_bayes.php 25 May 2010 20:49:46 -0000 1.7 +++ serendipity_event_spamblock_bayes.php 14 Jun 2010 14:23:51 -0000 1.8 @@ -13,6 +13,9 @@ class serendipity_event_spamblock_bayes extends serendipity_event { var $lastRating; + //store serendipity[GET] when loading the menu for later use in the + //menu itself + var $get; //maps from the names used in this plugin to the names //used in the db var $type = array( 'ip' => 'ip', @@ -31,7 +34,7 @@ $this->title = PLUGIN_EVENT_SPAMBLOCK_BAYES_NAME; $propbag->add ( 'description', PLUGIN_EVENT_SPAMBLOCK_BAYES_DESC); $propbag->add ( 'name', $this->title); - $propbag->add ( 'version', '0.3.6.1' ); + $propbag->add ( 'version', '0.3.7' ); $propbag->add ( 'event_hooks', array ('frontend_saveComment' => true, 'backend_spamblock_comments_shown' => true, 'external_plugin' => true, @@ -52,7 +55,8 @@ 'logtype', 'logfile', 'menu', - 'recycler' + 'recycler', + 'recyclerdelete' )); } @@ -102,6 +106,13 @@ $propbag->add('description', PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DESC); $propbag->add('default', true); break; + case 'recyclerdelete': + $propbag->add('type', 'string'); + $propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DELETE); + $propbag->add('description', PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DELETE_DESC); + $propbag->add('default', ''); + return true; + break; case 'path': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_EVENT_SPAMBLOCK_BAYES_PATH); @@ -205,9 +216,25 @@ } else { $spamBarrier = 0.9; } - if(max($ratings) >= $spamBarrier) { + + #If a field is clearly spam, a spammer probably mixed + #it's spam with valid content to fool the spamfilter. + $max_ratings = array(); + $min_ratings = array(); + foreach ($ratings as $rating) { + if ($rating >= $spamBarrier) { + $max_ratings[] = $rating; + } + if ($rating <= 0.1) { + $min_ratings[] = $rating; + } + } + if (count($max_ratings) > count($min_ratings)) { return max($ratings); } + /*if(max($ratings) >= $spamBarrier) { + return max($ratings); + }*/ return (array_sum($ratings) / $divider); } @@ -235,12 +262,13 @@ if ($spam_texts == 0 || $ham_texts == 0) { return false; } - + if ($type == $this->type['ip']) { $tokens = array($comment => 1); } else { $tokens = $this->tokenize($comment); } + if ($tokens === false|| empty($tokens)) { return false; } @@ -280,19 +308,21 @@ $n = 0; $probability = 0; - #calculate spamminness and hamminess - #take only those important enough foreach($tokens as $word => $count) { if ($importance[$word] > 0.2) { $n++; $probability += $ratings[$word]; } } - + + + if ( $n > 0 ) { $probability = $probability / $n; } else { - $probability = 1; + // was: = 1, but if undecided, we better want to be at + // "undecided" than "ham" + $probability = 0.5; } return abs(1 - $probability); } @@ -622,7 +652,20 @@ if(isset($_REQUEST['restore'])) { if ( !empty($_REQUEST['serendipity']['selected'])) { $ids = array_keys($_REQUEST['serendipity']['selected']); + #When restoring a comment we can be pretty sure it's a valid one + $comments = $this->getRecyclerComment($ids); + foreach ($comments as $comment) { + $this->startLearn($comment, 'ham'); + } + $this->restoreComments($ids); + + if (in_array(0, $ids)) { + #this happened when the recyclercode was broken + $msg = "Not able to restore comment with id 0"; + $msgtype = 'error'; + } + if (count($ids) > 1) { $msg = 'Comments '. implode(', ', $ids) .' restored'; } else { @@ -635,18 +678,48 @@ } } if(isset($_REQUEST['empty'])) { - $this->emptyRecycler(); - $msg = 'Recycler emptied'; - $msgtype = 'success'; + if (isset($_REQUEST['recyclerSpam'])) { + $comments = $this->getAllRecyclerComments(); + foreach ($comments as $comment) { + $this->startLearn($comment, 'spam'); + } + } + $success = $this->emptyRecycler(); + if (serendipity_db_bool($success)) { + $msg = 'Recycler emptied'; + $msgtype = 'success'; + } else { + $msg = urlencode($success); + $msgtype = 'error'; + } } $redirect= '<meta http-equiv="REFRESH" content="0;url='; $url = 'serendipity_admin.php?serendipity[adminModule]=event_display'; $url .= '&serendipity[adminAction]=spamblock_bayes'; $url .= '&serendipity[subpage]=3'; - if ($msgtype == 'success') { - $url .= '&serendipity[success]='. $msg .'">'; - } else if ($msgtype == 'message') { - $url .= '&serendipity[message]='. $msg .'">'; + if (!empty($msgtype)) { + $url .= '&serendipity['.$msgtype.']='. $msg .'">'; + } + echo $redirect . $url; + break; + case 'bayesAnalyse': + if(isset($_REQUEST['comments'])) { + $this->emptyRecycler(); + $msgtype = 'message'; + $comment_ids = array_keys($_REQUEST['comments']); + } else { + $msg = 'Please select at least one comment'; + $msgtype = 'message'; + } + $redirect= '<meta http-equiv="REFRESH" content="0;url='; + $url = 'serendipity_admin.php?serendipity[adminModule]=event_display'; + $url .= '&serendipity[adminAction]=spamblock_bayes'; + $url .= '&serendipity[subpage]=4'; + foreach ($comment_ids as $comment) { + $url .= '&serendipity[comments]['.$comment.']'; + } + if (!empty($msgtype)) { + $url .= '&serendipity['.$msgtype.']='. $msg .'">'; } echo $redirect . $url; break; @@ -787,14 +860,16 @@ } global $serendipity; if (isset($serendipity['GET']['message'])) { - echo '<p class="serendipityAdminMsgNote">'.$serendipity['GET']['message'].'</p>'; + echo '<p class="serendipityAdminMsgNote">'.htmlspecialchars($serendipity['GET']['message']).'</p>'; } if (isset($serendipity['GET']['success'])) { - echo '<p class="serendipityAdminMsgSuccess">'.$serendipity['GET']['success'].'</p>'; + echo '<p class="serendipityAdminMsgSuccess">'.htmlspecialchars($serendipity['GET']['success']).'</p>'; } if (isset($serendipity['GET']['error'])) { - echo '<p class="serendipityAdminMsgError">'.$serendipity['GET']['error'].'</p>'; + echo '<p class="serendipityAdminMsgError">'.htmlspecialchars($serendipity['GET']['error']).'</p>'; } + $this->get = $serendipity['GET']; + $this->displayMenu($serendipity['GET']['subpage']); return true; break; @@ -820,7 +895,8 @@ #Navigation: $menuNames = array( PLUGIN_EVENT_SPAMBLOCK_BAYES_MENU_LEARN, PLUGIN_EVENT_SPAMBLOCK_BAYES_MENU_DATABASE, - PLUGIN_EVENT_SPAMBLOCK_BAYES_MENU_RECYCLER); + PLUGIN_EVENT_SPAMBLOCK_BAYES_MENU_RECYCLER, + PLUGIN_EVENT_SPAMBLOCK_BAYES_MENU_ANALYSIS); $menu ='<div id="bayesNav"> <ul>'; $menuLength = count($menuNames); @@ -853,6 +929,9 @@ case '3': $this->showRecyclerMenu(); break; + case '4': + $this->showAnalysisMenu($this->get['commentpage']); + break; default: break; } @@ -955,16 +1034,91 @@ <div id="bayesControls"> <input type="submit" class="serendipityPrettyButton input_button" value="'.PLUGIN_EVENT_SPAMBLOCK_BAYES_RESTORE.'" name="restore"/> <input type="submit" class="serendipityPrettyButton input_button" value="'.PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_EMPTY.'" name="empty" /> + <label for="recyclerSpam">'.PLUGIN_EVENT_SPAMBLOCK_BAYES_SPAMBUTTON.'<input type="checkbox" id="recyclerSpam" class="serendipityPrettyButton input_button" value="" name="recyclerSpam" /></label> </div>' - . $this->showTable('spamblock_bayes_recycler', true, '', 'bayesRecyclerTable', array('author', 'url', 'body', 'email', 'timestamp'), + . $this->showTable('spamblock_bayes_recycler', true, '', 'bayesRecyclerTable', array('author', 'url', 'email', 'body', 'timestamp'), array( 'timestamp' => create_function('$time', 'return strftime(\'%e.%m.%y, %R\', $time);') )) .'</form> <script src="'.$this->path.'jquery.excerpt.js" type="text/javascript"></script> - <script>shortenAll("body");</script>'; + <script>shortenAll("body", 3);</script>'; } + + function showAnalysisMenu($commentpage=0) { + if (isset($this->get['comments'])) { + //comments already were selected + $comment_ids = array_keys($this->get['comments']); + $this->showAnalysis($comment_ids); + } else { + $comments = $this->getAllComments(); + if ($commentpage > 0) { + echo '<a class="serendipityIconLink" href="?serendipity[adminModule]=event_display&serendipity[adminAction]=spamblock_bayes&serendipity[subpage]=4&serendipity[commentpage]='. ($commentpage-1) .'"><img src="/templates/default/admin/img/previous.png"/>'.PREVIOUS.'</a>'; + } + if (($commentpage+1)*20 < count($comments) ) { + echo '<a class="serendipityIconLinkRight" href="?serendipity[adminModule]=event_display&serendipity[adminAction]=spamblock_bayes&serendipity[subpage]=4&serendipity[commentpage]='. ($commentpage+1) .'">'.NEXT.'<img src="/templates/default/admin/img/next.png"/></a>'; + } + echo '<form action="'. "{$serendipity['baseURL']}index.php?/plugin/bayesAnalyse" .'" method="post"> + <ul id="bayesAnalysisList" class="plainList">'; + for ($i=$commentpage*20; $i<($commentpage+1)*20;$i++) { + if (! isset($comments[$i])) { + break; + } + $comment = $comments[$i]; + echo '<li><input type="checkbox" id="comments['. $comment['id'] .']" name="comments['. $comment['id'] .']" /><label for="comments['. $comment['id'] .']" >'.$comment['id'].'</label>: <div class="bayesComments">'.htmlspecialchars($comment['name']).', "'.htmlspecialchars($comment['body']).'</div> </li>'; + } + echo '<input type="submit" value="'.GO.'" /> + </ul></form> + <script src="'.$this->path.'jquery.excerpt.js" type="text/javascript"></script> + <script>shortenAll("bayesComments", 1)</script> '; + if ($commentpage > 0) { + echo '<a class="serendipityIconLink" href="?serendipity[adminModule]=event_display&serendipity[adminAction]=spamblock_bayes&serendipity[subpage]=4&serendipity[commentpage]='. ($commentpage-1) .'"><img src="/templates/default/admin/img/previous.png"/>'.PREVIOUS.'</a>'; + } + if (($commentpage+1)*20 < count($comments) ) { + echo '<a class="serendipityIconLinkRight" href="?serendipity[adminModule]=event_display&serendipity[adminAction]=spamblock_bayes&serendipity[subpage]=4&serendipity[commentpage]='. ($commentpage+1) .'">'.NEXT.'<img src="/templates/default/admin/img/next.png"/></a>'; + } + + + } + } + + function showAnalysis($comment_id) { + $comments = $this->getComment($comment_id); + for ($i=0; $i < count($comments); $i++) { + $comment = $comments[$i]; + if (is_array($comment_id)) { + echo '<h3>'. $comment_id[$i] .'</h3>'; + } else { + echo '<h3>'.COMMENT .' #'. $comment_id .'</h3>'; + } + $types = array_keys($this->type); + $ratings = array(); + + foreach($types as $type) { + $rating = $this->classify($comment[$type], $this->type[$type]); + $ratings[$type] = $rating; + } + echo '<ul class="plainList bayesAnalysis">'; + foreach($types as $type) { + echo "<li class=\"ratingBox\"><div class=\"commentType\">$type:</div> + <div class=\"commentPart\">".htmlspecialchars($comment[$type])."</div> + <div class=\"rating\">"; + if (is_numeric($ratings[$type])) { + echo preg_replace('/\..*/', '', $ratings[$type] * 100) .'%'; + } else + echo '-'; + echo "</div></li>"; + } + echo '</ul>'; + echo '<div class="finalRating">'.preg_replace('/\..*/', '', $this->startClassify($comment) * 100) .'%</div>'; + } + echo '<script src="'.$this->path.'jquery.excerpt.js" type="text/javascript"></script> + <script>shortenAll("commentPart", 1) + colorize()</script> '; + } + + # Returns the input of a table as HTML-Table # $table The name of the table # $select Shall a checkbox for selecting a row be shown? @@ -1087,10 +1241,63 @@ return $comments; } + #id: array of ids or a single id + function getRecyclerComment($id) { + global $serendipity; + + if(is_array($id)) { + $sql = "SELECT body, entry_id, author, email, url, ip, referer FROM {$serendipity['dbPrefix']}spamblock_bayes_recycler + WHERE " . serendipity_db_in_sql ( 'id', $id ); + } else { + $sql = "SELECT body, entry_id, author, email, url, ip, referer FROM {$serendipity['dbPrefix']}spamblock_bayes_recycler + WHERE id = " . (int)$id; + } + $comments = serendipity_db_query($sql); + #map to the names used in the eventData, else there would be seperate data + foreach ($comments as &$comment) { + $comment['referrer'] = $comment[$this->type['referrer']]; + $comment['name'] = $comment[$this->type['name']]; + unset($comment[$this->type['referrer']]); + unset($comment[$this->type['name']]); + } + + return $comments; + } + + function getAllComments() { + global $serendipity; + $sql = "SELECT * FROM {$serendipity['dbPrefix']}comments"; + $comments = serendipity_db_query($sql); + foreach ($comments as &$comment) { + $comment['referrer'] = $comment[$this->type['referrer']]; + $comment['name'] = $comment[$this->type['name']]; + unset($comment[$this->type['referrer']]); + unset($comment[$this->type['name']]); + } + return $comments; + } + + function getAllRecyclerComments() { + global $serendipity; + $sql = "SELECT * FROM {$serendipity['dbPrefix']}spamblock_bayes_recycler"; + $comments = serendipity_db_query($sql); + foreach ($comments as &$comment) { + $comment['referrer'] = $comment[$this->type['referrer']]; + $comment['name'] = $comment[$this->type['name']]; + unset($comment[$this->type['referrer']]); + unset($comment[$this->type['name']]); + } + return $comments; + } + function block(&$eventData, &$addData) { global $serendipity; if ($this->get_config('recycler', true)) { - $this->throwInRecycler($eventData, $addData); + $delete = $this->get_config('recyclerdelete', ''); + $rating = preg_replace('/\..*/', '', $this->lastRating * 100); + if (empty($delete) || $rating < $delete) { + $this->throwInRecycler($eventData, $addData); + } } $logfile = $this->logfile = $this->get_config('logfile', $serendipity['serendipityPath'] . 'spamblock.log'); $this->log($logfile, $eventData['id'], 'REJECTED', PLUGIN_EVENT_SPAMBLOCK_BAYES_REASON, $addData); @@ -1112,7 +1319,7 @@ global $serendipity; $sql = "DELETE FROM {$serendipity['dbPrefix']}spamblock_bayes_recycler"; - serendipity_db_query($sql); + return serendipity_db_query($sql); } //Get the blocked comment and store it in the recycler-table @@ -1155,6 +1362,7 @@ function restoreComments($ids) { global $serendipity; + if (is_array($ids)) { $sql = "INSERT INTO {$serendipity['dbPrefix']}comments Index: lang_en.inc.php =================================================================== RCS file: /cvsroot/php-blog/additional_plugins/serendipity_event_spamblock_bayes/lang_en.inc.php,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- lang_en.inc.php 23 May 2010 12:02:37 -0000 1.5 +++ lang_en.inc.php 14 Jun 2010 14:23:51 -0000 1.6 @@ -49,4 +49,7 @@ @define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DESC', 'Shall blocked comments be saved in the recycler?'); @define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_EMPTY', 'Empty Recycler'); @define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RESTORE', 'Restore'); +@define('PLUGIN_EVENT_SPAMBLOCK_BAYES_MENU_ANALYSIS', 'Analyse'); +@define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DELETE', 'Recyler Bypass'); +@define('PLUGIN_EVENT_SPAMBLOCK_BAYES_RECYCLER_DELETE_DESC', 'Comments with a rating equal or higher this value will not be thrown into the recycler, they will be deleted. Example: 98'); ?> Index: ChangeLog =================================================================== RCS file: /cvsroot/php-blog/additional_plugins/serendipity_event_spamblock_bayes/ChangeLog,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- ChangeLog 25 May 2010 20:49:46 -0000 1.7 +++ ChangeLog 14 Jun 2010 14:23:51 -0000 1.8 @@ -1,3 +1,14 @@ +0.3.7: + * Restored wanted order of the recycler-table + * Mitigated the effect of one spamfield if there are other clearly + valid fields in the comment (e.g. commenter's name looks like spam + but everything else is valid) + * Learn restored comments directly as ham + * Added a button to learn comments in the recycler again as spam when + emptying it. + * Added menu for analysing the ratings of a comment, showing the + the rating of each part + 0.3.6.1: * Fixing restore of recyclercontent @@ -11,6 +22,7 @@ * Made the "mark selected as spam"-function more robust * Upgrade: Fixed saving of old counter into the new system * Named treatment "custom" better + 0.3.4: * Added workaround for "empty" pingbacks Index: serendipity_event_spamblock_bayes.js =================================================================== RCS file: /cvsroot/php-blog/additional_plugins/serendipity_event_spamblock_bayes/serendipity_event_spamblock_bayes.js,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- serendipity_event_spamblock_bayes.js 21 Apr 2010 15:29:06 -0000 1.1 +++ serendipity_event_spamblock_bayes.js 14 Jun 2010 14:23:51 -0000 1.2 @@ -11,16 +11,16 @@ sortwithcolor( $(this).parent().children().index( this ) + 1 ); }); -function shortenAll(textclass) { +function shortenAll(textclass, lines) { $.each( $('.'+textclass), function() { - shorten($(this)); + shorten($(this), lines); }); } -function shorten($element) { +function shorten($element, lines) { var o = $element.text(); $r = $('><a href="#" style="padding-left: 5px;">... show</a>'); - $element.excerpt({ lines: 3, end: $r}); + $element.excerpt({ lines: lines, end: $r}); $element.find('a').click(function(e){ e.preventDefault(); var $cell = $(this).parent(); @@ -33,7 +33,25 @@ $link.remove(); shorten($cell); }); - $cell.html(o); + $cell.text(o); $cell.append($link); }); } + +function colorize() { + $ratings = $(".ratingBox").children(".rating"); + $.each($ratings, function() { + var rating = parseInt($(this).text().replace("%","")); + if (rating > 70) { + $(this).parent().css('background', 'rgba(249, 199, 199, 0.5)'); + } else if ( rating > 10) { + $(this).parent().css('background', 'rgba(248, 246, 137, 0.5)'); + } else if (rating >= 0){ + $(this).parent().css('background', 'rgba(202, 248, 199, 0.5)'); + } else { + /*detect those without a rating*/ + $(this).parent().css('background', 'rgba(165, 165, 165, 0.5)'); + } + }); + +} \ No newline at end of file Index: serendipity_event_spamblock_bayes.css =================================================================== RCS file: /cvsroot/php-blog/additional_plugins/serendipity_event_spamblock_bayes/serendipity_event_spamblock_bayes.css,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- serendipity_event_spamblock_bayes.css 21 Apr 2010 15:29:06 -0000 1.1 +++ serendipity_event_spamblock_bayes.css 14 Jun 2010 14:23:51 -0000 1.2 @@ -97,4 +97,35 @@ } #bayesRecyclerTable td.select { text-align: center; +} +.ratingBox { + border-bottom: 1px solid grey; +} +.commentPart { + margin-left: 5em; +} +.rating { + margin-left: 5em; + font-weight: bold; +} +.commentType { + font-weight: bold; +} +.finalRating { + padding-left: 3.3em; + font-weight: bold; + font-size: 1.5em; + border-bottom: 1px solid grey; +} +#bayesAnalysisList li { + margin: 1em; +} +label { + cursor: pointer; +} +.serendipityIconLinkRight { + float: right; +} +#bayesControls label { + display: block; } \ No newline at end of file Index: bayes_commentlist.js =================================================================== RCS file: /cvsroot/php-blog/additional_plugins/serendipity_event_spamblock_bayes/bayes_commentlist.js,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- bayes_commentlist.js 23 May 2010 12:02:37 -0000 1.3 +++ bayes_commentlist.js 14 Jun 2010 14:23:51 -0000 1.4 @@ -86,7 +86,6 @@ function deleteComment(ids) { if (httpRequest.readyState == 4 && httpRequest.status == 200) { - getAllRatings(); if (! (ids.constructor == Array)) { //without the use of id, the new ids would be undefined var id = ids; @@ -104,6 +103,7 @@ remove(comment) remove(message); remove(divider); + getAllRatings(); } } } @@ -181,7 +181,9 @@ if (ratingLocation == null) { ratingLocation = document.getElementById('comment_'+id); } - ratingLocation.appendChild(textElement); + if (ratingLocation != null) { + ratingLocation.appendChild(textElement); + } } } |