Was this page helpful?

Monitor changes on watched pages, search criteria or given pathnames

     

    Introduction

    I get the idea from the following page:

        User:Neilw/Monitoring

    But, insted of hard write the pathnames, just use the watch list to populate the grid, then when I was programing I also thought that was interesant to have too pathnames, and search criteria to populate the grid.

    The other good thing of the template, it's that it saves the "state" of the pages when you decide, then you can return to the monitoring page and look for what's changed.

    You can get more information on this forum thread:

    http://forums.developer.mindtouch.co...ead.php?t=6562

    History

    Version Date Author Description
     1.0  28-October carles.coll  First Release
     1.1  07-November-2009 carles.coll - Susbtitute the Last edit resume, for a link to Difference
    between las review and actual version.
    - Change the behaviour, all uses AJAX calls, no page reloads.
    - Show how many changes on (views, comments, attachments)
    1.2 06-March-2010 carles.coll - A change on language behaviour on 9.12 release -> Better language behaviour
    1.3 10-March-2010 carles.coll - Added a loading icon on ajax action.
    1.4 19-March-2010 carles.coll - Mindtouch guys changed an JS api call, Deki.Api -> Mindtouch.Deki , Grrr
    1.5 24-March-2010 carles.coll - Change some CSS copied from neilwPagesMonitor

    Ideas for future releases

    • Show who and what was attached
    • [DONE!! 07-Nov-2009] Make it all AJAX like (not page reloads)
    • [DONE!! 07-Nov-2009] HOT!!! Put a link onto the last edit field to the diff page from the last update, this way yon can see automatically all the changes from last review
    • Redesign Avatar+Text CSS, it are not showing very well
    • himikel: to show only the last changes (colored cells)
    • himikel: to explore only N levels in the tree

    Requirements

    • This template requires MindTouch version:
      • Template:collapseItem
      • Template:TSTable
      • DekiApi
      • Images
        • A default image for NO_AVATAR, update "constant" NO_AVATAR
        • /skins/fiesta/icon_grid_dropdown.png, update "constant" ICONOS

    How do I install it?

    1. Create a template, call it "Template:PagesMonitor" (or rename as you desire).  You must have UNSAFECONTENT permission for this to work.
    2. Create a "DekiScript" block on the template page (use the "Style" menu in the editor")
    3. Copy the code from the end of this page and paste it into the DekiScript block.  To copy, click "expand source", then mouse over the top right corner of the source code, and click the "view source" button.  This will pop up a window with the source code.  Select all, then copy to clipboard.
    4. Make sure there isn't an extra blank paragraph after the DekiScript block! Do this every time you edit!!!  
    5. Save.

     

    A quick note about the examples on this page

    For all the examples on this page, the code is shown before the working example.  The code is shown with the syntax extension, and looks like this:

    PagesMonitor();

    This means that the actual code on the page should be enclosed in a DekiScript block.  If you want to copy the code from this page, then use the same procedure as described in steps 2-4 above. 

    How do I use it?

     

    Arguments

    Name Type Default Description
    page_alerts bool?  true  For the moment it doesn't work, there's no way to get a list of page alers for a given user. When I can get this list of pages, it will be a second to include here.
    favorites bool?  true  It includes all the Whatch List pages
    paths List of str?  []  List of paths to add, they get recursive subpages automatically.
    search_criteria str?  ""  Search criteria for pages to add.
    languages str?
    1. Page language
    2. Site language
    3.  'en-us'
     Language PagesMonitor standard texts

    Interface usage

    1. what does the first column do?
      • The first column, get the whole tree of the checked page (subpages, and so on).
    2. what does the last column mean?
      • The last column shows where the line comes from:
        - Star -> From Whatch list / Favorites
        - Tree -> Recursive ones or from a given path
        - Turn key -> From a search
    3. what does the color coding mean?
      • Color coding (there's only green) it says what's changed from the last update.
    4. the "update history" saves the actual values, and reloads the page, then you will see nothing green (3), when someone does something to the given pages then it will get green again.

    Examples

     The following example, gives a simple use of this template - just monitor your's Watch Pages (a.k.a. favorites).

    PagesMonitor();
    
    (unable to fetch text document from uri [status: 501 (NotImplemented)]) (click for details)

    Reference(s)

     

    Credits/Special Thanks

    • To neilw, to give me the idea, and the base code from what this come from.

    Template/Extension Source Code

    /* PagesMonitor
        Monitors the changes on pages, it saves the state per user.
    
        get the idea from http://developer.mindtouch.com/index.php?title=User:Neilw/Monitoring by neilw
        created by carles.coll, 2009
    
        Version history:
            1.00    28-October-2009        First published version
            1.01    07-november-2009       - Susbtitute the Last edit resume, for a link to Difference
                                              between las review and actual version.
                                           - Change the behaviour, all uses AJAX calls, no page reloads.
                                           - Show how many changes on (views, comments, attachments)
            1.02    06-March-2010          A change on language behaviour on 9.12 release -> Better language behaviour.
            1.03    10-March-2010          Added a loading icon on ajax action.
            1.04    19-March-2010          Mindtouch guys changed an JS api call, Deki.Api -> Mindtouch.Deki , Grrr
            1.05    24-March-2010          Change some CSS copied from neilwPagesMonitor
            1.06    30-August-2010         Some minor changes with problems with   entity with v10 release
    
     Usage:  PagesMonitor(favorites:bool?, paths:list of str?, search_criteria:str?, language:str?)
        favorites:  (optional) default -> true; It includes all the Whatch List pages.
        paths:   (optional) default -> []; List of paths to add, they get recursive automatically.
        search_criteria:      (optional) default -> ''; Search criteria for pages to monitor.
        language:                 (optional) default -> 
                                                        1rst -> Page language
                                                        2nd  -> Site language
                                                        3rd  -> 'en-us'
    
    */
    
    dekiapi();
    
    // + PARAMETERS
    var par = { 
        favorites: __request.args.favorites?? args.favorites ??  true,
        paths: __request.args.paths?? args.paths ??  [],
        search_criteria: __request.args.search_criteria ?? args.search_criteria ??  '',
        language: __request.args.language ?? args.language ?? ( wiki.language ? wiki.language() : (page.language .. site.languge .. 'en-us') ),
        ajax_action: String.tolower( __request.args.ajax_action ?? args.ajax_action ?? 'load')   
       };
    
    if ((par.ajax_action=='load') || (par.ajax_action=='reload_pagesmonitor')) {
    
    
    // + CONSTANTS
    
    // -- START LANGUAGE STRINGS
    var LANGUAGE_ES = {
        title_recursive: web.html("<span class='recursive' title='Incluir subpáginas'>&nbsp;</span>"),
        title_page: "Página",
        title_cmts: web.html("<span class='comment' title='Número comentarios'>&nbsp;</span>"),
        title_lst_cmt: "Ult. Com.",
        title_lst_edit: "Ult. Edición",
        title_views: web.html("<span class='views' title='Número Visitas'>&nbsp;</span>"),    
        title_atts: web.html("<span class='attach' title='Número Adjuntos'>&nbsp;</span>"),
        title_types: "T",
    
        txt_last_updated: "Fecha última actualización:",
    
        error_no_data_page: "ERROR: no puedo encontrar la pagina con los datos históricos.",
        error_updating_history: "ERROR: actualizando el histórico ",
        error_creating_history: "ERROR: creando el histórico ",
        error_reading_history: "ERROR: leyendo el histórico "
    
        };
    var LANGUAGE_EN = {
        title_recursive: web.html("<span class='recursive' title='Include subpages'>&nbsp;</span>"),
        title_page: "Page",
        title_cmts: web.html("<span class='comment' title='Comments number'>&nbsp;</span>"),
        title_lst_cmt: "Last comment",
        title_lst_edit: "Last edit",
        title_views: web.html("<span class='views' title='Viewcount'>&nbsp;</span>"),    
        title_atts: web.html("<span class='attach' title='Attachments number'>&nbsp;</span>"),
        title_types: "T",
    
        txt_last_updated: "Last updated on:",
    
        error_no_data_page: "ERROR: can't find page with data store",
        error_updating_history: "ERROR: updating history ",
        error_creating_history: "ERROR: creating history ",
        error_reading_history: "ERROR: reding history "
    
        };
    
    var TXTS = { 'es-es': LANGUAGE_ES, 'en-us': LANGUAGE_EN,  'en': LANGUAGE_EN };
    var lg = par.language;
    // -- END LANGUAGE STRINGS
    
    var OBJ_BLANK = {
            page: '' ,
            views: 0,
            cmts: 0,
            lastcomment: '',
            lastedit:    '',
            revision: 1
          };
    var STYLE_DIFF_VALUE = 'background-color: #AAFFAA';
    var HISTORY_STORE = 'monitoring_history_'..user.name;
    var RECURSIVE_STORE = 'monitoring_recursive_'..user.name;
    var ICONOS = '/skins/fiesta/icon_grid_dropdown.png';
    var NO_AVATAR = '/@api/deki/files/4913/=NoAvatar.jpg';
    var DATE_FORMAT = 'dd/MM/yyyy hh:mm';
    
    // + VARS
    /*var path = $3 ?? $path;
    var p = (path == nil ? page : wiki.getpage(path));*/
    var p = page;
    var p_api = null;
    if (p == nil) { <p>TXTS[lg].error_no_data_page;</p>;}
       else { let p_api = p.api; }
    
    var cache_avatars = {};
    var avatar,source,n,a;
    
    var favorites = [];
    
    // + LET'S CODE
    // -- Let's search for the notifications
    // -- !!! We can't do it for the moment, they are stored on a file, and it's
    // -- !!! innaccesible from DekiScript, let's wait for a ne Deki Wiki release...
    
    // -- Let's search for the watchlist
    if (par.favorites) {
       let favorites ..= [ { path: xml.text(fname), type: "<span class='favoritos' title='favoritos'>&nbsp;</span>", recusive: 0 } foreach var fname in 
                        wiki.api(site.api.."/users/"..user.id.."/favorites")['//path'] ]; 
      }
    
    // -- Let's search for the search criteria
    if (par.search_criteria!='') {
       var sres = wiki.getsearch(par.search_criteria, 10000, 'title');
       foreach(var gs in sres) {
         let favorites ..= [ { path: gs.path, 
                type: "<span class='search' title='busqueda'>&nbsp;</span>", 
                recursive: 0} ]; 
        }
     }
    
    // -- Let's add each path
    if (par.paths!=[]) {
      foreach(var p in par.paths) { 
        let favorites ..= [ { path: p, 
            type: "<span class='recursive' title='ruta'>&nbsp;</span>",
            recursive: 3} ]; 
       }
     }
    
    // -- Let's eliminate de duplicity
    let k = List.GroupBy(favorites,"$.path");
    let favorites = [];
    foreach(var group in map.keys(k)) {
      var types = "";
      var rec = 0;
      foreach(var val in k[group]) {
            let types ..= val.type;
            if (val.recursive>rec) { let rec = val.recursive;}
        }
      let favorites ..= [ { 'path': group, 'types': types, 'recursive': rec} ];
     }
      
    var recursive = json.parse(page.properties[RECURSIVE_STORE].text ?? "") ??[];
    
    var pages = [];
    var npages = 0;
    
    foreach(var fv in favorites) {
      let npages += 1;
      var p = wiki.getpage(fv.path);
      var r = 0;
      if ((list.contains(recursive,""..p.id))||(fv.recursive>0)) {
         var tree = wiki.tree(fv.path);
         let npages +=#xml.list(tree, ".//li"); 
         let r = 1;
        }
      let pages ..= [ {'path': fv.path, 'recursive': (fv.recursive>0?fv.recursive:r), 'types': fv.types} ];
     }
    
    
    var data_history = json.parse(page.properties[HISTORY_STORE].text ?? "") ??[];
    
    var data = [];
    var data_save = [ { id: 'special', fecha: (date.now) } ];
    
    var dummy = Num.Series(0,npages);
    
    foreach(var dummy_k in dummy) {
        if (__index==#pages) { break; }
        var act = pages[__index];
        var path = act.path;
        var p = wiki.getpage(path);
        var num_cmts = #p.comments;
        var num_atts = #p.files;
        var last = num_cmts ? p.comments[num_cmts - 1] : nil;
        var hobj = List.Select(data_history,"$.id=='"..p.id.."'");
        if (#hobj) { let hobj = hobj[0]; }
          else { let hobj = OBJ_BLANK; }
    
        if (act.recursive>0) {
          foreach(var k in p.subpages) {
             let pages ..= [ { 'path': k.path, 'recursive': 2, 'types': "<span class='recursive' title='Subpágina'>&nbsp;</span>" } ];
            }
         }
        var obj = {
            id: p.id ,
            page: p.path ,
            path: p.path ,
            views: p.viewcount,
            cmts: num_cmts,
            atts: num_atts,
            lastcomment: (num_cmts ? ( date.format(last.date,DATE_FORMAT).." by "..last.author.name; ) : ""),
            lastedit:    ( date.format(p.date, DATE_FORMAT).." by "..p.author.name ),
            revision: (#p.revisions)
          };
        let data_save ..= [ obj ];
    
         // -- Let Search for the avatar and save it to the cache.
        var users = [ p.author ];
        var un ='';
        if (num_cmts) { let users ..= [ last.author ]; }
        foreach ( var uns in users ) {
          let un = uns.name;
          if (!Map.Contains(cache_avatars,un)) {
            let source=wiki.getpage('/User:' .. un).files;
            let avatar=NO_AVATAR;
            foreach (var f in source) {
               let n=f.name;
               let a=f.api;
               if (String.tolower(n) == 'avatar.jpg') { let avatar=f.api; }
              }
            if (avatar==NO_AVATAR) { let avatar = uns.gravatar; }
            let cache_avatars ..= {(un): ("<img src='"..avatar.."' width='30px' valing='top' style='vertical-align: text-top' />") };
           }
         }
    
        let obj ..= { 
            views: web.html( (hobj.views!=obj.views ? "<span class='plusCount'>".."+"..(obj.views-hobj.views).."</span>" :"")..(hobj.views?obj.views:"")),
            cmts: web.html((hobj.cmts!=obj.cmts? "<span class='plusCount'>".."+"..(obj.cmts-hobj.cmts).."</span>" :"")..(hobj.cmts?obj.cmts:"")),
            atts: web.html((hobj.atts!=obj.atts? "<span class='plusCount'>".."+"..(obj.atts-hobj.atts).."</span>" :"")..(hobj.atts?obj.atts:"")),
            recursive: (act.recursive<2?
                            web.html("<input type='checkbox' name='recursive' class='pm_cb_recursive' value='"..obj.id.."' "..(act.recursive>0 ? "checked=1" : nil).." />"):
                            (act.recursive==3?web.html("<span class='recursive' title='Se incluyen subpaginas'>&nbsp;</span>"):"")),
            types: web.html(act.types),
            page_style: (hobj.page!=obj.page?STYLE_DIFF_VALUE:''),
            views_style: (hobj.views!=obj.views?STYLE_DIFF_VALUE:''),
            cmts_style: (hobj.cmts!=obj.cmts?STYLE_DIFF_VALUE:''),
            atts_style: (hobj.atts!=obj.atts?STYLE_DIFF_VALUE:''),
            lastcomment_style: (hobj.lastcomment!=obj.lastcomment?(last.author.name !=user.name?STYLE_DIFF_VALUE:''):''),
            lastedit_style: (hobj.lastedit!=obj.lastedit?(p.author.name!=user.name?STYLE_DIFF_VALUE:''):''),
    
            lastcomment: (num_cmts ? ( <div class='mp_avatar'>web.html(cache_avatars[last.author.name])</div> 
                                       <div class='mp_avatar_text'>obj.lastcomment;
                                       collapseItem(<div> last.text </div>)</div> ) : ""),
            page: (web.link(p.uri, p.title);
                    <br /><span style="font-size: 10px; font-color: #eeeeee; font-style: italic">(obj.path)</span>;),
            lastedit:    ( <div class='mp_avatar'>web.html(cache_avatars[p.author.name])</div>
                           <div class='mp_avatar_text'>obj.lastedit;' ';
                            if (hobj.revision!=#p.revisions) { <a href=(uri.build(p.uri,nil,{action:'diff',revision: (hobj.revision??1),diff: (#p.revisions)})) target='_blank'>'Diff'</a> }
                            </div> )
    
           };
        let data ..= [ obj ];
    }
    
    let data = list.sort(data,'path');
    
    // + DYNAMIC HTML CONTENT
    <div id='monitor_pages'>
    <form id='form_page_monitor'>
    <input id='button_pm_update_history' type="button" value="Update History" />
    if (#data_history>0) {
      <span id='pages_monitor_updated' class='mp_last_updated'>" "..TXTS[lg].txt_last_updated.." "..data_history[0].fecha</span>
      <span id="pages_monitor_loading" style="display:none;margin:auto;width:40px;height:40px;background-repeat: no-repeat; align: left; background-image:url('/skins/common/icons/anim-wait-circle.gif');">&nbsp;;&nbsp;;&nbsp;;</span>
     }
    
    TSTable {
        options: { id: 'ts_pages_monitor', zebra:true },
        columns: [
            { title:TXTS[lg].title_recursive,key: "recursive", width:"5%"},
            { title:TXTS[lg].title_page,    key: "page", width:"35%" , style:"($.page_style)" },
            { title:TXTS[lg].title_views,   key: "views", width:"8%", style:"($.views_style)" },
            { title:TXTS[lg].title_atts,    key: "atts", width:"8%", style:"($.atts_style)" },
            { title:TXTS[lg].title_cmts,    key: "cmts", width:"8%", style:"($.cmts_style)" },
            { title:TXTS[lg].title_lst_cmt, key:"lastcomment", width:"20%", style:"($.lastcomment_style)" },
            { title:TXTS[lg].title_lst_edit,key:"lastedit", width:"20%", style:"($.lastedit_style)" },
            { title:TXTS[lg].title_types,   key:"types" }
    
          ],
        data: data
    };
    </form>
    
    <span id='pg_data_save' style='display: none' data=(json.emit(data_save))></span>
    
    </div>
    
    if (par.ajax_action=='load') {
    
    <script type="text/javascript"> "
    
     function pagemonitorWireControls(){
        Deki.$('.pm_cb_recursive').bind('click', function() {
            var $this = Deki.$(this);
            var prop = 'urn:custom.mindtouch.com#'  + '"..RECURSIVE_STORE.."';
            MindTouch.Deki.ReadPageProperty('"..p_api.."', prop, function(result) {
                var data = YAHOO.lang.JSON.parse(result.value || '[]');
                if ($this.attr('checked'))
                    {  data.push($this.attr('value')); }
                    else {  
                            var i; 
                            var trobat=-1;
                            for(i=0;i<data.length;i++) {
                                if (data[i]==$this.attr('value')) { trobat=i; }
                               } 
                            if (trobat!=-1) { data.splice(trobat,1); }
                         }
                if(result.etag)
                    MindTouch.Deki.UpdatePageProperty(result.href,  YAHOO.lang.JSON.stringify(data), result.etag,
                        function() { 
                                      MindTouch.Deki.Reload($('#monitor_pages'),{ajax_action: 'reload_pagesmonitor'}, function() {  pagemonitorWireControlsReload(); });
                                    },
                        function(result) { alert('"..TXTS[lg].error_updating_history.." (status: ' +
                result.status + ' - ' + result.text + ')'); }
                    );
                else
                    MindTouch.Deki.CreatePageProperty('"..p_api.."', prop,  YAHOO.lang.JSON.stringify(data),
                        function() { 
                                    MindTouch.Deki.Reload($('#monitor_pages'),{ajax_action: 'reload_pagesmonitor'}, function() {  pagemonitorWireControlsReload(); });
                                    },
                        function(result) { alert('"..TXTS[lg].error_creating_history.." (status: ' +
                result.status + ' - ' + result.text + ')'); }
                    );
            },
            function(result) { alert('"..TXTS[lg].error_reading_history.." (status: ' +
                result.status + ' - ' + result.text + ')'); }
            );
        });
    
        Deki.$('#button_pm_update_history').bind('click', function() {
            $('#pages_monitor_updated').hide();
            $('#pages_monitor_loading').show();
    
            var prop = 'urn:custom.mindtouch.com#'  + '"..HISTORY_STORE.."';
            MindTouch.Deki.ReadPageProperty('"..p_api.."', prop, function(result) {
                var data = Deki.$('#pg_data_save').attr('data');
                if(result.etag)
                    MindTouch.Deki.UpdatePageProperty(result.href, data, result.etag,
                        function() { 
                             MindTouch.Deki.Reload($('#monitor_pages'),{ajax_action: 'reload_pagesmonitor'}, function() { 
                                 pagemonitorWireControlsReload();
                                });
                            },
                        function(result) { alert('"..TXTS[lg].error_updating_history.." (status: ' +
                result.status + ' - ' + result.text + ')'); }
                    );
                else
                    MindTouch.Deki.CreatePageProperty('"..p_api.."', prop, data,
                        function() { 
                             MindTouch.Deki.Reload($('#monitor_pages'),{ajax_action: 'reload_pagesmonitor'}, function() {  pagemonitorWireControlsReload(); });
                            },
                        function(result) { alert('"..TXTS[lg].error_creating_history.." (status: ' +
                result.status + ' - ' + result.text + ')'); }
                    );
            },
            function(result) { alert('"..TXTS[lg].error_reading_history.." (status: ' +
                result.status + ' - ' + result.text + ')'); }
            );
    
         });
    
      }
    
     function pagemonitorWireControlsReload() { 
        tstableApply($, false,false,null,'ts_pages_monitor',{},[],['zebra'],[],false);
        pagemonitorWireControls();
      }
    
     Deki.$(document).ready(function(){ 
            pagemonitorWireControls(); 
       });
     
    " </script> 
    
     // + CSS DEFINITION
    <style type="text/css">"
     #monitor_pages span.mp_last_updated {
         font-size:12px;
         font-style: italic;
        }
    
     #monitor_pages span.favoritos {
            width: 28px;
            height: 28px;
            float: left;
    	background-image: url("..ICONOS..");
    	background-position: left -420px;
    	background-repeat:no-repeat;
     }
    
     #monitor_pages span.search {
            width: 28px;
            height: 28px;
            float: left;
    	background-image: url("..ICONOS..");
    	background-position: left -60px;
    	background-repeat:no-repeat;
     }
    
     #monitor_pages span.recursive {
            width: 28px;
            height: 28px;
            float: left;
    	background-image: url("..ICONOS..");
    	background-position: left -180px;
    	background-repeat:no-repeat;
     }
    
     #monitor_pages span.views {
            width: 28px;
            height: 28px;
            float: left;
    	background-image: url("..ICONOS..");
    	background-position: left -120px;
    	background-repeat:no-repeat;
     }
    
     #monitor_pages span.attach {
            width: 28px;
            height: 28px;
            float: left;
    	background-image: url("..ICONOS..");
    	background-position: left -300px;
    	background-repeat:no-repeat;
     }
    
     #monitor_pages span.comment {
            width: 28px;
            height: 28px;
            float: left;
    	background-image: url("..ICONOS..");
    	background-position: left -510px;
    	background-repeat:no-repeat;
     }
    
     #monitor_pages div.mp_avatar {
            margin: 0px; 
            padding: 0px; 
            float: left; 
            width: 25%;
        }
    
     #monitor_pages div.mp_avatar_text {
            margin: 0px; 
            padding: 0px; 
            font-size: 10px;
            float: right; 
            width: 70%;
        }
    
    #monitor_pages .plusCount {
        padding:2px;
        background-color: black;
        color:white;
        margin-right: 5px;
    }
    
    
    "</style>
     } // if (par.ajax_action=='load')...
    
    }  // -- if ((par.ajax_action=='load') || (par.ajax_action=='reload_pagesmonitor')) ..

     

    Disclaimers

    None.

    Discuss

    Show more... Show all


    #2
    ttablek at 18/12/2009 - 15:10
    #1: yeah


    #3
    jonverve at 11/02/2010 - 23:57
    I added the following code just below the comment DYNAMIC HTML CONTENT
    web.link(uri.build(site.uri .. "Special:Watchedpages"), "Edit your watched pages");
    This provides a link to the special page where a user can remove watched pages. Let me know what you think.

    #4
    carles.coll at 12/02/2010 - 06:23
    #3: @jonverve - Yes, it's usefull, but only when favorites==true, you can whatch pages by pathnames and then they aren't on the Special:Watchedpages.


    #5
    sabadosj at 03/08/2010 - 17:12
    This solution appears to be broken after the MindTouch 2010 upgrade. Can this be confirmed and can anyone offer a fix if that's the case?
    Add message:

    Was this page helpful?
    Tag page
    Viewing 4 of 4 comments: view all
    #1: yeah
    Posted 05:10, 18 Dec 2009
    I added the following code just below the comment DYNAMIC HTML CONTENT

    <div style="float:right;font-size:12px;">web.link(uri.build(site.uri .. "Special:Watchedpages"), "Edit your watched pages");</div>

    This provides a link to the special page where a user can remove watched pages. Let me know what you think.
    Posted 13:57, 11 Feb 2010
    #3: @jonverve - Yes, it's usefull, but only when favorites==true, you can whatch pages by pathnames and then they aren't on the Special:Watchedpages.
    Posted 20:23, 11 Feb 2010
    This solution appears to be broken after the MindTouch 2010 upgrade. Can this be confirmed and can anyone offer a fix if that's the case?
    Posted 07:12, 3 Aug 2010
    Viewing 4 of 4 comments: view all
    You must login to post a comment.

    Copyright © 2011 MindTouch, Inc. Powered by