From: <re...@us...> - 2007-09-21 09:53:54
|
Revision: 563 http://sciret.svn.sourceforge.net/sciret/?rev=563&view=rev Author: reinerj Date: 2007-09-21 02:53:52 -0700 (Fri, 21 Sep 2007) Log Message: ----------- update the trunk to stable Modified Paths: -------------- trunk/CHANGELOG trunk/CONTRIBUTORS trunk/TODO trunk/VERSION trunk/actions/DeleteArticle.php trunk/actions/EditUser.php trunk/actions/Install.php trunk/actions/Login.php trunk/actions/MailArticle.php trunk/actions/SaveArticle.php trunk/actions/SaveCategory.php trunk/actions/SavePreferences.php trunk/actions/Upgrade.php trunk/classes/Controller.php trunk/fckeditor/editor/_source/classes/fckcontextmenu.js trunk/fckeditor/editor/_source/classes/fckdataprocessor.js trunk/fckeditor/editor/_source/classes/fckdomrange.js trunk/fckeditor/editor/_source/classes/fckdomrange_gecko.js trunk/fckeditor/editor/_source/classes/fckdomrange_ie.js trunk/fckeditor/editor/_source/classes/fckeditingarea.js trunk/fckeditor/editor/_source/classes/fckenterkey.js trunk/fckeditor/editor/_source/classes/fckevents.js trunk/fckeditor/editor/_source/classes/fckicon.js trunk/fckeditor/editor/_source/classes/fckiecleanup.js trunk/fckeditor/editor/_source/classes/fckkeystrokehandler.js trunk/fckeditor/editor/_source/classes/fckpanel.js trunk/fckeditor/editor/_source/classes/fckspecialcombo.js trunk/fckeditor/editor/_source/classes/fcktoolbarbutton.js trunk/fckeditor/editor/_source/classes/fcktoolbarfontformatcombo.js trunk/fckeditor/editor/_source/classes/fcktoolbarstylecombo.js trunk/fckeditor/editor/_source/commandclasses/fck_othercommands.js trunk/fckeditor/editor/_source/commandclasses/fckfitwindow.js trunk/fckeditor/editor/_source/commandclasses/fcktablecommand.js trunk/fckeditor/editor/_source/fckeditorapi.js trunk/fckeditor/editor/_source/fckscriptloader.js trunk/fckeditor/editor/_source/internals/fck.js trunk/fckeditor/editor/_source/internals/fck_contextmenu.js trunk/fckeditor/editor/_source/internals/fck_gecko.js trunk/fckeditor/editor/_source/internals/fck_ie.js trunk/fckeditor/editor/_source/internals/fckcommands.js trunk/fckeditor/editor/_source/internals/fckconfig.js trunk/fckeditor/editor/_source/internals/fckdocumentprocessor.js trunk/fckeditor/editor/_source/internals/fckdomtools.js trunk/fckeditor/editor/_source/internals/fcklanguagemanager.js trunk/fckeditor/editor/_source/internals/fcklistslib.js trunk/fckeditor/editor/_source/internals/fckselection.js trunk/fckeditor/editor/_source/internals/fckselection_gecko.js trunk/fckeditor/editor/_source/internals/fckselection_ie.js trunk/fckeditor/editor/_source/internals/fcktablehandler.js trunk/fckeditor/editor/_source/internals/fcktoolbarset.js trunk/fckeditor/editor/_source/internals/fcktools.js trunk/fckeditor/editor/_source/internals/fcktools_gecko.js trunk/fckeditor/editor/_source/internals/fcktools_ie.js trunk/fckeditor/editor/_source/internals/fckxhtml.js trunk/fckeditor/editor/_source/internals/fckxhtml_ie.js trunk/fckeditor/editor/_source/internals/fckxhtmlentities.js trunk/fckeditor/editor/dialog/fck_flash/fck_flash.js trunk/fckeditor/editor/dialog/fck_image/fck_image.js trunk/fckeditor/editor/dialog/fck_link/fck_link.js trunk/fckeditor/editor/dialog/fck_paste.html trunk/fckeditor/editor/dialog/fck_replace.html trunk/fckeditor/editor/dialog/fck_smiley.html trunk/fckeditor/editor/dialog/fck_specialchar.html trunk/fckeditor/editor/dialog/fck_spellerpages/spellerpages/server-scripts/spellchecker.cfm trunk/fckeditor/editor/dialog/fck_tablecell.html trunk/fckeditor/editor/fckdialog.html trunk/fckeditor/editor/fckeditor.html trunk/fckeditor/editor/filemanager/browser/default/browser.css trunk/fckeditor/editor/filemanager/browser/default/browser.html trunk/fckeditor/editor/filemanager/browser/default/frmfolders.html trunk/fckeditor/editor/filemanager/browser/default/frmresourceslist.html trunk/fckeditor/editor/filemanager/browser/default/frmupload.html trunk/fckeditor/editor/lang/_translationstatus.txt trunk/fckeditor/editor/lang/cs.js trunk/fckeditor/editor/lang/en-au.js trunk/fckeditor/editor/lang/en-ca.js trunk/fckeditor/editor/lang/en-uk.js trunk/fckeditor/editor/lang/en.js trunk/fckeditor/editor/lang/fi.js trunk/fckeditor/editor/lang/he.js trunk/fckeditor/editor/lang/zh-cn.js trunk/fckeditor/editor/lang/zh.js trunk/fckeditor/editor/plugins/tablecommands/fckplugin.js trunk/fckeditor/editor/skins/default/fck_dialog.css trunk/fckeditor/editor/skins/default/fck_strip.gif trunk/fckeditor/editor/skins/office2003/fck_dialog.css trunk/fckeditor/editor/skins/office2003/fck_strip.gif trunk/fckeditor/editor/skins/silver/fck_dialog.css trunk/fckeditor/editor/skins/silver/fck_strip.gif trunk/fckeditor/fckconfig.js trunk/fckeditor/fckeditor.js trunk/fckeditor/fckpackager.xml trunk/flowMap.php trunk/javascript/general.js trunk/languages/ChineseTraditional.txt trunk/languages/Czech.txt trunk/languages/Deutsch.txt trunk/languages/Dutch.txt trunk/languages/English.txt trunk/languages/Hebrew.txt trunk/languages/Italian.txt trunk/languages/Japanese.txt trunk/languages/Norsk.txt trunk/languages/Russian.txt trunk/languages/Spanish.txt trunk/languages/Svenska.txt trunk/models/Article.php trunk/models/ArticleGateway.php trunk/models/ArticleIterator.php trunk/models/Configuration.php trunk/models/Question.php trunk/models/User.php trunk/models/UserGateway.php trunk/setup/final.sql trunk/setup/sampleData.sql trunk/setup/versions.php trunk/templates/EditArticle.tpl trunk/templates/EditBookmark.tpl trunk/templates/EditCategories.tpl trunk/templates/EditCategory.tpl trunk/templates/EditPreferences.tpl trunk/templates/EditUser.tpl trunk/templates/MainView.tpl trunk/templates/RelatedArticles.tpl trunk/templates/ViewArticle.tpl trunk/templates/head.tpl trunk/templates/header.tpl trunk/views/EditArticle.php trunk/views/EditCategories.php trunk/views/EditPreferences.php trunk/views/EditUser.php trunk/views/InstallEnterCredentials.php trunk/views/MainView.php trunk/views/View.php trunk/views/ViewArticle.php trunk/views/ViewBookmark.php Modified: trunk/CHANGELOG =================================================================== --- trunk/CHANGELOG 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/CHANGELOG 2007-09-21 09:53:52 UTC (rev 563) @@ -1,20 +1,124 @@ -2007-08-24 Lucie Goga <lg...@th...> - * Add Italian translation from two students +2007-09-21 Lucie Goga <lg...@th...> + * Sciret 1.2.0 release -2007-07-18 Lucie Goga <lg...@th...> - * Sciret 1.1.0 - * extention Send mail as UTF-8, patch reported from Rune Hammersland +2007-09-03 Lucie Goga <lg...@th...> + * Sciret 1.2.0-RC1 + * Sciret language packs 1.2.0 +2007-09-05 Alejandro Pedraza <ale...@gm...> + * [BUG] Fix in the upgrade fuction + getValidatedUser() needs the config array to need what version we're on + +2007-09-03 Lucie Goga <lg...@th...> + * update language file Russian, Spanish, Svenska. + * update Roadmap + +2007-09-02 Lucie Goga <lg...@th...> + * update language file Hebrew, Japanese, Italian, Norsk, Russian, Spanish. + The file are sorted and extended. + +2007-08-24 Lucie Goga <lg...@th...> + * Add Italian translation from two students + * update language file Chinesetraditional, Czech, Dutch. + The file are sorted and extended. + +2007-08-22 Lucie Goga <lg...@th...> + * Add SF patch 1778378 from Trond Viggo Håpnes. This patch + Restrict the possibility to modify and delete articles. + * update German lang file + +2007-08-22 Alejandro Pedraza <ale...@gm...> + * [BUG] Fix SF bug 1778175 Bookmark save as draft + * [BUG] Fix SF bug 1772632 Expiration Date in Bookmarks + +2007-08-20 Lucie Goga <lg...@th...> + * Update the English and German lang file. + +2007-08-19 Lucie Goga <lg...@th...> + * Update the English and German lang file. + +2007-08-19 Alejandro Pedraza <ale...@gm...> + * New feature: download pdf for article + * New feature: repeat password field to avoid typos + * SQL Error + +2007-08-18 Alejandro Pedraza <ale...@gm...> + * FCKEditor: Make the config a little smarter by figuring out itself + where the upload dir must go + * Added explanatory message to error list + * Killed ConfigNotWritable view. Show missing requirements in the view + where the db credentials are shown. Also have additional + checks: for db version and check if upload dirs are writable. + +2007-08-16 Reiner Jung <rj...@th...> + * Update the English and German lang file. Files are sorted now and + duplicates are removed + +2007-08-16 Lucie Goga <lg...@th...> + * release 1.2.0-svn-r487 + * Add SF patch 1775353 from Trond Viggo Håpnes. This patch + allows / disallow coments and ratings. + +2007-08-16 Alejandro Pedraza <ale...@gm...> + * Allow users can manage the categories and hide them with the + Manage categories. + +2007-08-15 Lucie Goga <lg...@th...> + * [BUG] Add SF patch 1772600 from Trond Viggo Håpnes. This patch + allows the admin to remove the icon from a (sub)category. + +2007-08-13 Alejandro Pedraza <ale...@gm...> + * Show original question for articles that answer a question. + When an article was made to answer a question, show the + question text between the title and the article excerpt in + the list view, and between the title and the category in + the article detail view. Also, when an article that answers + a question is shown on the list view, use a question mark + as an icon, instead of the sheet icon currently used. + * update db structure + +2007-08-10 Reiner Jung <rj...@th...> + * Add SF patch 1765899 from Trond Viggo Håpnes. This patch removes + the mail-link from ViewArticle if the article is marked + for internal use only + * Fixed a typing error in EditArticle.tpl + +2007-08-04 Alejandro Pedraza <ale...@gm...> + * Let registered users edit their own profile. + * Added functionality to expire passwords and oblige users to + change them when that happens + * Be able to decide whether the KB is public or not + (set by the admin, in the preferences section) + +2007-08-02 Reiner Jung <rj...@th...> + * Add SF patch 1771482 from Trond Viggo Håpnes. This patch will + let the administrator decide if new articles should be marked + for internal or public use. Only the administrator can change + status on an article from internal to public. You can not email + an article marked for internal use only. + +2007-07-28 Reiner Jung <rj...@th...> + * Update the setup scripts for Sciret 1.2.0 + * Add SF patch 1762272 from Rune Hammersland. This patch enables + the admin to choose between sending e-mails through sendmail or + through an SMTP server of his choosing. The admin can also + choose the name and address used when sending e-mails. + * Update language files for SMTP settings + * Update Norsk translation + +2007-07-23 Reiner Jung <rj...@th...> + * Add XCache to the Sciret documentation. OpenBSD howto is still + missing with xcache + +2007-07-18 Lucie Goga <lg...@th...> + * Sciret 1.1.0 release + 2007-07-15 Alejandro Pedraza <ale...@gm...> * [BUG] Fix problem to send mail from Sciret 2007-07-12 Lucie Goga <lg...@th...> * Add Norwegian translation from Rune Hammersland -2007-07-10 Reiner Jung <rj...@th...> - * [BUG] Fix a problem that saving a draft article didn't appear - in the unpublished and drafts list - 2007-06-29 Reiner Jung <rj...@th...> * update scriptulus to last version Modified: trunk/CONTRIBUTORS =================================================================== --- trunk/CONTRIBUTORS 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/CONTRIBUTORS 2007-09-21 09:53:52 UTC (rev 563) @@ -1,9 +1,10 @@ Contributors to Sciret development - Patch contribution * Nikolai Essel submitted patches to sciret 0.9 and 1.1 + * Rune Hammersland submitted patches to sciret 1.1 and 1.2 + * Trond Viggo Håpnes submitted patches to sciret 1.2 Translations @@ -11,7 +12,7 @@ * Dutch translation R. de Milde * Hebrew translation from SF user Golanor * Japanese translation from SF user tm800720 - * Norwegian translation from Rune Hammersland + * Norway translation from Rune Hammersland * Swedish translation from Henrik Christensson Testing Modified: trunk/TODO =================================================================== --- trunk/TODO 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/TODO 2007-09-21 09:53:52 UTC (rev 563) @@ -1,30 +1,27 @@ -1.2 Release -- When edit a category and select a icon, the icon should be visible as a preview and not after it is selected -- Password protected access to Sciret that only signed in users have access. Should be a configuration option (SF request 1704597) -- A Question should be visible also in the categories where the question is assigned so long as it is answered. It must be marked - that it is clear visible this is a question -- Automatic password reset for users (SF request 1704597) -- Preferences for a user based view of the screen -- Pre Installation check for Sciret (Check the right file system rights ...) - 1.3 Release -- New User Interface for Sciret based on the work from Nuno Pinheiro +- Introduce group support. Admin can restrict access to User based work groups +- Search for articles by registerd users +- Make an article appear in more than one category +- Add tags and tag search to article, bookmarks and documents +- Admin must change the default password after first login 1.4 Release -- Document Management Functionality -- Add tags and tag search to article, bookmarks and documents +- New User Interface for Sciret based on the work from Nuno Pinheiro - Ubuntu/Debian Packages +- Cancel Editing +- Send mail as PDF 1.5 Release -- Introduce group support. Groups from admin for restricrted access and User based work groups -- Create PDF from Article +- Document Management Functionality +- A category will be only visible when there is a article or bookmark in. Otherwise it will be hidden - Authentication again LDAP - Authentication again AD 1.6 Release - One Time Passwords - Authentication with Secure Token -- Search for articles by registered users +- Category Content [Feature RQID 1776663] +- What links here [Feature RQ ID 1776661] 1.7 Release - Sciret will use PHPUnit testing. This will delay our further releases, but will give it more stability Modified: trunk/VERSION =================================================================== --- trunk/VERSION 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/VERSION 2007-09-21 09:53:52 UTC (rev 563) @@ -1 +1 @@ -1.1.0-SVN-Release-428 +1.2.0-SVN-Release-554 Modified: trunk/actions/DeleteArticle.php =================================================================== --- trunk/actions/DeleteArticle.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/DeleteArticle.php 2007-09-21 09:53:52 UTC (rev 563) @@ -17,6 +17,15 @@ function dispatch() { $artId = isset($_GET['id'])? (int)$_GET['id'] : 0; + if ($this->configuration->getConfigValue('restrictEditDelete')) { + $article = new Article($artId); + + if ($article->getUserId() != $this->user->getId() && ($this->user->getRole() & ROLE_ADMIN) != ROLE_ADMIN) { + $_SESSION['message'] = $this->user->lang('Sorry, only the author or an admin can delete this article.'); + Library::redirect(Library::getLink(array('view' => 'ViewArticle', 'id' => $artId))); + } + } + $articleGateway = new ArticleGateway; $articleGateway->delete($artId); Modified: trunk/actions/EditUser.php =================================================================== --- trunk/actions/EditUser.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/EditUser.php 2007-09-21 09:53:52 UTC (rev 563) @@ -15,6 +15,13 @@ class EditUser extends Action { function dispatch() { + + // security check + if (!$this->user->isAdmin() && $this->user->getId() != $_POST['userId']) { + $_SESSION['message'] = $this->user->lang('What are you trying to do??'); + Library::redirect(Library::getLink(array('view' => 'Login'))); + } + $userId = (int)$_POST['userId']; $user = new User($userId); @@ -36,18 +43,21 @@ $missingFieldsArr[] = $this->user->lang('password'); } - if (!$user->setPassword($_POST['password'])) { + $invalidPassword = false; + if ($_POST['password'] != $_POST['password2']) { + $_SESSION['message'] = $this->user->lang('Password and Repeat Password fields don\'t match'); + $invalidPassword = true; + } + elseif (!$user->setPassword($_POST['password'])) { $_SESSION['message'] = $this->user->lang('Invalid password. Please don\'t use any of these characters: %s', implode($user->getDisallowedPasswordChars())); $invalidPassword = true; - } else { - $invalidPassword = false; } if ($missingFieldsArr) { $_SESSION['message'] = $this->user->lang('You need to fill the following fields: ').implode(', ', $missingFieldsArr); } - if ($missingFields || $invalidPassword) { + if ($missingFieldsArr || $invalidPassword) { $_SESSION['formFields'] = array( 'firstName' => $_POST['firstName'], 'lastName' => $_POST['lastName'], @@ -60,19 +70,30 @@ } } else { - if ($_POST['password'] != '') { - if (!$user->changePassword($_POST['password'])) { - $_SESSION['message'] = $this->user->lang('Invalid password. Please don\'t use any of these characters: %s', implode(', ', $user->getDisallowedPasswordChars())); + + if ( + $user->isPasswordExpired($this->configuration->getConfigValue('passwordExpirationDays')) + && $user->getPassword() == md5($_POST['password']) + ) + { + $_SESSION['message'] = $this->user->lang('Your password has expired. Please change it below.'); Library::redirect(Library::getLink(array('view' => 'EditUser', 'userId' => $user->getId()))); - } } + + if ($_POST['password'] != $_POST['password2']) { + $_SESSION['message'] = $this->user->lang('Password and Repeat Password fields don\'t match'); + Library::redirect(Library::getLink(array('view' => 'EditUser', 'userId' => $user->getId()))); + } elseif (!$user->changePassword($_POST['password'])) { + $_SESSION['message'] = $this->user->lang('Invalid password. Please don\'t use any of these characters: %s', implode(', ', $user->getDisallowedPasswordChars())); + Library::redirect(Library::getLink(array('view' => 'EditUser', 'userId' => $user->getId()))); + } } $user->setFirstName($_POST['firstName']); $user->setLastName($_POST['lastName']); $user->setUserName($_POST['userName']); $user->setEmail($_POST['email']); - $user->setAdmin(isset($_POST['adminAccess'])); + $user->setAdmin($this->user->isAdmin() && isset($_POST['adminAccess'])); $user->save(); if (!$user->getId()) { @@ -80,7 +101,12 @@ } else { $_SESSION['message'] = $this->user->lang('User edited successfully'); } - Library::redirect(Library::getLink(array('view' => 'ManageUsers'))); + + if ($this->user->isAdmin()) { + Library::redirect(Library::getLink(array('view' => 'ManageUsers'))); + } else { + Library::redirect(Library::getLink(array('view' => 'EditUser', 'userId' => $user->getId()))); + } } } Modified: trunk/actions/Install.php =================================================================== --- trunk/actions/Install.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/Install.php 2007-09-21 09:53:52 UTC (rev 563) @@ -17,13 +17,6 @@ function dispatch() { - // is_writable() not working under windows - if (!$fp = @fopen(dirname(__FILE__).'/../config.php', 'a')) { - Library::redirect(Library::getLink(array('view' => 'ConfigNotWritable'))); - } else { - fclose($fp); - } - if (!isset($_GET['step'])) { $_GET['step'] = 0; } @@ -35,17 +28,35 @@ case 1: $this->db =& DB::DBFactory(DB_ENGINE, $_POST['host'], $_POST['username'], $_POST['password'], true); if (!$this->db->connect()) { - Library::redirect(Library::getLink(array('view' => 'InstallEnterCredentials', 'error' => urlencode($this->user->lang('Couldn\'t connect to database'))))); + Library::redirect(Library::getLink(array('view' => 'InstallEnterCredentials', 'error' => urlencode($this->user->lang('Couldn\'t connect to database, please check your credentials.'))))); } + + $errors = array(); + if (!$this->_isConfigWritable()) { + $errors[] = $this->user->lang('The config.php file must be writable'); + } + if (!$this->_areUploadDirsWritable()) { + $errors[] = $this->user->lang('All directories under the "uploads" and "uploads/editor" directories must be writable'); + } + if ($this->db->isLowerThan41()) { + $errors[] = $this->user->lang('You need a MySQL version no lower than 4.1'); + } + if (!$this->db->selectDb($_POST['database'])) { if (!$result = $this->db->createDB($_POST['database'])) { - Library::redirect(Library::getLink(array('view' => 'InstallEnterCredentials', 'error' => urlencode($this->user->lang('Couldn\'t create database. Please create it manually and try again.'))))); + $errors[] = $this->user->lang('Couldn\'t create database. Please create it manually and try again.'); + } else { + $this->db->selectDb($_POST['database']); } - $this->db->selectDb($_POST['database']); } + + if ($errors) { + Library::redirect(Library::getLink(array('view' => 'InstallEnterCredentials', 'error' => urlencode(implode('<br />', $errors))))); + } + $this->_writeConfig(DB_ENGINE, $_POST['host'], $_POST['database'], $_POST['username'], $_POST['password']); $this->_runSQLFILE('final.sql'); - if (isset($_POST['demodata'])) { + if (isset($_POST['demodata']) && $_POST['demodata']) { $this->_runSQLFILE('sampleData.sql'); } Library::redirect(Library::getLink(array('view' => 'InstallOk'))); @@ -101,6 +112,31 @@ } fclose($fp); } + + function _isConfigWritable() { + // is_writable() not working under windows + if (!$fp = @fopen(dirname(__FILE__).'/../config.php', 'a')) { + return false; + } + fclose($fp); + + return true; + } + + function _areUploadDirsWritable() { + foreach (array('files', 'icons', 'editor/File', 'editor/Flash', 'editor/Image', 'editor/Media') as $folder) { + // is_writable() not working under windows + if (!$fp = @fopen(dirname(__FILE__)."/../uploads/$folder/eraseme.txt", 'a')) { + return false; + } else { + fclose($fp); + unlink(dirname(__FILE__)."/../uploads/$folder/eraseme.txt"); + } + + } + + return true; + } } ?> Modified: trunk/actions/Login.php =================================================================== --- trunk/actions/Login.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/Login.php 2007-09-21 09:53:52 UTC (rev 563) @@ -16,12 +16,18 @@ function dispatch() { require 'models/UserGateway.php'; $userGateway = new UserGateway; - if (!$user = $userGateway->getValidatedUser($_POST['username'], $_POST['password'])) { + if (!$user = $userGateway->getValidatedUser($_POST['username'], $_POST['password'], $this->configuration)) { $_SESSION['message'] = $this->user->lang('Wrong Username or Password'); Library::redirect(Library::getLink(array('view' => 'Login'))); } $_SESSION['userId'] = $user->getId(); + + if ($user->isPasswordExpired($this->configuration->getConfigValue('passwordExpirationDays'))) { + $_SESSION['message'] = $this->user->lang('Your password has expired. Please change it below.'); + Library::redirect(Library::getLink(array('view' => 'EditUser', 'userId' => $user->getId()))); + } + Library::redirect(Library::getLink(array('view' => 'MainView'))); } } Modified: trunk/actions/MailArticle.php =================================================================== --- trunk/actions/MailArticle.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/MailArticle.php 2007-09-21 09:53:52 UTC (rev 563) @@ -23,7 +23,10 @@ if (!$article->getId()) { die($this->user->lang('Invalid article ID')); } - + if ($article->isInternal()) { + $_SESSION['message'] = $this->user->lang('Sorry, this article is for internal use only.'); + Library::redirect(Library::getLink(array('view' => 'ViewArticle', 'id' => $articleId))); + } if ($_POST['recipient'] == '' || !preg_match($this->regexp_valid_email, $_POST['recipient'])) { $_SESSION['message'] = $this->user->lang('Invalid recipient'); Library::redirect(Library::getLink(array('view' => 'MailArticle', 'artId' => $articleId))); @@ -33,9 +36,8 @@ Library::redirect(Library::getLink(array('view' => 'MailArticle', 'artId' => $articleId))); } - $mail = new PHPMailer(); - $mail->IsSendmail(); - $mail->CharSet = "utf-8"; + $mail = $this->setUpMailer(); + if ($_POST['replyTo'] != '') { $mail->AddReplyTo($_POST['replyTo']); } @@ -58,6 +60,30 @@ $_SESSION['message'] = $this->user->lang('E-mail has been successfuly sent'); Library::redirect(Library::getLink(array('view' => 'ViewArticle', 'id' => $articleId))); } + + function setUpMailer() { + $mail = new PHPMailer(); + + $config = $this->configuration; + $transport = $config->getConfigValue('mailTransport'); + + if ($transport == 'smtp') { + $mail->IsSMTP(); + $mail->Host = $config->getConfigValue('smtpServer'); + $mail->Username = $config->getConfigValue('smtpUser'); + $mail->Password = $config->getConfigValue('smtpPassword'); + $mail->Port = $config->getConfigValue('smtpPort'); + } else if ($transport == 'sendmail') { + $mail->IsSendmail(); + } + + $mail->CharSet = "utf-8"; + $mail->FromName = $config->getConfigValue('mailFromName'); + $mail->From = $config->getConfigValue('mailFromMail'); + + return $mail; + } + } ?> Modified: trunk/actions/SaveArticle.php =================================================================== --- trunk/actions/SaveArticle.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/SaveArticle.php 2007-09-21 09:53:52 UTC (rev 563) @@ -17,6 +17,15 @@ function dispatch() { $articleId = isset($_POST['articleId'])? (int)$_POST['articleId'] : 0; + if ($articleId > 0 && $this->configuration->getConfigValue('restrictEditDelete')) { + $article = new Article($articleId); + + if ($article->getUserId() != $this->user->getId() && ($this->user->getRole() & ROLE_ADMIN) != ROLE_ADMIN) { + $_SESSION['message'] = $this->user->lang('Sorry, only the author or an admin can modify this article.'); + Library::redirect(Library::getLink(array('view' => 'ViewArticle', 'id' => $articleId))); + } + } + // validation if ($_POST['title'] == '') { $_SESSION['message'] = $this->user->lang('Article can\'t be saved without a title.'); @@ -28,6 +37,12 @@ $art->setTitle($_POST['title']); $art->setContent($_POST['content']); + if (!isset($_POST['usage_id'])) { + $art->setInternal($this->configuration->getConfigValue('internalByDefault')? 1 : 0); + } else { + $art->setInternal($_POST['usage_id']); + } + if ($_POST['expDate'] == '') { $art->setExpDate('0000-00-00'); } else { @@ -39,14 +54,15 @@ $art->setModifiedByUserId($this->user->getId()); $historyMessage = $this->user->lang('Article modified'); } else { - $art->setPublished(($this->configuration->getConfigValue('publishArticlesAuto') == '1' && $_POST['draft'] != 1)? true : false); + $art->setPublished($this->configuration->getConfigValue('publishArticlesAuto') == '1'? true : false); $art->setUserId($this->user->getId()); $historyMessage = $this->user->lang('Article created'); if (isset($_POST['questionID'])) { - require 'models/QuestionGateway.php'; - $questionGateway = new QuestionGateway; - $questionGateway->delete($_POST['questionID']); + require 'models/Question.php'; + $question = new Question($_POST['questionID']); + $art->setQuestion($question->getContents()); + $question->delete(); } } $art->setDraft($_POST['draft']); Modified: trunk/actions/SaveCategory.php =================================================================== --- trunk/actions/SaveCategory.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/SaveCategory.php 2007-09-21 09:53:52 UTC (rev 563) @@ -26,9 +26,7 @@ $category->setParentId($_POST['parentCategory']); $category->setLabel($_POST['name']); $category->setDescription($_POST['description']); - if ($_POST['icon'] != 'blank.gif') { - $category->setIconFileName($_POST['icon']); - } + $category->setIconFileName($_POST['icon']); $category->save(); $_SESSION['message'] = $this->user->lang('Category saved successfully'); Modified: trunk/actions/SavePreferences.php =================================================================== --- trunk/actions/SavePreferences.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/SavePreferences.php 2007-09-21 09:53:52 UTC (rev 563) @@ -33,10 +33,22 @@ } if (($this->user->getRole() & ROLE_ADMIN) == ROLE_ADMIN) { + $this->configuration->setConfigValue('publishKB', $_POST['publishKB'] == '1'? '1' : '0'); $this->configuration->setConfigValue('publishArticlesAuto', $_POST['publishArticlesAuto'] == '1'? '1' : '0'); $this->configuration->setConfigValue('publishBookmarksAuto', $_POST['publishBookmarksAuto'] == '1'? '1' : '0'); $this->configuration->setConfigValue('publishCommentsAuto', $_POST['publishCommentsAuto'] == '1'? '1' : '0'); $this->configuration->setConfigValue('publishQuestionsAuto', $_POST['publishQuestionsAuto'] == '1'? '1' : '0'); + $this->configuration->setConfigValue('internalByDefault', $_POST['internalByDefault'] == '1'? '1' : '0'); + $this->configuration->setConfigValue('allowCommentsRatings', $_POST['allowCommentsRatings'] == '1'? '1' : '0'); + $this->configuration->setConfigValue('restrictEditDelete', $_POST['restrictEditDelete'] == '1'? '1' : '0'); + $this->configuration->setConfigValue('passwordExpirationDays', $_POST['passwordExpirationDays']); + $this->configuration->setConfigValue('mailTransport', $_POST['mailTransport'] == 'smtp' ? 'smtp' : 'sendmail'); + $this->configuration->setConfigValue('mailFromName', $_POST['mailFromName']); + $this->configuration->setConfigValue('mailFromMail', $_POST['mailFromMail']); + $this->configuration->setConfigValue('smtpServer', $_POST['smtpServer']); + $this->configuration->setConfigValue('smtpUser', $_POST['smtpUser']); + $this->configuration->setConfigValue('smtpPassword', $_POST['smtpPassword']); + $this->configuration->setConfigValue('smtpPort', $_POST['smtpPort']); $this->configuration->save(); } Modified: trunk/actions/Upgrade.php =================================================================== --- trunk/actions/Upgrade.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/actions/Upgrade.php 2007-09-21 09:53:52 UTC (rev 563) @@ -17,7 +17,7 @@ function dispatch() { require 'models/UserGateway.php'; $this->userGateway = new UserGateway; - if (!($user = $this->userGateway->getValidatedUser($_POST['username'], $_POST['password'])) || !$user->isAdmin()) { + if (!($user = $this->userGateway->getValidatedUser($_POST['username'], $_POST['password'], $this->configuration)) || !$user->isAdmin()) { $_SESSION['message'] = $this->user->lang('Wrong Username or Password'); Library::redirect(Library::getLink(array('view' => 'Upgrade'))); } Modified: trunk/classes/Controller.php =================================================================== --- trunk/classes/Controller.php 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/classes/Controller.php 2007-09-21 09:53:52 UTC (rev 563) @@ -12,6 +12,8 @@ define('MINIMUM_ROLE', 0); define('LOAD_CONFIGURATION', 1); define('SHOW_HEADER', 2); +define('ALLOW_VIEW_ONLY_IF_PUBLIC_KB', 3); +define('ALLOW_ACTION_ONLY_IF_PUBLIC_KB', 2); require 'models/Configuration.php'; @@ -52,7 +54,14 @@ $this->user->setSkipTranslations(true); } - if (($this->user->getRole() & $this->views[$view][MINIMUM_ROLE]) != $this->views[$view][MINIMUM_ROLE]) { + if ( + // user hasn't got enough privileges + (($this->user->getRole() & $this->views[$view][MINIMUM_ROLE]) != $this->views[$view][MINIMUM_ROLE]) + + // or user is anonymous and KB is not public + || ($this->user->getRole() == ROLE_ANONYMOUS && $this->views[$view][ALLOW_VIEW_ONLY_IF_PUBLIC_KB] && !$this->configuration->getConfigValue('publishKB')) + ) + { Library::redirect(Library::getLink(array('view' => 'Login'))); } require "views/$view.php"; Modified: trunk/fckeditor/editor/_source/classes/fckcontextmenu.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckcontextmenu.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckcontextmenu.js 2007-09-21 09:53:52 UTC (rev 563) @@ -94,9 +94,11 @@ FCKTools.CancelEvent( e ) ; FCKContextMenu_AttachedElement_OnContextMenu( e, el._FCKContextMenu, el ) ; + return false ; } el = el.parentNode ; } + return true ; } function FCKContextMenu_AttachedElement_OnContextMenu( ev, fckContextMenu, el ) @@ -140,4 +142,4 @@ { contextMenu._Panel.Hide() ; FCKTools.RunFunction( contextMenu.OnItemClick, contextMenu, menuItem ) ; -} \ No newline at end of file +} Modified: trunk/fckeditor/editor/_source/classes/fckdataprocessor.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckdataprocessor.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckdataprocessor.js 2007-09-21 09:53:52 UTC (rev 563) @@ -79,16 +79,8 @@ if ( FCKBrowserInfo.IsIE && FCKConfig.DocType.length > 0 && !FCKRegexLib.Html4DocType.test( FCKConfig.DocType ) ) html += ' style="overflow-y: scroll"' ; - html += '><head><title></title></head><body' ; - - // Add id and class to the body. - if ( FCKConfig.BodyId.length > 0 ) - html += ' id="' + FCKConfig.BodyId + '"' ; - if ( FCKConfig.BodyClass.length > 0 ) - html += ' class="' + FCKConfig.BodyClass + '"' ; - - html += - '>' + + html += '><head><title></title></head>' + + '<body' + FCKConfig.GetBodyAttributes() + '>' + data + '</body></html>' ; Modified: trunk/fckeditor/editor/_source/classes/fckdomrange.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckdomrange.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckdomrange.js 2007-09-21 09:53:52 UTC (rev 563) @@ -276,6 +276,71 @@ this._UpdateElementInfo() ; }, + // Non-intrusive bookmark algorithm + CreateBookmark2 : function() + { + // If there is no range then get out of here. + // It happens on initial load in Safari #962 and if the editor it's hidden also in Firefox + if ( ! this._Range ) + return { "Start" : 0, "End" : 0 } ; + + // First, we record down the offset values + var bookmark = + { + "Start" : [ this._Range.startOffset ], + "End" : [ this._Range.endOffset ] + } ; + // Then, we record down the precise position of the container nodes + // by walking up the DOM tree and counting their childNode index + var curNode = this._Range.startContainer ; + while ( curNode && curNode != this.Window.document.documentElement ) + { + var curParent = curNode.parentNode ; + for( var i = 0 ; i < curParent.childNodes.length ; i++ ) + { + if ( curParent.childNodes.item( i ) == curNode ) + { + bookmark.Start.unshift( i ) ; + break ; + } + } + curNode = curParent; + } + curNode = this._Range.endContainer; + while ( curNode && curNode != this.Window.document.documentElement ) + { + var curParent = curNode.parentNode; + for ( var i = 0 ; i < curParent.childNodes.length ; i++ ) + { + if ( curParent.childNodes.item( i ) == curNode ) + { + bookmark.End.unshift( i ); + break; + } + } + curNode = curParent; + } + return bookmark; + }, + + MoveToBookmark2 : function( bookmark ) + { + // Reverse the childNode counting algorithm in CreateBookmark2() + var curStart = this.Window.document.documentElement ; + var curEnd = this.Window.document.documentElement ; + for ( var i = 0 ; i < bookmark.Start.length - 1 ; i++ ) + curStart = curStart.childNodes.item( bookmark.Start[ i ] ) ; + for ( var i = 0 ; i < bookmark.End.length - 1 ; i++ ) + curEnd = curEnd.childNodes.item( bookmark.End[ i ] ) ; + + // Generate the W3C Range object and update relevant data + this.Release( true ) ; + this._Range = new FCKW3CRange( this.Window.document ) ; + this._Range.setStart( curStart, bookmark.Start[ bookmark.Start.length - 1 ] ) ; + this._Range.setEnd( curEnd, bookmark.End[ bookmark.End.length - 1 ] ) ; + this._UpdateElementInfo() ; + }, + MoveToPosition : function( targetElement, position ) { this.SetStart( targetElement, position ) ; @@ -570,4 +635,20 @@ this.EndBlockLimit = null ; this._Range = null ; } -} ; \ No newline at end of file +} ; + +FCKDomRange.CompareCursors = function( cursor1, cursor2 ) +{ + for ( var i = 0 ; i < Math.min( cursor1.length, cursor2.length ) ; i++ ) + { + if ( cursor1[i] < cursor2[i] ) + return -1; + else if (cursor1[i] > cursor2[i] ) + return 1; + } + if ( cursor1.length < cursor2.length ) + return -1; + else if (cursor1.length > cursor2.length ) + return 1; + return 0; +} Modified: trunk/fckeditor/editor/_source/classes/fckdomrange_gecko.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckdomrange_gecko.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckdomrange_gecko.js 2007-09-21 09:53:52 UTC (rev 563) @@ -29,7 +29,7 @@ var oSel = this.Window.getSelection() ; - if ( oSel.rangeCount == 1 ) + if ( oSel && oSel.rangeCount > 0 ) { this._Range = FCKW3CRange.CreateFromRange( this.Window.document, oSel.getRangeAt(0) ) ; this._UpdateElementInfo() ; Modified: trunk/fckeditor/editor/_source/classes/fckdomrange_ie.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckdomrange_ie.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckdomrange_ie.js 2007-09-21 09:53:52 UTC (rev 563) @@ -33,15 +33,24 @@ if ( oSel.type != 'Control' ) { + var eMarkerStart = this._GetSelectionMarkerTag( true ) ; + var eMarkerEnd = this._GetSelectionMarkerTag( false ) ; + + if ( ! ( eMarkerStart && eMarkerEnd ) ) + { + this._Range.setStart( this.Window.document.body, 0 ); + this._Range.collapse( true ); + this._UpdateElementInfo(); + return; + } + // Set the start boundary. - eMarker = this._GetSelectionMarkerTag( true ) ; - this._Range.setStart( eMarker.parentNode, FCKDomTools.GetIndexOf( eMarker ) ) ; - eMarker.parentNode.removeChild( eMarker ) ; + this._Range.setStart( eMarkerStart.parentNode, FCKDomTools.GetIndexOf( eMarkerStart ) ) ; + eMarkerStart.parentNode.removeChild( eMarkerStart ) ; // Set the end boundary. - var eMarker = this._GetSelectionMarkerTag( false ) ; - this._Range.setEnd( eMarker.parentNode, FCKDomTools.GetIndexOf( eMarker ) ) ; - eMarker.parentNode.removeChild( eMarker ) ; + this._Range.setEnd( eMarkerEnd.parentNode, FCKDomTools.GetIndexOf( eMarkerEnd ) ) ; + eMarkerEnd.parentNode.removeChild( eMarkerEnd ) ; this._UpdateElementInfo() ; } @@ -122,6 +131,12 @@ var oRange = this.Window.document.selection.createRange() ; oRange.collapse( toStart === true ) ; + // IE might take the range object to the main window instead of inside the editor iframe window. + // This is known to happen when the editor window has not been selected before (See #933). + // We need to avoid that. + if (oRange.parentElement().document != this.Window.document) + return null; + // Paste a marker element at the collapsed range and get it from the DOM. var sMarkerId = 'fck_dom_range_temp_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000) ; oRange.pasteHTML( '<span id="' + sMarkerId + '"></span>' ) ; @@ -146,4 +161,4 @@ oRange.insertNode( eSpan ) ; return eSpan ; -} \ No newline at end of file +} Modified: trunk/fckeditor/editor/_source/classes/fckeditingarea.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckeditingarea.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckeditingarea.js 2007-09-21 09:53:52 UTC (rev 563) @@ -52,7 +52,12 @@ { // Create the editing area IFRAME. var oIFrame = this.IFrame = oTargetDocument.createElement( 'iframe' ) ; - oIFrame.src = 'javascript:void(0)' ; + + // Firefox will render the tables inside the body in Quirks mode if the + // source of the iframe is set to javascript. see #515 + if ( !FCKBrowserInfo.IsGecko ) + oIFrame.src = 'javascript:void(0)' ; + oIFrame.frameBorder = 0 ; oIFrame.width = oIFrame.height = '100%' ; @@ -130,6 +135,8 @@ eTextarea.dir = 'ltr' ; eTextarea.style.width = eTextarea.style.height = '100%' ; eTextarea.style.border = 'none' ; + // CSS3 http://www.w3.org/TR/css3-ui/#resize + eTextarea.style.resize = 'none' ; eTargetElement.appendChild( eTextarea ) ; eTextarea.value = html ; @@ -162,7 +169,13 @@ if ( FCKBrowserInfo.IsIE ) { + oDoc.body.unselectable = "on" ; oDoc.body.contentEditable = true ; + var enableFunc = function() + { + oDoc.body.removeAttribute("unselectable") ; + } + setTimeout( enableFunc, 1 ) ; /* The following commands don't throw errors, but have no effect. oDoc.execCommand( 'AutoDetect', false, false ) ; @@ -208,10 +221,42 @@ // Disable the standard table editing features of Firefox. oDoc.execCommand( 'enableInlineTableEditing', false, !FCKConfig.DisableFFTableHandles ) ; } - catch (e) {} + catch (e) + { + // In Firefox if the iframe is initially hidden it can't be set to designMode and it raises an exception + // So we set up a DOM Mutation event Listener on the HTML, as it will raise several events when the document is visible again + FCKTools.AddEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ; + } + } } +// This function processes the notifications of the DOM Mutation event on the document +// We use it to know that the document will be ready to be editable again (or we hope so) +function FCKEditingArea_Document_AttributeNodeModified( evt ) +{ + var editingArea = evt.currentTarget.contentWindow._FCKEditingArea ; + + // We want to run our function after the events no longer fire, so we can know that it's a stable situation + if ( editingArea._timer ) + window.clearTimeout( editingArea._timer ) ; + + editingArea._timer = FCKTools.SetTimeout( FCKEditingArea_MakeEditableByMutation, 1000, editingArea ) ; +} + +// This function ideally should be called after the document is visible, it does clean up of the +// mutation tracking and tries again to make the area editable. +function FCKEditingArea_MakeEditableByMutation() +{ + // Clean up + delete this._timer ; + // Now we don't want to keep on getting this event + FCKTools.RemoveEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ; + // Let's try now to set the editing area editable + // If it fails it will set up the Mutation Listener again automatically + this.MakeEditable() ; +} + FCKEditingArea.prototype.Focus = function() { try @@ -221,13 +266,21 @@ // The following check is important to avoid IE entering in a focus loop. Ref: // http://sourceforge.net/tracker/index.php?func=detail&aid=1567060&group_id=75348&atid=543653 if ( FCKBrowserInfo.IsIE && this.Document.hasFocus() ) + { + // In IE it can happen that the document is in theory focused but the active element is outside it + this.Document.body.setActive() ; return ; + } if ( FCKBrowserInfo.IsSafari ) this.IFrame.focus() ; else { this.Window.focus() ; + + // In IE it can happen that the document is in theory focused but the active element is outside it + if ( FCKBrowserInfo.IsIE ) + this.Document.body.setActive() ; } } else Modified: trunk/fckeditor/editor/_source/classes/fckenterkey.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckenterkey.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckenterkey.js 2007-09-21 09:53:52 UTC (rev 563) @@ -29,7 +29,7 @@ * @shiftEnterMode : the behavior for the <Shift>+<Enter> keystroke. * May be "p", "div", "br". Defaults to "br". */ -var FCKEnterKey = function( targetWindow, enterMode, shiftEnterMode ) +var FCKEnterKey = function( targetWindow, enterMode, shiftEnterMode, tabSpaces ) { this.Window = targetWindow ; this.EnterMode = enterMode || 'p' ; @@ -43,10 +43,18 @@ oKeystrokeHandler.SetKeystrokes( [ [ 13 , 'Enter' ], [ SHIFT + 13, 'ShiftEnter' ], + [ 9 , 'Tab' ], [ 8 , 'Backspace' ], [ 46 , 'Delete' ] ] ) ; + if ( tabSpaces > 0 ) + { + this.TabText = '' ; + while ( tabSpaces-- > 0 ) + this.TabText += '\xa0' ; + } + oKeystrokeHandler.AttachToElement( targetWindow.document ) ; } @@ -76,6 +84,9 @@ case 'Delete' : return oEnterKey.DoDelete() ; + break ; + case 'Tab' : + return oEnterKey.DoTab() ; } /* @Packager.RemoveLine } @@ -94,6 +105,9 @@ */ FCKEnterKey.prototype.DoEnter = function( mode, hasShift ) { + // Save an undo snapshot before doing anything + FCKUndo.SaveUndoStep() ; + this._HasShift = ( hasShift === true ) ; var sMode = mode || this.EnterMode ; @@ -124,7 +138,22 @@ oRange.MoveToSelection() ; if ( !oRange.CheckIsCollapsed() ) + { + // Bug #327, Backspace with an img selection would activate the default action in IE. + // Let's override that with our logic here. + if ( FCKBrowserInfo.IsIE && this.Window.document.selection.type.toLowerCase() == "control" ) + { + var controls = this.Window.document.selection.createRange() ; + for ( var i = controls.length - 1 ; i >= 0 ; i-- ) + { + var el = controls.item( i ) ; + el.parentNode.removeChild( el ) ; + } + return true ; + } + return false ; + } var oStartBlock = oRange.StartBlock ; var oEndBlock = oRange.EndBlock ; @@ -256,6 +285,10 @@ */ FCKEnterKey.prototype.DoDelete = function() { + // Save an undo snapshot before doing anything + // This is to conform with the behavior seen in MS Word + FCKUndo.SaveUndoStep() ; + // The <Delete> has the same effect as the <Backspace>, so we have the same // results if we just move to the next block and apply the same <Backspace> logic. @@ -279,6 +312,40 @@ return bCustom ; } +/* + * Executes the <Tab> key behavior. + */ +FCKEnterKey.prototype.DoTab = function() +{ + var oRange = new FCKDomRange( this.Window ); + oRange.MoveToSelection() ; + + // If the user pressed <tab> inside a table, we should give him the default behavior ( moving between cells ) + // instead of giving him more non-breaking spaces. (Bug #973) + var node = oRange._Range.startContainer ; + while ( node ) + { + if ( node.nodeType == 1 ) + { + var tagName = node.tagName.toLowerCase() ; + if ( tagName == "tr" || tagName == "td" || tagName == "th" || tagName == "tbody" || tagName == "table" ) + return false ; + else + break ; + } + node = node.parentNode ; + } + + if ( this.TabText ) + { + oRange.DeleteContents() ; + oRange.InsertNode( this.Window.document.createTextNode( this.TabText ) ) ; + oRange.Collapse( false ) ; + oRange.Select() ; + } + return true ; +} + FCKEnterKey.prototype._ExecuteEnterBlock = function( blockTag, range ) { // Get the current selection. @@ -338,7 +405,10 @@ else eNewBlock = this.Window.document.createElement( blockTag ) ; - if ( FCKBrowserInfo.IsGeckoLike ) + // Opera needs some text (even empty) to correctly position the caret (#214). + if ( FCKBrowserInfo.IsOpera ) + eNewBlock.appendChild( this.Window.document.createTextNode( '' ) ) ; + else if ( FCKBrowserInfo.IsGeckoLike ) eNewBlock.innerHTML = GECKO_BOGUS ; oRange.InsertNode( eNewBlock ) ; @@ -354,7 +424,7 @@ oRange.MoveToElementEditStart( bIsStartOfBlock ? eNextBlock : eNewBlock ) ; - if ( FCKBrowserInfo.IsGecko ) + if ( FCKBrowserInfo.IsGeckoLike ) eNewBlock.scrollIntoView( false ) ; } @@ -415,7 +485,7 @@ FCKDomTools.InsertAfterNode( eBr, this.Window.document.createTextNode( '' ) ) ; // If we are at the end of a block, we must be sure the bogus node is available in that block. - if ( bIsEndOfBlock && FCKBrowserInfo.IsGecko ) + if ( bIsEndOfBlock && FCKBrowserInfo.IsGeckoLike ) FCKTools.AppendBogusBr( eBr.parentNode ) ; if ( FCKBrowserInfo.IsIE ) @@ -456,4 +526,4 @@ range.MoveToBookmark( oBookmark ) ; range.Select() ; -} \ No newline at end of file +} Modified: trunk/fckeditor/editor/_source/classes/fckevents.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckevents.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckevents.js 2007-09-21 09:53:52 UTC (rev 563) @@ -46,7 +46,20 @@ if ( oCalls ) { for ( var i = 0 ; i < oCalls.length ; i++ ) - bReturnValue = ( oCalls[ i ]( this.Owner, params ) && bReturnValue ) ; + { + try + { + bReturnValue = ( oCalls[ i ]( this.Owner, params ) && bReturnValue ) ; + } + catch(e) + { + // Ignore the following error. It may happen if pointing to a + // script not anymore available (#934): + // -2146823277 = Can't execute code from a freed script + if ( e.number != -2146823277 ) + throw e ; + } + } } return bReturnValue ; Modified: trunk/fckeditor/editor/_source/classes/fckicon.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckicon.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckicon.js 2007-09-21 09:53:52 UTC (rev 563) @@ -74,7 +74,7 @@ eIcon = document.createElement( 'IMG' ) ; eIcon.src = FCK_SPACER_PATH ; eIcon.style.backgroundPosition = '0px ' + sPos ; - eIcon.style.backgroundImage = 'url(' + this.Path + ')' ; + eIcon.style.backgroundImage = 'url("' + this.Path + '")' ; } } else // It is using a single icon image. Modified: trunk/fckeditor/editor/_source/classes/fckiecleanup.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckiecleanup.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckiecleanup.js 2007-09-21 09:53:52 UTC (rev 563) @@ -43,7 +43,7 @@ function FCKIECleanup_Cleanup() { - if ( !this._FCKCleanupObj ) + if ( !this._FCKCleanupObj || !window.FCKUnloadFlag ) return ; var aItems = this._FCKCleanupObj.Items ; @@ -65,4 +65,4 @@ if ( CollectGarbage ) CollectGarbage() ; -} \ No newline at end of file +} Modified: trunk/fckeditor/editor/_source/classes/fckkeystrokehandler.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckkeystrokehandler.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckkeystrokehandler.js 2007-09-21 09:53:52 UTC (rev 563) @@ -133,4 +133,4 @@ } return true ; -} \ No newline at end of file +} Modified: trunk/fckeditor/editor/_source/classes/fckpanel.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckpanel.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckpanel.js 2007-09-21 09:53:52 UTC (rev 563) @@ -52,7 +52,21 @@ oIFrame.width = oIFrame.height = 0 ; if ( this._Window == window.parent && window.frameElement ) + { + var scrollPos = null ; + if ( FCKBrowserInfo.IsGecko && FCK && FCK.EditorDocument ) + scrollPos = [ FCK.EditorDocument.body.scrollLeft, FCK.EditorDocument.body.scrollTop ] ; window.frameElement.parentNode.insertBefore( oIFrame, window.frameElement ) ; + if ( scrollPos ) + { + var restoreFunc = function() + { + FCK.EditorDocument.body.scrollLeft = scrollPos[0] ; + FCK.EditorDocument.body.scrollTop = scrollPos[1] ; + } + setTimeout( restoreFunc, 500 ) ; + } + } else this._Window.document.body.appendChild( oIFrame ) ; @@ -60,9 +74,14 @@ oDocument = this.Document = oIFrameWindow.document ; + // Workaround for Safari 12256. Ticket #63 + var sBase = '' ; + if ( FCKBrowserInfo.IsSafari ) + sBase = '<base href="' + window.document.location + '">' ; + // Initialize the IFRAME document body. oDocument.open() ; - oDocument.write( '<html><head></head><body style="margin:0px;padding:0px;"><\/body><\/html>' ) ; + oDocument.write( '<html><head>' + sBase + '<\/head><body style="margin:0px;padding:0px;"><\/body><\/html>' ) ; oDocument.close() ; FCKTools.AddEventListenerEx( oIFrameWindow, 'focus', FCKPanel_Window_OnFocus, this ) ; @@ -156,7 +175,10 @@ // setting the _IFrame size (which returns "0"), and then after that, // to return the correct width. Remove the first step and it will not // work when the editor is in RTL. - iMainWidth = this.MainNode.offsetWidth ; + // + // The "|| this.MainNode.firstChild.offsetWidth" part has been added + // for Opera compatibility (see #570). + iMainWidth = this.MainNode.offsetWidth || this.MainNode.firstChild.offsetWidth ; var oPos = FCKTools.GetElementPosition( relElement.nodeType == 9 ? @@ -302,4 +324,4 @@ this._Window = null ; this.Document = null ; this.MainNode = null ; -} \ No newline at end of file +} Modified: trunk/fckeditor/editor/_source/classes/fckspecialcombo.js =================================================================== --- trunk/fckeditor/editor/_source/classes/fckspecialcombo.js 2007-09-21 09:35:20 UTC (rev 562) +++ trunk/fckeditor/editor/_source/classes/fckspecialcombo.js 2007-09-21 09:53:52 UTC (rev 563) @@ -1,363 +1,364 @@ -/* - * FCKeditor - The text editor for Internet - http://www.fckeditor.net - * Copyright (C) 2003-2007 Frederico Caldeira Knabben - * - * == BEGIN LICENSE == - * - * Licensed under the terms of any of the following licenses at your - * choice: - * - * - GNU General Public License Version 2 or later (the "GPL") - * http://www.gnu.org/licenses/gpl.html - * - * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") - * http://www.gnu.org/licenses/lgpl.html - * - * - Mozilla Public License Version 1.1 or later (the "MPL") - * http://www.mozilla.org/MPL/MPL-1.1.html - * - * == END LICENSE == - * - * FCKSpecialCombo Class: represents a special combo. - */ - -var FCKSpecialCombo = function( caption, fieldWidth, panelWidth, panelMaxHeight, parentWindow ) -{ - // Default properties values. - this.FieldWidth = fieldWidth || 100 ; - this.PanelWidth = panelWidth || 150 ; - this.PanelMaxHeight = panelMaxHeight || 150 ; - this.Label = ' ' ; - this.Caption = caption ; - this.Tooltip = caption ; - this.Style = FCK_TOOLBARITEM_ICONTEXT ; - - this.Enabled = true ; - - this.Items = new Object() ; - - this._Panel = new FCKPanel( parentWindow || window ) ; - this._Panel.AppendStyleSheet( FCKConfig.SkinPath + 'fck_editor.css' ) ; - this._PanelBox = this._Panel.MainNode.appendChild( this._Panel.Document.createElement( 'DIV' ) ) ; - this._PanelBox.className = 'SC_Panel' ; - this._PanelBox.style.width = this.PanelWidth + 'px' ; - - this._PanelBox.innerHTML = '<table cellpadding="0" cellspacing="0" width="100%" style="TABLE-LAYOUT: fixed"><tr><td nowrap></td></tr></table>' ; - - this._ItemsHolderEl = this._PanelBox.getElementsByTagName('TD')[0] ; - - if ( FCK.IECleanup ) - FCK.IECleanup.AddItem( this, FCKSpecialCombo_Cleanup ) ; - -// this._Panel.StyleSheet = FCKConfig.SkinPath + 'fck_contextmenu.css' ; -// this._Panel.Create() ; -// this._Panel.PanelDiv.className += ' SC_Panel' ; -// this._Panel.PanelDiv.innerHTML = '<table cellpadding="0" cellspacing="0" width="100%" style="TABLE-LAYOUT: fixed"><tr><td nowrap></td></tr></table>' ; -// this._ItemsHolderEl = this._Panel.PanelDiv.getElementsByTagName('TD')[0] ; -} - -function FCKSpecialCombo_ItemOnMouseOver() -{ - this.className += ' SC_ItemOver' ; -} - -function FCKSpecialCombo_ItemOnMouseOut() -{ - this.className = this.originalClass ; -} - -function FCKSpecialCombo_ItemOnClick() -{ - this.className = this.originalClass ; - - this.FCKSpecialCombo._Panel.Hide() ; - - this.FCKSpecialCombo.SetLabel( this.FCKItemLabel ) ; - - if ( typeof( this.FCKSpecialCombo.OnSelect ) == 'function' ) - this.FCKSpecialCombo.OnSelect( this.FCKItemID, this ) ; -} - -FCKSpecialCombo.prototype.AddItem = function( id, html, label, bgColor ) -{ - // <div class="SC_Item" onmouseover="this.className='SC_Item SC_ItemOver';" onmouseout="this.className='SC_Item';"><b>Bold 1</b></div> - var oDiv = this._ItemsHolderEl.appendChild( this._Panel.Document.createElement( 'DIV' ) ) ; - oDiv.className = oDiv.originalClass = 'SC_Item' ; - oDiv.innerHTML = html ; - oDiv.FCKItemID = id ; - oDiv.FCKItemLabel = la... [truncated message content] |