Fossil SCM
/wikiedit now embeds a copy of the page list JSON at page-render time to save an XHR request at startup.
Commit
bc6651331a81baa7d1f9ec6d19a7dfb4fedca54ba4022224bb5cc31f4ae656c3
Parent
7913bba6109d8a1…
2 files changed
+12
-5
+56
-24
+12
-5
| --- src/fossil.page.wikiedit.js | ||
| +++ src/fossil.page.wikiedit.js | ||
| @@ -413,15 +413,22 @@ | ||
| 413 | 413 | self.cache.pageList = list; |
| 414 | 414 | self._rebuildList(); |
| 415 | 415 | F.message("Loaded page list."); |
| 416 | 416 | }; |
| 417 | 417 | } |
| 418 | - F.fetch('wikiajax/list',{ | |
| 419 | - urlParams:{verbose:true}, | |
| 420 | - responseType: 'json', | |
| 421 | - onload: callee.onload | |
| 422 | - }); | |
| 418 | + if(P.initialPageList){ | |
| 419 | + /* ^^^ injected at page-creation time. */ | |
| 420 | + const list = P.initialPageList; | |
| 421 | + delete P.initialPageList; | |
| 422 | + callee.onload(list); | |
| 423 | + }else{ | |
| 424 | + F.fetch('wikiajax/list',{ | |
| 425 | + urlParams:{verbose:true}, | |
| 426 | + responseType: 'json', | |
| 427 | + onload: callee.onload | |
| 428 | + }); | |
| 429 | + } | |
| 423 | 430 | return this; |
| 424 | 431 | }, |
| 425 | 432 | |
| 426 | 433 | /** |
| 427 | 434 | Returns true if the given name appears to be a valid |
| 428 | 435 |
| --- src/fossil.page.wikiedit.js | |
| +++ src/fossil.page.wikiedit.js | |
| @@ -413,15 +413,22 @@ | |
| 413 | self.cache.pageList = list; |
| 414 | self._rebuildList(); |
| 415 | F.message("Loaded page list."); |
| 416 | }; |
| 417 | } |
| 418 | F.fetch('wikiajax/list',{ |
| 419 | urlParams:{verbose:true}, |
| 420 | responseType: 'json', |
| 421 | onload: callee.onload |
| 422 | }); |
| 423 | return this; |
| 424 | }, |
| 425 | |
| 426 | /** |
| 427 | Returns true if the given name appears to be a valid |
| 428 |
| --- src/fossil.page.wikiedit.js | |
| +++ src/fossil.page.wikiedit.js | |
| @@ -413,15 +413,22 @@ | |
| 413 | self.cache.pageList = list; |
| 414 | self._rebuildList(); |
| 415 | F.message("Loaded page list."); |
| 416 | }; |
| 417 | } |
| 418 | if(P.initialPageList){ |
| 419 | /* ^^^ injected at page-creation time. */ |
| 420 | const list = P.initialPageList; |
| 421 | delete P.initialPageList; |
| 422 | callee.onload(list); |
| 423 | }else{ |
| 424 | F.fetch('wikiajax/list',{ |
| 425 | urlParams:{verbose:true}, |
| 426 | responseType: 'json', |
| 427 | onload: callee.onload |
| 428 | }); |
| 429 | } |
| 430 | return this; |
| 431 | }, |
| 432 | |
| 433 | /** |
| 434 | Returns true if the given name appears to be a valid |
| 435 |
+56
-24
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -745,11 +745,10 @@ | ||
| 745 | 745 | static int wiki_ajax_emit_page_object(const char *zPageName, |
| 746 | 746 | int includeContent){ |
| 747 | 747 | Manifest * pWiki = 0; |
| 748 | 748 | char * zUuid; |
| 749 | 749 | |
| 750 | - cgi_set_content_type("application/json"); | |
| 751 | 750 | if( is_sandbox(zPageName) ){ |
| 752 | 751 | char * zMimetype = |
| 753 | 752 | db_get("sandbox-mimetype","text/x-fossil-wiki"); |
| 754 | 753 | char * zBody = db_get("sandbox",""); |
| 755 | 754 | CX("{\"name\": %!j, \"type\": \"sandbox\", " |
| @@ -846,10 +845,11 @@ | ||
| 846 | 845 | ajax_route_error(403,"Creating new page [%s] requires passing " |
| 847 | 846 | "isnew=1.", zPageName); |
| 848 | 847 | return; |
| 849 | 848 | } |
| 850 | 849 | blob_init(&content, zContent ? zContent : "", -1); |
| 850 | + cgi_set_content_type("application/json"); | |
| 851 | 851 | db_begin_transaction(); |
| 852 | 852 | wiki_cmd_commit(zPageName, parentRid, &content, zMimetype, 0); |
| 853 | 853 | rollback = wiki_ajax_emit_page_object(zPageName, 1) ? 0 : 1; |
| 854 | 854 | db_end_transaction(rollback); |
| 855 | 855 | } |
| @@ -870,10 +870,11 @@ | ||
| 870 | 870 | |
| 871 | 871 | if( zPageName==0 || zPageName[0]==0 ){ |
| 872 | 872 | ajax_route_error(400,"Missing page name."); |
| 873 | 873 | return; |
| 874 | 874 | } |
| 875 | + cgi_set_content_type("application/json"); | |
| 875 | 876 | wiki_ajax_emit_page_object(zPageName, 1); |
| 876 | 877 | } |
| 877 | 878 | |
| 878 | 879 | /* |
| 879 | 880 | ** Ajax route handler for /wikiajax/diff. |
| @@ -951,33 +952,28 @@ | ||
| 951 | 952 | blob_reset(&content); |
| 952 | 953 | } |
| 953 | 954 | } |
| 954 | 955 | |
| 955 | 956 | /* |
| 956 | -** Ajax route handler for /wikiajax/list. | |
| 957 | -** | |
| 958 | -** Optional parameters: verbose, includeContent (see below). | |
| 959 | -** | |
| 960 | -** Responds with JSON. On error, an object in the form documented by | |
| 961 | -** ajax_route_error(). | |
| 962 | -** | |
| 963 | -** On success, it emits an array of strings (page names) sorted | |
| 964 | -** case-insensitively. If the "verbose" parameter is passed in then | |
| 965 | -** the result list contains objects in the format documented for | |
| 966 | -** wiki_ajax_emit_page_object(). The content of each object is elided | |
| 967 | -** unless the "includeContent" parameter is passed on. | |
| 968 | -** | |
| 969 | -** The result list always contains an entry | |
| 970 | -** named "sandbox" which represents the sandbox pseudo-page. | |
| 971 | -*/ | |
| 972 | -static void wiki_ajax_route_list(void){ | |
| 957 | +** Outputs the wiki page list in JSON form. If verbose is false then | |
| 958 | +** it emits an array of strings (page names). If verbose is true it outputs | |
| 959 | +** an array of objects in this form: | |
| 960 | +** | |
| 961 | +** { name: string, version: string or null of sandbox box, | |
| 962 | +** parent: uuid or null for first version or sandbox, | |
| 963 | +** mimetype: string, | |
| 964 | +** type: string (normal, branch, tag, checkin, or sandbox) | |
| 965 | +** } | |
| 966 | +** | |
| 967 | +** If includeContent is true, the object contains a "content" member | |
| 968 | +** with the raw page content. includeContent is ignored if verbose is | |
| 969 | +** false. | |
| 970 | +** | |
| 971 | +*/ | |
| 972 | +static void wiki_render_page_list_json(int verbose, int includeContent){ | |
| 973 | 973 | Stmt q = empty_Stmt; |
| 974 | 974 | int n = 0; |
| 975 | - const int verbose = ajax_p_bool("verbose"); | |
| 976 | - const int includeContent = ajax_p_bool("includeContent"); | |
| 977 | - | |
| 978 | - cgi_set_content_type("application/json"); | |
| 979 | 975 | db_begin_transaction(); |
| 980 | 976 | db_prepare(&q, "SELECT" |
| 981 | 977 | " substr(tagname,6) AS name" |
| 982 | 978 | " FROM tag WHERE tagname GLOB 'wiki-*'" |
| 983 | 979 | " UNION SELECT 'Sandbox' AS name" |
| @@ -992,13 +988,39 @@ | ||
| 992 | 988 | CX("%!j", zName); |
| 993 | 989 | }else{ |
| 994 | 990 | wiki_ajax_emit_page_object(zName, includeContent); |
| 995 | 991 | } |
| 996 | 992 | } |
| 993 | + CX("]"); | |
| 997 | 994 | db_finalize(&q); |
| 998 | 995 | db_end_transaction(0); |
| 999 | - CX("]"); | |
| 996 | +} | |
| 997 | + | |
| 998 | +/* | |
| 999 | +** Ajax route handler for /wikiajax/list. | |
| 1000 | +** | |
| 1001 | +** Optional parameters: verbose, includeContent (see below). | |
| 1002 | +** | |
| 1003 | +** Responds with JSON. On error, an object in the form documented by | |
| 1004 | +** ajax_route_error(). | |
| 1005 | +** | |
| 1006 | +** On success, it emits an array of strings (page names) sorted | |
| 1007 | +** case-insensitively. If the "verbose" parameter is passed in then | |
| 1008 | +** the result list contains objects in the format documented for | |
| 1009 | +** wiki_ajax_emit_page_object(). The content of each object is elided | |
| 1010 | +** unless the "includeContent" parameter is passed on with a | |
| 1011 | +** "non-false" value.. | |
| 1012 | +** | |
| 1013 | +** The result list always contains an entry named "Sandbox" which | |
| 1014 | +** represents the sandbox pseudo-page. | |
| 1015 | +*/ | |
| 1016 | +static void wiki_ajax_route_list(void){ | |
| 1017 | + const int verbose = ajax_p_bool("verbose"); | |
| 1018 | + const int includeContent = ajax_p_bool("includeContent"); | |
| 1019 | + | |
| 1020 | + cgi_set_content_type("application/json"); | |
| 1021 | + wiki_render_page_list_json(verbose, includeContent); | |
| 1000 | 1022 | } |
| 1001 | 1023 | |
| 1002 | 1024 | /* |
| 1003 | 1025 | ** WEBPAGE: wikiajax |
| 1004 | 1026 | ** |
| @@ -1240,11 +1262,21 @@ | ||
| 1240 | 1262 | style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer", |
| 1241 | 1263 | "storage", "page.wikiedit", 0); |
| 1242 | 1264 | builtin_fulfill_js_requests(); |
| 1243 | 1265 | /* Dynamically populate the editor... */ |
| 1244 | 1266 | style_emit_script_tag(0,0); |
| 1245 | - CX("\nfossil.onPageLoad(function(){\n"); | |
| 1267 | + { | |
| 1268 | + /* Render the current page list to save us an XHR request | |
| 1269 | + during page initialization. This must be OUTSIDE of | |
| 1270 | + an onPageLoad() handler or else it does not get applied | |
| 1271 | + until after the wiki list widget is initialized. Similarly, | |
| 1272 | + it must come *after* window.fossil is initialized. */ | |
| 1273 | + CX("\nfossil.page.initialPageList = "); | |
| 1274 | + wiki_render_page_list_json(1, 0); | |
| 1275 | + CX(";\n"); | |
| 1276 | + } | |
| 1277 | + CX("fossil.onPageLoad(function(){\n"); | |
| 1246 | 1278 | CX("const P = fossil.page;\n" |
| 1247 | 1279 | "try{\n"); |
| 1248 | 1280 | if(!found && zPageName && *zPageName){ |
| 1249 | 1281 | /* For a new page, stick a dummy entry in the JS-side stash |
| 1250 | 1282 | and "load" it from there. */ |
| 1251 | 1283 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -745,11 +745,10 @@ | |
| 745 | static int wiki_ajax_emit_page_object(const char *zPageName, |
| 746 | int includeContent){ |
| 747 | Manifest * pWiki = 0; |
| 748 | char * zUuid; |
| 749 | |
| 750 | cgi_set_content_type("application/json"); |
| 751 | if( is_sandbox(zPageName) ){ |
| 752 | char * zMimetype = |
| 753 | db_get("sandbox-mimetype","text/x-fossil-wiki"); |
| 754 | char * zBody = db_get("sandbox",""); |
| 755 | CX("{\"name\": %!j, \"type\": \"sandbox\", " |
| @@ -846,10 +845,11 @@ | |
| 846 | ajax_route_error(403,"Creating new page [%s] requires passing " |
| 847 | "isnew=1.", zPageName); |
| 848 | return; |
| 849 | } |
| 850 | blob_init(&content, zContent ? zContent : "", -1); |
| 851 | db_begin_transaction(); |
| 852 | wiki_cmd_commit(zPageName, parentRid, &content, zMimetype, 0); |
| 853 | rollback = wiki_ajax_emit_page_object(zPageName, 1) ? 0 : 1; |
| 854 | db_end_transaction(rollback); |
| 855 | } |
| @@ -870,10 +870,11 @@ | |
| 870 | |
| 871 | if( zPageName==0 || zPageName[0]==0 ){ |
| 872 | ajax_route_error(400,"Missing page name."); |
| 873 | return; |
| 874 | } |
| 875 | wiki_ajax_emit_page_object(zPageName, 1); |
| 876 | } |
| 877 | |
| 878 | /* |
| 879 | ** Ajax route handler for /wikiajax/diff. |
| @@ -951,33 +952,28 @@ | |
| 951 | blob_reset(&content); |
| 952 | } |
| 953 | } |
| 954 | |
| 955 | /* |
| 956 | ** Ajax route handler for /wikiajax/list. |
| 957 | ** |
| 958 | ** Optional parameters: verbose, includeContent (see below). |
| 959 | ** |
| 960 | ** Responds with JSON. On error, an object in the form documented by |
| 961 | ** ajax_route_error(). |
| 962 | ** |
| 963 | ** On success, it emits an array of strings (page names) sorted |
| 964 | ** case-insensitively. If the "verbose" parameter is passed in then |
| 965 | ** the result list contains objects in the format documented for |
| 966 | ** wiki_ajax_emit_page_object(). The content of each object is elided |
| 967 | ** unless the "includeContent" parameter is passed on. |
| 968 | ** |
| 969 | ** The result list always contains an entry |
| 970 | ** named "sandbox" which represents the sandbox pseudo-page. |
| 971 | */ |
| 972 | static void wiki_ajax_route_list(void){ |
| 973 | Stmt q = empty_Stmt; |
| 974 | int n = 0; |
| 975 | const int verbose = ajax_p_bool("verbose"); |
| 976 | const int includeContent = ajax_p_bool("includeContent"); |
| 977 | |
| 978 | cgi_set_content_type("application/json"); |
| 979 | db_begin_transaction(); |
| 980 | db_prepare(&q, "SELECT" |
| 981 | " substr(tagname,6) AS name" |
| 982 | " FROM tag WHERE tagname GLOB 'wiki-*'" |
| 983 | " UNION SELECT 'Sandbox' AS name" |
| @@ -992,13 +988,39 @@ | |
| 992 | CX("%!j", zName); |
| 993 | }else{ |
| 994 | wiki_ajax_emit_page_object(zName, includeContent); |
| 995 | } |
| 996 | } |
| 997 | db_finalize(&q); |
| 998 | db_end_transaction(0); |
| 999 | CX("]"); |
| 1000 | } |
| 1001 | |
| 1002 | /* |
| 1003 | ** WEBPAGE: wikiajax |
| 1004 | ** |
| @@ -1240,11 +1262,21 @@ | |
| 1240 | style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer", |
| 1241 | "storage", "page.wikiedit", 0); |
| 1242 | builtin_fulfill_js_requests(); |
| 1243 | /* Dynamically populate the editor... */ |
| 1244 | style_emit_script_tag(0,0); |
| 1245 | CX("\nfossil.onPageLoad(function(){\n"); |
| 1246 | CX("const P = fossil.page;\n" |
| 1247 | "try{\n"); |
| 1248 | if(!found && zPageName && *zPageName){ |
| 1249 | /* For a new page, stick a dummy entry in the JS-side stash |
| 1250 | and "load" it from there. */ |
| 1251 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -745,11 +745,10 @@ | |
| 745 | static int wiki_ajax_emit_page_object(const char *zPageName, |
| 746 | int includeContent){ |
| 747 | Manifest * pWiki = 0; |
| 748 | char * zUuid; |
| 749 | |
| 750 | if( is_sandbox(zPageName) ){ |
| 751 | char * zMimetype = |
| 752 | db_get("sandbox-mimetype","text/x-fossil-wiki"); |
| 753 | char * zBody = db_get("sandbox",""); |
| 754 | CX("{\"name\": %!j, \"type\": \"sandbox\", " |
| @@ -846,10 +845,11 @@ | |
| 845 | ajax_route_error(403,"Creating new page [%s] requires passing " |
| 846 | "isnew=1.", zPageName); |
| 847 | return; |
| 848 | } |
| 849 | blob_init(&content, zContent ? zContent : "", -1); |
| 850 | cgi_set_content_type("application/json"); |
| 851 | db_begin_transaction(); |
| 852 | wiki_cmd_commit(zPageName, parentRid, &content, zMimetype, 0); |
| 853 | rollback = wiki_ajax_emit_page_object(zPageName, 1) ? 0 : 1; |
| 854 | db_end_transaction(rollback); |
| 855 | } |
| @@ -870,10 +870,11 @@ | |
| 870 | |
| 871 | if( zPageName==0 || zPageName[0]==0 ){ |
| 872 | ajax_route_error(400,"Missing page name."); |
| 873 | return; |
| 874 | } |
| 875 | cgi_set_content_type("application/json"); |
| 876 | wiki_ajax_emit_page_object(zPageName, 1); |
| 877 | } |
| 878 | |
| 879 | /* |
| 880 | ** Ajax route handler for /wikiajax/diff. |
| @@ -951,33 +952,28 @@ | |
| 952 | blob_reset(&content); |
| 953 | } |
| 954 | } |
| 955 | |
| 956 | /* |
| 957 | ** Outputs the wiki page list in JSON form. If verbose is false then |
| 958 | ** it emits an array of strings (page names). If verbose is true it outputs |
| 959 | ** an array of objects in this form: |
| 960 | ** |
| 961 | ** { name: string, version: string or null of sandbox box, |
| 962 | ** parent: uuid or null for first version or sandbox, |
| 963 | ** mimetype: string, |
| 964 | ** type: string (normal, branch, tag, checkin, or sandbox) |
| 965 | ** } |
| 966 | ** |
| 967 | ** If includeContent is true, the object contains a "content" member |
| 968 | ** with the raw page content. includeContent is ignored if verbose is |
| 969 | ** false. |
| 970 | ** |
| 971 | */ |
| 972 | static void wiki_render_page_list_json(int verbose, int includeContent){ |
| 973 | Stmt q = empty_Stmt; |
| 974 | int n = 0; |
| 975 | db_begin_transaction(); |
| 976 | db_prepare(&q, "SELECT" |
| 977 | " substr(tagname,6) AS name" |
| 978 | " FROM tag WHERE tagname GLOB 'wiki-*'" |
| 979 | " UNION SELECT 'Sandbox' AS name" |
| @@ -992,13 +988,39 @@ | |
| 988 | CX("%!j", zName); |
| 989 | }else{ |
| 990 | wiki_ajax_emit_page_object(zName, includeContent); |
| 991 | } |
| 992 | } |
| 993 | CX("]"); |
| 994 | db_finalize(&q); |
| 995 | db_end_transaction(0); |
| 996 | } |
| 997 | |
| 998 | /* |
| 999 | ** Ajax route handler for /wikiajax/list. |
| 1000 | ** |
| 1001 | ** Optional parameters: verbose, includeContent (see below). |
| 1002 | ** |
| 1003 | ** Responds with JSON. On error, an object in the form documented by |
| 1004 | ** ajax_route_error(). |
| 1005 | ** |
| 1006 | ** On success, it emits an array of strings (page names) sorted |
| 1007 | ** case-insensitively. If the "verbose" parameter is passed in then |
| 1008 | ** the result list contains objects in the format documented for |
| 1009 | ** wiki_ajax_emit_page_object(). The content of each object is elided |
| 1010 | ** unless the "includeContent" parameter is passed on with a |
| 1011 | ** "non-false" value.. |
| 1012 | ** |
| 1013 | ** The result list always contains an entry named "Sandbox" which |
| 1014 | ** represents the sandbox pseudo-page. |
| 1015 | */ |
| 1016 | static void wiki_ajax_route_list(void){ |
| 1017 | const int verbose = ajax_p_bool("verbose"); |
| 1018 | const int includeContent = ajax_p_bool("includeContent"); |
| 1019 | |
| 1020 | cgi_set_content_type("application/json"); |
| 1021 | wiki_render_page_list_json(verbose, includeContent); |
| 1022 | } |
| 1023 | |
| 1024 | /* |
| 1025 | ** WEBPAGE: wikiajax |
| 1026 | ** |
| @@ -1240,11 +1262,21 @@ | |
| 1262 | style_emit_fossil_js_apis(0, "fetch", "dom", "tabs", "confirmer", |
| 1263 | "storage", "page.wikiedit", 0); |
| 1264 | builtin_fulfill_js_requests(); |
| 1265 | /* Dynamically populate the editor... */ |
| 1266 | style_emit_script_tag(0,0); |
| 1267 | { |
| 1268 | /* Render the current page list to save us an XHR request |
| 1269 | during page initialization. This must be OUTSIDE of |
| 1270 | an onPageLoad() handler or else it does not get applied |
| 1271 | until after the wiki list widget is initialized. Similarly, |
| 1272 | it must come *after* window.fossil is initialized. */ |
| 1273 | CX("\nfossil.page.initialPageList = "); |
| 1274 | wiki_render_page_list_json(1, 0); |
| 1275 | CX(";\n"); |
| 1276 | } |
| 1277 | CX("fossil.onPageLoad(function(){\n"); |
| 1278 | CX("const P = fossil.page;\n" |
| 1279 | "try{\n"); |
| 1280 | if(!found && zPageName && *zPageName){ |
| 1281 | /* For a new page, stick a dummy entry in the JS-side stash |
| 1282 | and "load" it from there. */ |
| 1283 |