1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-07-06 20:14:22 +00:00

Initial Commit

This commit is contained in:
jeremy@jermolene.com 2023-04-29 17:16:14 +01:00
parent 1cac177211
commit 585c7339de
6 changed files with 318 additions and 2 deletions

View File

@ -20,6 +20,11 @@ exports.before = ["story"];
exports.synchronous = true;
exports.startup = function() {
// Install the HTTP client event handler
$tw.httpClient = new $tw.utils.HttpClient();
$tw.rootWidget.addEventListener("tm-http-request",function(event) {
$tw.httpClient.handleHttpRequest(event);
});
// Install the modal message mechanism
$tw.modal = new $tw.utils.Modal($tw.wiki);
$tw.rootWidget.addEventListener("tm-modal",function(event) {

View File

@ -3,7 +3,7 @@ title: $:/core/modules/utils/dom/http.js
type: application/javascript
module-type: utils
Browser HTTP support
HTTP support
\*/
(function(){
@ -13,11 +13,127 @@ Browser HTTP support
"use strict";
/*
A quick and dirty HTTP function; to be refactored later. Options are:
Manage tm-http-request events. Options are:
wiki - the wiki object to use
*/
function HttpClient(options) {
options = options || {};
}
HttpClient.prototype.handleHttpRequest = function(event) {
console.log("Initiating an HTTP request",event)
var self = this,
wiki = event.widget.wiki,
paramObject = event.paramObject || {},
url = paramObject.url,
completionActions = paramObject.oncompletion || "",
progressActions = paramObject.onprogress || "",
bindStatus = paramObject["bind-status"],
bindProgress = paramObject["bind-progress"],
method = paramObject.method || "GET",
HEADER_PARAMETER_PREFIX = "header-",
QUERY_PARAMETER_PREFIX = "query-",
PASSWORD_HEADER_PARAMETER_PREFIX = "password-header-",
PASSWORD_QUERY_PARAMETER_PREFIX = "password-query-",
CONTEXT_VARIABLE_PARAMETER_PREFIX = "var-",
requestHeaders = {},
contextVariables = {},
setBinding = function(title,text) {
if(title) {
wiki.addTiddler(new $tw.Tiddler({title: title, text: text}));
}
};
if(url) {
setBinding(bindStatus,"pending");
setBinding(bindProgress,"0");
$tw.utils.each(paramObject,function(value,name) {
// Look for query- parameters
if(name.substr(0,QUERY_PARAMETER_PREFIX.length) === QUERY_PARAMETER_PREFIX) {
url = $tw.utils.setQueryStringParameter(url,name.substr(QUERY_PARAMETER_PREFIX.length),value);
}
// Look for header- parameters
if(name.substr(0,HEADER_PARAMETER_PREFIX.length) === HEADER_PARAMETER_PREFIX) {
requestHeaders[name.substr(HEADER_PARAMETER_PREFIX.length)] = value;
}
// Look for password-header- parameters
if(name.substr(0,PASSWORD_QUERY_PARAMETER_PREFIX.length) === PASSWORD_QUERY_PARAMETER_PREFIX) {
url = $tw.utils.setQueryStringParameter(url,name.substr(PASSWORD_QUERY_PARAMETER_PREFIX.length),$tw.utils.getPassword(value) || "");
}
// Look for password-query- parameters
if(name.substr(0,PASSWORD_HEADER_PARAMETER_PREFIX.length) === PASSWORD_HEADER_PARAMETER_PREFIX) {
requestHeaders[name.substr(PASSWORD_HEADER_PARAMETER_PREFIX.length)] = $tw.utils.getPassword(value) || "";
}
// Look for var- parameters
if(name.substr(0,CONTEXT_VARIABLE_PARAMETER_PREFIX.length) === CONTEXT_VARIABLE_PARAMETER_PREFIX) {
contextVariables[name.substr(CONTEXT_VARIABLE_PARAMETER_PREFIX.length)] = value;
}
});
// Set the request tracker tiddler
var requestTrackerTitle = wiki.generateNewTitle("$:/temp/HttpRequest");
wiki.addTiddler({
title: requestTrackerTitle,
tags: "$:/tags/HttpRequest",
text: JSON.stringify({
url: url,
type: method,
status: "inprogress",
headers: requestHeaders,
data: paramObject.body
})
});
$tw.utils.httpRequest({
url: url,
type: method,
headers: requestHeaders,
data: paramObject.body,
callback: function(err,data,xhr) {
var success = (xhr.status >= 200 && xhr.status < 300) ? "complete" : "error",
headers = {};
$tw.utils.each(xhr.getAllResponseHeaders().split("\r\n"),function(line) {
var pos = line.indexOf(":");
if(pos !== -1) {
headers[line.substr(0,pos)] = line.substr(pos + 1).trim();
}
});
setBinding(bindStatus,success);
setBinding(bindProgress,"100");
var results = {
status: xhr.status.toString(),
statusText: xhr.statusText,
error: (err || "").toString(),
data: (data || "").toString(),
headers: JSON.stringify(headers)
};
// Update the request tracker tiddler
wiki.addTiddler(new $tw.Tiddler(wiki.getTiddler(requestTrackerTitle),{
status: success,
}));
wiki.invokeActionString(completionActions,undefined,$tw.utils.extend({},contextVariables,results),{parentWidget: $tw.rootWidget});
// console.log("Back!",err,data,xhr);
},
progress: function(lengthComputable,loaded,total) {
if(lengthComputable) {
setBinding(bindProgress,"" + Math.floor((loaded/total) * 100))
}
wiki.invokeActionString(progressActions,undefined,{
lengthComputable: lengthComputable ? "yes" : "no",
loaded: loaded,
total: total
},{parentWidget: $tw.rootWidget});
}
});
}
};
exports.HttpClient = HttpClient;
/*
Make an HTTP request. Options are:
url: URL to retrieve
headers: hashmap of headers to send
type: GET, PUT, POST etc
callback: function invoked with (err,data,xhr)
progress: optional function invoked with (lengthComputable,loaded,total)
returnProp: string name of the property to return as first argument of callback
*/
exports.httpRequest = function(options) {
@ -83,8 +199,16 @@ exports.httpRequest = function(options) {
options.callback($tw.language.getString("Error/XMLHttpRequest") + ": " + this.status,null,this);
}
};
// Handle progress
if(options.progress) {
request.onprogress = function(event) {
console.log("Progress event",event)
options.progress(event.lengthComputable,event.loaded,event.total);
};
}
// Make the request
request.open(type,url,true);
// Headers
if(headers) {
$tw.utils.each(headers,function(header,headerTitle,object) {
request.setRequestHeader(headerTitle,header);
@ -96,6 +220,7 @@ exports.httpRequest = function(options) {
if(!hasHeader("X-Requested-With") && !isSimpleRequest(type,headers)) {
request.setRequestHeader("X-Requested-With","TiddlyWiki");
}
// Send data
try {
request.send(data);
} catch(e) {
@ -104,4 +229,19 @@ exports.httpRequest = function(options) {
return request;
};
exports.setQueryStringParameter = function(url,paramName,paramValue) {
var URL = $tw.browser ? window.URL : require("url").URL,
newUrl;
try {
newUrl = new URL(url);
} catch(e) {
}
if(newUrl && paramName) {
newUrl.searchParams.set(paramName,paramValue || "");
return newUrl.toString();
} else {
return url;
}
};
})();

View File

@ -1415,6 +1415,14 @@ exports.checkTiddlerText = function(title,targetText,options) {
return text === targetText;
}
/*
Execute an action string without an associated context widget
*/
exports.invokeActionString = function(actions,event,variables,options) {
var widget = this.makeWidget(null,{parentWidget: options.parentWidget});
widget.invokeActionString(actions,null,event,variables);
};
/*
Read an array of browser File objects, invoking callback(tiddlerFieldsArray) once they're all read
*/

View File

@ -0,0 +1,112 @@
title: WidgetMessage: tm-http-request Example - Zotero
tags: $:/tags/Macro
\procedure select-zotero-group()
Specify the Zotero group ID to import
<$edit-text tiddler="$:/config/zotero-group" tag="input"/> or
<$select tiddler="$:/config/zotero-group">
<option value="4813312">com216</option>
<option value="4913310">pos252</option>
<option value="4747244">idt575</option>
</$select>
\end
\procedure zotero-save-item(item)
<$action-createtiddler
$basetitle={{{ =[[_zotero_import ]] =[<item>jsonget[key]] =[[ ]] =[<item>jsonget[title]] +[join[]] }}}
text={{{ [<item>jsonget[title]] }}}
tags="$:/tags/ZoteroImport"
>
<$action-setmultiplefields $tiddler=<<createTiddler-title>> $fields="[<item>jsonindexes[]addprefix[zotero-]]" $values="[<item>jsonindexes[]] :map[<item>jsonget<currentTiddler>else[.XXXXX.]]"/>
<$list filter="[<item>jsonindexes[creators]]" variable="creatorIndex">
<$action-setmultiplefields $tiddler=<<createTiddler-title>> $fields="[<item>jsonget[creators],<creatorIndex>,[creatorType]addprefix[zotero-]]" $values="[<item>jsonget[creators],<creatorIndex>,[lastName]] [<item>jsonget[creators],<creatorIndex>,[firstName]] +[join[, ]] :else[<item>jsonget[creators],<creatorIndex>,[name]] "/>
</$list>
</$action-createtiddler>
\end zotero-save-item
\procedure zotero-save-items(data)
<$list filter="[<data>jsonindexes[]] :map[<data>jsonextract<currentTiddler>,[data]]" variable="item">
<$macrocall $name="zotero-save-item" item=<<item>>/>
</$list>
\end zotero-save-items
\procedure zotero-get-items(start:"0",limit:"25")
\procedure completion()
\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]
<$action-log msg="In completion"/>
<$action-log/>
<!-- Success -->
<$list filter="[<status>compare:number:gteq[200]compare:number:lteq[299]]" variable="ignore">
<!-- Import these items -->
<$macrocall $name="zotero-save-items" data=<<data>>/>
<!-- Check if there are any more items to download -->
<$list filter="[<headers>jsonget[total-results]subtract<start>subtract<limit>compare:number:gt[0]]" variable="ignore">
<$macrocall $name="zotero-get-items" start={{{ [<start>add<limit>] }}} limit=<<limit>>/>
</$list>
</$list>
\end completion
\procedure progress()
\import [[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]
<$action-log message="In progress-actions"/>
\end progress
\procedure request-url()
\rules only transcludeinline transcludeblock filteredtranscludeinline filteredtranscludeblock
https://api.zotero.org/groups/{{$:/config/zotero-group}}/items/
\end request-url
<$wikify name="url" text=<<request-url>>>
<$action-sendmessage
$message="tm-http-request"
url=<<url>>
method="GET"
query-format="json"
query-sort="title"
query-start=<<start>>
query-limit=<<limit>>
header-accept="application/json"
bind-status="$:/temp/zotero/status"
bind-progress="$:/temp/zotero/progress"
oncompletion=<<completion>>
onprogress=<<progress>>
var-start=<<start>>
var-limit=<<limit>>
/>
</$wikify>
\end
\procedure zotero-actions()
<$macrocall $name="zotero-get-items" start="0" limit="50"/>
\end
<<select-zotero-group>>
<$button actions=<<zotero-actions>>>
Start import from Zotero group
</$button>
<$list filter="[tag[$:/tags/ZoteroImport]limit[1]]" variable="ignore">
!! Imported Tiddlers
<$button>
<$action-deletetiddler $filter="[tag[$:/tags/ZoteroImport]]"/>
Delete these tiddlers
</$button>
Export: <$macrocall $name="exportButton" exportFilter="[tag[$:/tags/ZoteroImport]]" lingoBase="$:/language/Buttons/ExportTiddlers/"/>
</$list>
<ol>
<$list filter="[tag[$:/tags/ZoteroImport]]">
<li>
<$link>
<$view field="title"/>
</$link>
</li>
</$list>
</ol>

View File

@ -0,0 +1,49 @@
caption: tm-http-request
created: 20230429161453032
modified: 20230429161453032
tags: Messages
title: WidgetMessage: tm-http-request
type: text/vnd.tiddlywiki
The ''tm-http-request'' message is used to make an HTTP request to a server.
It uses the following properties on the `event` object:
|!Name |!Description |
|param |Not used |
|paramObject |Hashmap of parameters (see below) |
The following parameters are used:
|!Name |!Description |
|method |HTTP method (eg "GET", "POST") |
|body |String data to be sent with the request |
|query-* |Query string parameters with string values |
|header-* |Headers with string values |
|password-header-* |Headers with values taken from the password store |
|password-query-* |Query string parameters with values taken from the password store |
|var-* |Variables to be passed to the completion and progress handlers (without the "var-" prefix) |
|bind-status |Title of tiddler to which the status of the request ("pending", "complete", "error") should be bound |
|bind-progress |Title of tiddler to which the progress of the request (0 to 100) should be bound |
|oncompletion |Action strings to be executed when the request completes |
|onprogress |Action strings to be executed when progress is reported |
The following variables are passed to the completion handler:
|!Name |!Description |
|status |HTTP result status code (see [[MDN|https://developer.mozilla.org/en-US/docs/Web/HTTP/Status]]) |
|statusText |HTTP result status text |
|error |Error string |
|data |Returned data |
|headers |Response headers as a JSON object |
The following variables are passed to the progress handler:
|!Name |!Description |
|lengthComputable |Whether the progress loaded and total figures are valid - "yes" or "no" |
|loaded |Number of bytes loaded so far |
|total |Total number bytes to be loaded |
!! Examples
* [[Zotero's|https://www.zotero.org/]] API for retrieving reference items: [[WidgetMessage: tm-http-request Example - Zotero]]

View File

@ -0,0 +1,2 @@
title: $:/config/zotero-group
text: 4813312