Introduce info mechanism

We expose browser information as shadow tiddlers so that wiki
applications can adapt to available features.
This commit is contained in:
Jermolene 2014-07-20 18:07:30 +01:00
parent 9ddff6d8c0
commit b4d47858e5
5 changed files with 437 additions and 0 deletions

View File

@ -0,0 +1,239 @@
/*!
* Bowser - a browser detector
* https://github.com/ded/bowser
* MIT License | (c) Dustin Diaz 2014
*/
!function (name, definition) {
if (typeof module != 'undefined' && module.exports) module.exports['browser'] = definition()
else if (typeof define == 'function') define(definition)
else this[name] = definition()
}('bowser', function () {
/**
* See useragents.js for examples of navigator.userAgent
*/
var t = true
function detect(ua) {
function getFirstMatch(regex) {
var match = ua.match(regex);
return (match && match.length > 1 && match[1]) || '';
}
var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase()
, likeAndroid = /like android/i.test(ua)
, android = !likeAndroid && /android/i.test(ua)
, versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i)
, tablet = /tablet/i.test(ua)
, mobile = !tablet && /[^-]mobi/i.test(ua)
, result
if (/opera|opr/i.test(ua)) {
result = {
name: 'Opera'
, opera: t
, version: versionIdentifier || getFirstMatch(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)
}
}
else if (/windows phone/i.test(ua)) {
result = {
name: 'Windows Phone'
, windowsphone: t
, msie: t
, version: getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i)
}
}
else if (/msie|trident/i.test(ua)) {
result = {
name: 'Internet Explorer'
, msie: t
, version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i)
}
}
else if (/chrome|crios|crmo/i.test(ua)) {
result = {
name: 'Chrome'
, chrome: t
, version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
}
}
else if (iosdevice) {
result = {
name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod'
}
// WTF: version is not part of user agent in web apps
if (versionIdentifier) {
result.version = versionIdentifier
}
}
else if (/sailfish/i.test(ua)) {
result = {
name: 'Sailfish'
, sailfish: t
, version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i)
}
}
else if (/seamonkey\//i.test(ua)) {
result = {
name: 'SeaMonkey'
, seamonkey: t
, version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i)
}
}
else if (/firefox|iceweasel/i.test(ua)) {
result = {
name: 'Firefox'
, firefox: t
, version: getFirstMatch(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)
}
if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) {
result.firefoxos = t
}
}
else if (/silk/i.test(ua)) {
result = {
name: 'Amazon Silk'
, silk: t
, version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i)
}
}
else if (android) {
result = {
name: 'Android'
, version: versionIdentifier
}
}
else if (/phantom/i.test(ua)) {
result = {
name: 'PhantomJS'
, phantom: t
, version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i)
}
}
else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) {
result = {
name: 'BlackBerry'
, blackberry: t
, version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
}
}
else if (/(web|hpw)os/i.test(ua)) {
result = {
name: 'WebOS'
, webos: t
, version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
};
/touchpad\//i.test(ua) && (result.touchpad = t)
}
else if (/bada/i.test(ua)) {
result = {
name: 'Bada'
, bada: t
, version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i)
};
}
else if (/tizen/i.test(ua)) {
result = {
name: 'Tizen'
, tizen: t
, version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier
};
}
else if (/safari/i.test(ua)) {
result = {
name: 'Safari'
, safari: t
, version: versionIdentifier
}
}
else result = {}
// set webkit or gecko flag for browsers based on these engines
if (/(apple)?webkit/i.test(ua)) {
result.name = result.name || "Webkit"
result.webkit = t
if (!result.version && versionIdentifier) {
result.version = versionIdentifier
}
} else if (!result.opera && /gecko\//i.test(ua)) {
result.name = result.name || "Gecko"
result.gecko = t
result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i)
}
// set OS flags for platforms that have multiple browsers
if (android || result.silk) {
result.android = t
} else if (iosdevice) {
result[iosdevice] = t
result.ios = t
}
// OS version extraction
var osVersion = '';
if (iosdevice) {
osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i);
osVersion = osVersion.replace(/[_\s]/g, '.');
} else if (android) {
osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i);
} else if (result.windowsphone) {
osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i);
} else if (result.webos) {
osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i);
} else if (result.blackberry) {
osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i);
} else if (result.bada) {
osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i);
} else if (result.tizen) {
osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i);
}
if (osVersion) {
result.osversion = osVersion;
}
// device type extraction
var osMajorVersion = osVersion.split('.')[0];
if (tablet || iosdevice == 'ipad' || (android && (osMajorVersion == 3 || (osMajorVersion == 4 && !mobile))) || result.silk) {
result.tablet = t
} else if (mobile || iosdevice == 'iphone' || iosdevice == 'ipod' || android || result.blackberry || result.webos || result.bada) {
result.mobile = t
}
// Graded Browser Support
// http://developer.yahoo.com/yui/articles/gbs
if ((result.msie && result.version >= 10) ||
(result.chrome && result.version >= 20) ||
(result.firefox && result.version >= 20.0) ||
(result.safari && result.version >= 6) ||
(result.opera && result.version >= 10.0) ||
(result.ios && result.osversion && result.osversion.split(".")[0] >= 6)
) {
result.a = t;
}
else if ((result.msie && result.version < 10) ||
(result.chrome && result.version < 20) ||
(result.firefox && result.version < 20.0) ||
(result.safari && result.version < 6) ||
(result.opera && result.version < 10.0) ||
(result.ios && result.osversion && result.osversion.split(".")[0] < 6)
) {
result.c = t
} else result.x = t
return result
}
var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '')
/*
* Set our detect method to the main bowser object so we can
* reuse it to test other user agents.
* This is needed to implement future tests.
*/
bowser._detect = detect;
return bowser
});

View File

@ -0,0 +1,12 @@
{
"tiddlers": [
{
"file": "bowser.js",
"fields": {
"type": "application/javascript",
"title": "$:/core/modules/info/bowser/bowser.js",
"module-type": "library"
}
}
]
}

View File

@ -0,0 +1,79 @@
/*\
title: $:/core/modules/info/browser.js
type: application/javascript
module-type: info
Initialise $:/info/browser tiddlers
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.getInfoTiddlerFields = function() {
var mapBoolean = function(value) {return value ? "yes" : "no"},
infoTiddlerFields = [];
// Basics
infoTiddlerFields.push({title: "$:/info/browser", text: mapBoolean(!!$tw.browser)});
if($tw.browser) {
// Mappings from tiddler titles (prefixed with "$:/info/browser/") to bowser.browser property name
var bowser = require("$:/core/modules/info/bowser/bowser.js"),
mappings = [
["name","name","unknown"],
["version","version"],
["is/webkit","webkit"],
["is/gecko","gecko"],
["is/chrome","chrome"],
["is/firefox","firefox"],
["is/ios","ios"],
["is/iphone","iphone"],
["is/ipad","ipad"],
["is/ipod","ios"],
["is/opera","opera"],
["is/phantomjs","phantomjs"],
["is/safari","safari"],
["is/seamonkey","seamonkey"],
["is/blackberry","blackberry"],
["is/webos","webos"],
["is/silk","silk"],
["is/bada","bada"],
["is/tizen","tizen"],
["is/sailfish","sailfish"],
["is/android","android"],
["is/windowsphone","windowsphone"],
["is/firefoxos","firefoxos"]
];
$tw.utils.each(mappings,function(mapping) {
var value = bowser.browser[mapping[1]];
if(value === undefined) {
value = mapping[2];
}
if(value === undefined) {
value = false;
}
if(typeof value === "boolean") {
value = mapBoolean(value);
}
infoTiddlerFields.push({title: "$:/info/browser/" + mapping[0], text: value});
});
// Set $:/info/browser/name to the platform with some changes from Bowser
var platform = bowser.browser.name;
if("iPad iPhone iPod".split(" ").indexOf(platform) !== -1) {
platform = "iOS";
}
infoTiddlerFields.push({title: "$:/info/browser/name", text: platform});
// Non-bowser settings for TiddlyFox and TiddlyDesktop
var hasTiddlyFox = !!document.getElementById("tiddlyfox-message-box"),
isTiddlyDesktop = false; // Can't detect it until we update TiddlyDesktop to have a distinct useragent string
infoTiddlerFields.push({title: "$:/info/browser/has/tiddlyfox", text: mapBoolean(hasTiddlyFox)});
infoTiddlerFields.push({title: "$:/info/browser/is/tiddlydesktop", text: mapBoolean(isTiddlyDesktop)});
if(isTiddlyDesktop) {
infoTiddlerFields.push({title: "$:/info/browser/name", text: "TiddlyDesktop"});
}
}
return infoTiddlerFields;
};
})();

View File

@ -0,0 +1,48 @@
/*\
title: $:/core/modules/startup/info.js
type: application/javascript
module-type: startup
Initialise $:/info tiddlers via $:/temp/info-plugin pseudo-plugin
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
// Export name and synchronous status
exports.name = "info";
exports.before = ["startup"];
exports.after = ["load-modules"];
exports.synchronous = true;
exports.startup = function() {
// Collect up the info tiddlers
var infoTiddlerFields = {};
// Give each info module a chance to fill in as many info tiddlers as they want
$tw.modules.forEachModuleOfType("info",function(title,moduleExports) {
if(moduleExports && moduleExports.getInfoTiddlerFields) {
var tiddlerFieldsArray = moduleExports.getInfoTiddlerFields(infoTiddlerFields);
$tw.utils.each(tiddlerFieldsArray,function(fields) {
if(fields) {
infoTiddlerFields[fields.title] = fields;
}
});
}
});
// Bake the info tiddlers into a plugin
var fields = {
title: "$:/temp/info-plugin",
type: "application/json",
"plugin-type": "info",
text: JSON.stringify({tiddlers: infoTiddlerFields},null,$tw.config.preferences.jsonSpaces)
};
$tw.wiki.addTiddler(new $tw.Tiddler(fields));
$tw.wiki.readPluginInfo();
$tw.wiki.registerPluginTiddlers("info");
$tw.wiki.unpackPluginTiddlers();
};
})();

View File

@ -0,0 +1,59 @@
created: 20140720164948099
modified: 20140720165248031
tags: mechanism
title: InfoMechanism
type: text/vnd.tiddlywiki
System tiddlers in the namespace `$:/info/` are used to expose information about the system (including the current browser) so that WikiText applications can adapt themselves to available features.
! Information Tiddlers
|!Title |!Description |
|[[$:/info/browser]] |Running in the browser? ("yes" or "no") |
|[[$:/info/browser/has/tiddlyfox]] |Is TiddlyFox available? ("yes" or "no") |
|[[$:/info/browser/is/android]] |Running on Android? ("yes" or "no") |
|[[$:/info/browser/is/bada]] |Running on Bada? ("yes" or "no") |
|[[$:/info/browser/is/blackberry]] |Running on Blackberry? ("yes" or "no") |
|[[$:/info/browser/is/chrome]] |Running on Chrome? ("yes" or "no") |
|[[$:/info/browser/is/firefox]] |Running on Firefox? ("yes" or "no") |
|[[$:/info/browser/is/firefoxos]] |Running on Firefox OS? ("yes" or "no") |
|[[$:/info/browser/is/gecko]] |Running on Gecko? ("yes" or "no") |
|[[$:/info/browser/is/ios]] |Running on iOS (ie an iPhone, iPad or iPod)? ("yes" or "no") |
|[[$:/info/browser/is/ipad]] |Running on iPad? ("yes" or "no") |
|[[$:/info/browser/is/iphone]] |Running on iPhone? ("yes" or "no") |
|[[$:/info/browser/is/ipod]] |Running on iPod? ("yes" or "no") |
|[[$:/info/browser/is/opera]] |Running on Opera? ("yes" or "no") |
|[[$:/info/browser/is/phantomjs]] |Running on PhantomJS? ("yes" or "no") |
|[[$:/info/browser/is/safari]] |Running on Safari? ("yes" or "no") |
|[[$:/info/browser/is/sailfish]] |Running on Sailfish? ("yes" or "no") |
|[[$:/info/browser/is/seamonkey]] |Running on Sea Monkey? ("yes" or "no") |
|[[$:/info/browser/is/silk]] |Running on Amazon's Silk? ("yes" or "no") |
|[[$:/info/browser/is/tiddlydesktop]] |Running on TiddlyDesktop? ("yes" or "no") |
|[[$:/info/browser/is/tizen]] |Running on Tizen? ("yes" or "no") |
|[[$:/info/browser/is/webkit]] |Running on WebKit? ("yes" or "no") |
|[[$:/info/browser/is/webos]] |Running on WebOS? ("yes" or "no") |
|[[$:/info/browser/is/windowsphone]] |Running on Windows Phone? ("yes" or "no") |
|[[$:/info/browser/name]] |Platform name (see below) |
|[[$:/info/browser/version]] |Browser version |
The browser information is obtained with [[Bowser, a browser detector library from Dustin Diaz|https://github.com/ded/bowser/]]. Possible browser names include:
* ''"Amazon Silk"''
* ''"Android"''
* ''"Bada"''
* ''"BlackBerry"''
* ''"Chrome"''
* ''"Firefox"''
* ''"Internet Explorer"''
* ''"iOS"''
* ''"Opera"''
* ''"PhantomJS"''
* ''"Safari"''
* ''"Sailfish"''
* ''"SeaMonkey"''
* ''"TiddlyDesktop"''
* ''"Tizen"''
* ''"WebOS"''
* ''"Windows Phone"''
Note that Bowser returns "iPhone", "iPad" and "iPod" as distinct values for the name of the current browser. TiddlyWiki converts all three distinct values into "iOS" before copying to [[$:/info/browser/name]].