Opened 18 years ago
Closed 17 years ago
#1410 closed New Feature (fixed)
Category Management within FCKeditor
| Reported by: | David Barker | Owned by: | Deimon |
|---|---|---|---|
| Priority: | Normal | Milestone: | |
| Component: | Project : MediaWiki+FCKeditor | Version: | |
| Keywords: | Confirmed HasPatch | Cc: |
Description
I like fckeditor for Mediawiki a lot. What I would find useful (and so might others) is some sort of Category Manager. By this I simply mean the ability to assign/create a category for the current document from the menu. It would access the database and create a dropdown (or pop-up, doesn't matter which) which would allow the user to select (or create new) a category for the current document.
Thanks for the amazing hard work that went into the creation of fckeditor. I was afraid I was going to have to create something like it myself, and that would be way beyond me.
David Barker
Attachments (1)
Change History (13)
comment:1 Changed 18 years ago by
comment:2 Changed 18 years ago by
I admit that having a checkbox like "search in categories" would be more user friendly.
comment:3 Changed 18 years ago by
| Keywords: | Confirmed added |
|---|
comment:4 Changed 17 years ago by
The linking functionality works, but I find it confusing, even as someone who develops MediaWiki extensions.
I think the main problem is that there is no way to distinguish a 'normal' link from a categorization link.
A secondary problem is that there is simply a 'floating' category link at the bottom of the page. Most new users would probably assume the link was not supposed to be there, and simply delete it.
I propose the following solution:
- Add a 'category' placeholder icon, like the placeholders used for templates and special tags. Use this to represent categories in the editor, rather than simply showing a link. Category links have very different behavior from standard links, and their representation should convey this.
- The link tool will ALWAYS insert the leading ':' for categories and images. This ensures that a link always creates a link, and eliminates the need to educate users to use a colon.
- Add a 'Add to category' button, which inserts the [[Category:Foo]] Wiki text. This will be represented in the editor by the category placeholder.
I might be willing to take a stab at implementing this... but does it seem like a valuable feature to have?
comment:5 Changed 17 years ago by
| Owner: | set to Deimon |
|---|---|
| Status: | new → assigned |
I have created such functionality.
Add this functions in extensions\FCKeditor\FCKeditorSajax.body.php
function wfSajaxSearchCategoryFCKeditor()
{
global $wgContLang, $wgOut;
$ns = NS_CATEGORY;
$m_sql="SELECT tmpSelectCat1.cl_to AS title
FROM wiki_categorylinks AS tmpSelectCat1
LEFT JOIN wiki_page AS tmpSelectCatPage ON ( tmpSelectCat1.cl_to = tmpSelectCatPage.page_title
AND tmpSelectCatPage.page_namespace =14 )
LEFT JOIN wiki_categorylinks AS tmpSelectCat2 ON tmpSelectCatPage.page_id = tmpSelectCat2.cl_from
WHERE tmpSelectCat2.cl_from IS NULL
GROUP BY tmpSelectCat1.cl_to";
$db =& wfGetDB( DB_SLAVE );
$res = $db->query($m_sql,__METHOD__ );
$ret = "";
$i=0;
while ( ( $row = $db->fetchObject( $res ) ) ) {
$ret .= $row->title ."\n";
//$ret.=wfSajaxSearchCategoryChildrenFCKeditor($row->title);
$sub = explode("\n",wfSajaxSearchCategoryChildrenFCKeditor($row->title));
foreach($sub as $subrow)if(strlen($subrow)>0)$ret.=" ".$subrow."\n";
}
return $ret;
}
function wfSajaxSearchCategoryChildrenFCKeditor($m_root)
{
global $wgContLang, $wgOut;
$limit = 50;
$ns = NS_CATEGORY;
$m_root = str_replace("'","\'",$m_root);
$m_sql = " SELECT tmpSelectCatPage.page_title AS title
FROM wiki_categorylinks AS tmpSelectCat
LEFT JOIN wiki_page AS tmpSelectCatPage ON tmpSelectCat.cl_from = tmpSelectCatPage.page_id
WHERE tmpSelectCat.cl_to LIKE '$m_root' AND tmpSelectCatPage.page_namespace = 14";
$db =& wfGetDB( DB_SLAVE );
$res = $db->query($m_sql,__METHOD__ );
$ret = "";
$i=0;
while ( ( $row = $db->fetchObject( $res ) ) ) {
$ret .= $row->title ."\n";
//$ret.=wfSajaxSearchCategoryChildrenFCKeditor($row->title);
$sub = explode("\n",wfSajaxSearchCategoryChildrenFCKeditor($row->title));
foreach($sub as $subrow)if(strlen($subrow)>0)$ret.=" ".$subrow."\n";
}
return $ret;
}
Add this in file extensions\FCKeditor\FCKeditor.php
$wgAjaxExportList[] = 'wfSajaxSearchCategoryFCKeditor';
Create file extensions\FCKeditor\plugins\mediawiki\dialogs\category.html as this
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!--
* Link dialog window.
-->
<html>
<head>
<title>Link Properties</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="robots" content="noindex, nofollow" />
<script type="text/javascript">
var oEditor = window.parent.InnerDialogLoaded() ;
var FCK = oEditor.FCK ;
var FCKLang = oEditor.FCKLang ;
var FCKConfig = oEditor.FCKConfig ;
var FCKRegexLib = oEditor.FCKRegexLib ;
var FCKTools = oEditor.FCKTools ;
var FCKBrowserInfo = oEditor.FCKBrowserInfo ;
var EditorDocument = oEditor.FCK.EditorDocument ;
document.write( '<script src="' + FCKConfig.BasePath + 'dialog/common/fck_dialog_common.js" type="text/javascript"><\/script>' ) ;
</script>
<script type="text/javascript">
// oLink: The actual selected link in the editor.
window.onload = function()
{
// Translate the dialog box texts.
oEditor.FCKLanguageManager.TranslatePage(document) ;
// Load the selected link information (if any).
InitSelected() ;
SetSearchMessage( 'loading categories...' ) ;
oEditor.window.parent.sajax_request_type = 'GET' ;
oEditor.window.parent.sajax_do_call( 'wfSajaxSearchCategoryFCKeditor', [], InitCategoryTree ) ;
// Activate the "OK" button.
window.parent.SetOkButton( true ) ;
window.parent.SetAutoSize( true ) ;
}
var selectedCats;
function InitSelected()
{
selectedCats=new Array();
var node=EditorDocument;
while(node){
if(node.nodeType==1 && node.tagName.toLowerCase() == 'a'){
// Get the actual Link href.
var sHRef = node.getAttribute( '_fcksavedurl' ) ;
if ( sHRef == null )sHRef = node.getAttribute( 'href' , 2 ) || '' ;
if(sHRef.StartsWith('Category:')){
var select = GetE('xCategories' ) ;
var cat=sHRef.slice(9);
SelectCategory(cat,-1);
}
}
node=FCKTools.GetNextNode(node,EditorDocument);
}
// Make an Ajax search for the pages.
}
function SelectCategory(cat,catTreeRow)
{
var row=parseInt(catTreeRow);
if(row>=0){
var select = GetE('xWikiResults' );
cat=select.options[row].text;
var lvl=0;
while(cat.charAt(lvl)==placeholder)lvl++;
cat=cat.slice(lvl);
if(cat.charAt(0)=='[' && cat.charAt(cat.length-1)==']')cat=cat.substring(1,cat.length-1);
}
if(selectedCats[cat])delete selectedCats[cat];
else selectedCats[cat]=cat;
var select = GetE( 'xCategories' ) ;
while (select.options.length > 0 )select.remove( 0 );
for(var cat in selectedCats) FCKTools.AddSelectOption( select, cat, cat) ;
}
var catTree;
function InitCategoryTree( result )
{
SetSearchMessage( '' ) ;
catTree=new Object();
var levelsHead=new Array('root');
var levelsBody=new Array('');
var results = result.responseText.Trim().split( '\n' ) ;
var previousLvl=-1;
for ( var i = 0 ; i < results.length ; i++ ){
var lvl=0;
while(results[i].charAt(lvl)==' ')lvl++;
var t=results[i].slice(lvl);
for(var j=previousLvl;j>lvl-1;j--){
if(levelsBody[j+1]!='')catTree[levelsHead[j+1]]=levelsBody[j+1];
delete levelsHead[j+1];
delete levelsBody[j+1];
}
if(lvl>previousLvl)levelsBody[lvl]=t;
else levelsBody[lvl]=levelsBody[lvl]+' '+t;
levelsHead[lvl+1]=t;
levelsBody[lvl+1]='';
previousLvl=lvl;
}
for(var j=previousLvl;j>=-1;j--){
if(levelsBody[j+1]!='')catTree[levelsHead[j+1]]=levelsBody[j+1];
delete levelsHead[j+1];
delete levelsBody[j+1];
}
ShowCategoriesSubTree(-1);
}
var placeholder='.';
//draw category subtree
function ShowCategoriesSubTree(rowInTree){
var row=parseInt(rowInTree);
var select = GetE('xWikiResults' ) ;
var root='root';
var lvl=-1;
var prefix='';
if(row>=0){
root=select.options[row].text;
lvl=0;
while(root.charAt(lvl)==placeholder)lvl++;
root=root.slice(lvl);
if(root.charAt(0)=='[' && root.charAt(root.length-1)==']')
root=root.substring(1,root.length-1);
prefix=new Array(lvl+1+3).join(placeholder);
}
if(!catTree[root])return;
var itCount=select.options.length;
var itSkip=row+1;
var opts=new Array();
for(var i=row+1;i<itCount;i++){
var t=select.options[i].text;
var sublvl=0;
while(t.charAt(sublvl)==placeholder)sublvl++;
if(sublvl>lvl)itSkip=i+1;
else break;
}
for(var i=itCount-1;i>row;i--){
var t=select.options[i].text;
//if(t==fullroot)break;
if(i>=itSkip)opts.push(t);
select.remove(i);
}
//while ( select.options.length > 0 )
// select.remove( 0 )
if(itSkip==row+1){
var cats = catTree[root].split(' ') ;
for(var k in cats){
var p=cats[k];
if(catTree[cats[k]])p='['+p+']';
var e=FCKTools.AddSelectOption( select, prefix+p, ++row) ;
if(catTree[cats[k]])e.style.color='#00f';
}
}
for(var i=opts.length-1;i>=0;i--){
var e=FCKTools.AddSelectOption( select, opts[i], ++row) ;
if(opts[i].indexOf('[')>=0)e.style.color='#00f';
}
}
//draw filtered
function ShowFilteredCategories(filter){
var select = GetE('xWikiResults' ) ;
while (select.options.length > 0 )select.remove( 0 );
//alert(filter);
var found=new Object();
if(filter.length==0){
ShowCategoriesSubTree(-1);
return;
}
filter=filter.toLowerCase();
var row=-1;
for(var folder in catTree){
var cats = catTree[folder].split(' ') ;
for(var k in cats){
var p=cats[k].toLowerCase();
if(p.indexOf(filter)>=0){
if(found[cats[k]]);
else{
found[cats[k]]=cats[k];
FCKTools.AddSelectOption( select, cats[k], ++row ) ;
}
}
}
}
}
function AddNew(){
var select = GetE('txtUrl' );
SelectCategory(select.value,-1)
}
//#### The OK button was hit.
function Ok()
{
var nodes=new Array();
var node=EditorDocument;
var nodeNext;
var s='';
var i=0;
while(node){
nodeNext=FCKTools.GetNextNode(node,EditorDocument);
if(node.nodeType==1 && node.tagName.toLowerCase() == 'a'){
// Get the actual Link href.
var sHRef = node.getAttribute( '_fcksavedurl' ) ;
if ( sHRef == null )sHRef = node.getAttribute( 'href' , 2 ) || '' ;
if(sHRef.StartsWith('Category:'))nodes[i++]=node;
}
node=nodeNext;
}
for(var i=0;i<nodes.length;i++)nodes[i].parentNode.removeChild(nodes[i]);
for(var cat in selectedCats)AddCategoryLink(cat);
return true;
}
function AddCategoryLink(cat){
var sUri = 'Category:'+cat;
var sInnerHtml ;
// If no link is selected, create a new one (it may result in more than one link creation - #220).
var aLinks = oEditor.FCK.CreateLink( sUri ) ;
// If no selection, no links are created, so use the uri as the link text (by dom, 2006-05-26)
var aHasSelection = ( aLinks.length > 0 ) ;
if ( !aHasSelection )
{
sInnerHtml = sUri;
var oLinkPathRegEx = new RegExp("//?([^?\"']+)([?].*)?$") ;
var asLinkPath = oLinkPathRegEx.exec( sUri ) ;
if (asLinkPath != null)
sInnerHtml = asLinkPath[1]; // use matched path
// Create a new (empty) anchor.
aLinks = [ oEditor.FCK.InsertElement( 'a' ) ] ;
}
oEditor.FCKUndo.SaveUndoStep() ;
for ( var i = 0 ; i < aLinks.length ; i++ )
{
oLink = aLinks[i] ;
if ( aHasSelection )
sInnerHtml = oLink.innerHTML ; // Save the innerHTML (IE changes it if it is like an URL).
oLink.href = sUri ;
SetAttribute( oLink, '_fcksavedurl', sUri ) ;
oLink.innerHTML = sInnerHtml ; // Set (or restore) the innerHTML
}
// Select the (first) link.
//oEditor.FCKSelection.SelectNode( aLinks[0] );
return true ;
}
//////////////////////
var searchTimer ;
//#### Called while the user types the URL.
function OnUrlChange()
{
var link =GetE('txtUrl').value.Trim();
ShowFilteredCategories(link);
return;
if ( searchTimer )
window.clearTimeout( searchTimer ) ;
if ( link.StartsWith( '#' ) )
{
SetSearchMessage( 'anchor link... no search for it' ) ;
return ;
}
if ( link.StartsWith( 'mailto:' ) )
{
SetSearchMessage( 'e-mail link... no search for it' ) ;
return ;
}
if( /^\w+:\/\//.test( link ) )
{
SetSearchMessage( 'external link... no search for it' ) ;
return ;
}
/*if ( link.length < 3 )
{
ClearSearch() ;
if ( link.length == 0 )
SetSearchMessage( 'start typing in the above field' ) ;
else
SetSearchMessage( 'too short... type more' ) ;
return ;
}
*/
SetSearchMessage( 'stop typing to search' ) ;
//searchTimer = window.setTimeout( StartSearch, 500 ) ;
}
function SetSearchMessage( message )
{
GetE('xWikiSearchStatus').innerHTML = message ;
}
</script>
</head>
<body scroll="no" style="overflow: hidden">
<div id="divInfo">
<div id="divLinkTypeUrl">
<span>Selected categories</span><br />
<select id="xCategories" size="10" style="width: 100%; height:70px" ondblclick="SelectCategory( this.value,-1);">
</select><br />
Search category<br />
<input id="txtUrl" style="width: 80%" type="text" onkeyup="OnUrlChange();" />
<input id="btnNew" style="width: 18%" type="button" onclick="AddNew();" value="Add new"/>
<br />
Category tree (<span id="xWikiSearchStatus">start typing in the above field</span>)<br />
<select id="xWikiResults" size="10" style="width: 100%; height:300px" onclick="ShowCategoriesSubTree( this.value );" ondblclick="SelectCategory('', this.value );">
</select>
</div>
</div>
</body>
</html>
Also you need to enable this new command. One way to do it is to add
tbButton = new FCKToolbarButton( 'Category', 'Categories', 'Insert/Edit categories' ) ; tbButton.IconPath = FCKConfig.PluginsPath + 'mediawiki/images/tb_icon_category.gif' ; FCKToolbarItems.RegisterItem( 'Category', tbButton ) ;
after
tbButton = new FCKToolbarButton( 'MW_Special', 'Special Tag', 'Insert/Edit Special Tag' ) ; tbButton.IconPath = FCKConfig.PluginsPath + 'mediawiki/images/tb_icon_special.gif' ; FCKToolbarItems.RegisterItem( 'MW_Special', tbButton ) ;
and add
FCKCommands.RegisterCommand( 'Category', new FCKDialogCommand( 'Category', 'Категории', FCKConfig.PluginsPath + 'mediawiki/dialogs/category.html', 400, 500 ) ) ;
after
FCKCommands.RegisterCommand( 'Link', new FCKDialogCommand( 'Link', FCKLang.DlgLnkWindowTitle, FCKConfig.PluginsPath + 'mediawiki/dialogs/link.html', 400, 250 ) ) ;
in extensions\FCKeditor\plugins\mediawiki\fckplugin.js
Also you need to create tb_icon_special.gif.
I'm new here. It's my first patch. Please correct the code above if it is not fit to coding standarts.
comment:8 Changed 17 years ago by
| Summary: | Category Management within FCKeditor → f not |
|---|
If you have SVN installed - you can use http://mediawiki.fckeditor.net/index.php/SVN_Instructions
If not - just provide version of the original files, I will make the patch.
comment:9 Changed 17 years ago by
| Summary: | f not → Category Management within FCKeditor |
|---|
Sorry. I changed summary by accident.
Changed 17 years ago by
| Attachment: | 1410.patch added |
|---|
comment:10 Changed 17 years ago by
Ok, here is the patch. I've changed some code to be more standart (like tableName() etc).
comment:12 Changed 17 years ago by
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
Thanks! Fixed with [3191].

This is already partly available: create a link with the link button, and type "Category:" + a part of the category name, you will get a list of available ones.