Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
open-source
SemWeb
libview
Commits
ef6bafcc57c1
Commit
3dabfc86
authored
Aug 10, 2018
by
Laurent Wouters
Browse files
Refactoring the extension
parent
5d2d0b2149e4
Changes
16
Hide whitespace changes
Inline
Side-by-side
extension/package.json
View file @
ef6bafcc
...
...
@@ -36,7 +36,6 @@
"@types/react-dom"
:
"^16.0.6"
,
"awesome-typescript-loader"
:
"^5.2.0"
,
"copy-webpack-plugin"
:
"^4.5.2"
,
"html-webpack-plugin"
:
"^3.0.0"
,
"source-map-loader"
:
"^0.2.3"
,
"typescript"
:
"^2.9.2"
,
"web-ext"
:
"^2.7.0"
,
...
...
extension/
src/
popup/index.html
→
extension/popup/index.html
View file @
ef6bafcc
File moved
extension/
src/
popup/main.css
→
extension/popup/main.css
View file @
ef6bafcc
File moved
extension/
src/
popup/main.tsx
→
extension/popup/main.tsx
View file @
ef6bafcc
File moved
extension/src/background/main.ts
View file @
ef6bafcc
...
...
@@ -31,10 +31,13 @@ import {
MimeInfo
,
refersToPrimaryTopic
,
refersToData
,
TabRegistry
,
resolveTabData
ObservedResourceRegistry
,
resolveObservationsForTab
,
selectDataSource
,
hasDetectedData
,
ResourceObservedData
}
from
"
../common/data
"
;
import
{
Message
,
updateTab
,
navigateTabTo
}
from
"
../common/messages
"
;
import
{
Message
}
from
"
../common/messages
"
;
/// <reference path="./fallback.d.ts"/>
let
F
=
require
(
"
./fallback
"
);
import
"
chrome
"
;
...
...
@@ -47,7 +50,7 @@ import {
/**
* The data about the tabs
*/
let
all
Tabs
:
Tab
Registry
=
{};
let
all
Observations
:
ObservedResource
Registry
=
{};
/**
* The reference view registry
*/
...
...
@@ -64,60 +67,18 @@ reloadRegistryFromStorage(registry)
});
/**
*
Updates a tab
*
When the observed data about a tab has been updated
* @param id The identifier of a tab
*/
function
onTabUpdated
(
tabId
:
number
):
void
{
updateTabIcon
(
tabId
);
updateTab
(
tabId
,
resolveTabData
(
allTabs
,
tabId
));
}
/**
* Updates the icon of a tab
* @param id The identifier of a tab
*/
function
updateTabIcon
(
tabId
:
number
):
void
{
let
data
=
resolveTabData
(
allTabs
,
tabId
);
chrome
.
browserAction
.
setIcon
({
path
:
data
.
command
.
isActive
?
{
48
:
"
icons/app.png
"
}
:
{
48
:
"
icons/app_disabled.png
"
},
tabId
:
tabId
});
chrome
.
browserAction
.
setBadgeBackgroundColor
({
color
:
[
217
,
0
,
0
,
255
],
tabId
:
tabId
});
var
badge
=
""
;
if
(
data
.
mainSource
!=
NO_DATA
)
badge
+=
"
\
u2605
"
;
if
(
data
.
primaryTopic
!=
null
)
badge
+=
"
\
u2605
"
;
chrome
.
browserAction
.
setBadgeText
({
text
:
badge
,
tabId
:
tabId
});
}
/**
* When a tab has been activated
* @param tabId The identifier of a tab
*/
function
onTabActivated
(
tabId
:
number
):
void
{
updateTabIcon
(
tabId
);
function
onObservedTabUpdated
(
tabId
:
number
):
void
{
let
observation
=
resolveObservationsForTab
(
allObservations
,
tabId
);
if
(
hasDetectedData
(
observation
))
{
chrome
.
pageAction
.
show
(
tabId
);
}
else
{
chrome
.
pageAction
.
hide
(
tabId
);
}
}
// listen to tab URL changes
chrome
.
tabs
.
onUpdated
.
addListener
(
function
(
tabId
,
changeInfo
,
tab
)
{
onTabActivated
(
tabId
);
});
// listen to tab switching
chrome
.
tabs
.
onActivated
.
addListener
(
function
(
activeInfo
)
{
onTabActivated
(
activeInfo
.
tabId
);
});
/**
* Parses the tags for a link
* @param content The link description
...
...
@@ -269,10 +230,8 @@ function doPreempt(
):
chrome
.
webRequest
.
BlockingResponse
{
let
headers
=
details
.
responseHeaders
;
setHeader
(
headers
,
"
Content-Type
"
,
"
text/plain
"
);
let
data
=
resolve
TabData
(
allTab
s
,
details
.
tabId
);
let
data
=
resolve
ObservationsForTab
(
allObservation
s
,
details
.
tabId
);
data
.
sources
.
push
(
new
DataSourcePage
(
details
.
url
,
mime
.
mime
));
data
.
command
.
isActive
=
true
;
// activate by default
data
.
selectMain
();
return
{
responseHeaders
:
headers
};
}
...
...
@@ -292,6 +251,7 @@ function onHeadersReceived(
details
.
type
!=
"
main_frame
"
// not the top-level document
)
return
{};
let
index
=
details
.
url
.
indexOf
(
"
?protocol=ldviews&uri=
"
);
if
(
index
>=
0
)
{
// preempts the protocol ldviews
...
...
@@ -303,37 +263,38 @@ function onHeadersReceived(
redirectUrl
:
chrome
.
extension
.
getURL
(
"
ldviews/index.html
"
)
+
"
?uri=
"
+
uri
};
}
let
data
=
resolveTabData
(
allTabs
,
details
.
tabId
);
if
(
data
.
mainSource
!=
NO_DATA
)
// already detected something
return
{};
let
observation
=
resolveObservationsForTab
(
allObservations
,
details
.
tabId
);
observation
.
url
=
details
.
url
;
// try to detect the primary topic in HTTP headers' links
let
links
=
getAllLinks
(
details
.
responseHeaders
);
data
.
primaryTopic
=
detectTopicOnlinks
(
links
);
if
(
observation
.
primaryTopic
==
""
)
observation
.
primaryTopic
=
detectTopicOnlinks
(
links
);
// determine if we shall preempt the content due to its type (raw RDF data)
let
mime
=
shouldPreempt
(
details
);
/*
let mime = shouldPreempt(details);
if (mime != null) {
// preempts this request
return doPreempt(details, mime);
}
}
*/
// try to detect alternate sources of content
data
.
sources
.
push
(
detectDataOnContent
(
details
,
details
.
responseHeaders
));
data
.
sources
=
data
.
sources
.
concat
(
detectDataOnLinks
(
links
));
data
.
selectMain
();
observation
.
sources
.
push
(
detectDataOnContent
(
details
,
details
.
responseHeaders
)
);
observation
.
sources
=
observation
.
sources
.
concat
(
detectDataOnLinks
(
links
));
// if there are still nothing, try to probe with HTTP content negotiation
if
(
data
.
mainSource
==
NO_DATA
)
{
if
(
!
hasDetectedData
(
observation
)
)
{
tryNegotiateData
(
details
.
url
)
.
then
((
source
:
DataSourceLinked
)
=>
{
data
.
sources
.
push
(
source
);
data
.
selectMain
();
onTabUpdated
(
details
.
tabId
);
observation
.
sources
.
push
(
source
);
onObservedTabUpdated
(
details
.
tabId
);
})
.
catch
((
reason
:
string
)
=>
{
// do nothing
onObservedTabUpdated
(
details
.
tabId
);
});
}
else
{
onObservedTabUpdated
(
details
.
tabId
);
}
updateTabIcon
(
details
.
tabId
);
return
{};
}
...
...
@@ -345,10 +306,10 @@ function onBeforeNavigate(
details
:
chrome
.
webNavigation
.
WebNavigationFramedCallbackDetails
):
void
{
if
(
details
.
tabId
==
-
1
||
details
.
frameId
!=
0
)
return
;
let
data
=
resolveTabData
(
allTabs
,
details
.
tabId
);
data
.
clear
()
;
data
.
url
=
details
.
url
;
updateTabIcon
(
details
.
tabId
);
let
observation
=
new
ResourceObservedData
(
);
observation
.
url
=
details
.
url
;
allObservations
[
details
.
tabId
]
=
observation
;
chrome
.
pageAction
.
hide
(
details
.
tabId
);
}
/**
...
...
@@ -359,7 +320,7 @@ function onCompleted(
details
:
chrome
.
webNavigation
.
WebNavigationFramedCallbackDetails
):
void
{
if
(
details
.
tabId
==
-
1
||
details
.
frameId
!=
0
)
return
;
onTabUpdated
(
details
.
tabId
);
on
Observed
TabUpdated
(
details
.
tabId
);
}
// listen to received headers
...
...
@@ -374,31 +335,25 @@ F.registerNavigations(onBeforeNavigate, onCompleted);
chrome
.
runtime
.
onMessage
.
addListener
(
(
request
:
Message
<
any
>
,
sender
,
sendResponse
)
=>
{
if
(
request
.
requestType
==
"
SubmitHtmlLinks
"
)
{
let
data
=
resolveTabData
(
allTabs
,
sender
.
tab
.
id
);
if
(
data
.
primaryTopic
==
null
)
{
data
.
primaryTopic
=
detectTopicOnlinks
(
request
.
payload
);
let
observation
=
resolveObservationsForTab
(
allObservations
,
sender
.
tab
.
id
);
if
(
observation
.
primaryTopic
==
null
||
observation
.
primaryTopic
==
""
)
{
observation
.
primaryTopic
=
detectTopicOnlinks
(
request
.
payload
);
}
data
.
sources
=
data
.
sources
.
concat
(
detectDataOnLinks
(
request
.
payload
));
data
.
selectMain
();
onTabUpdated
(
sender
.
tab
.
id
);
}
else
if
(
request
.
requestType
==
"
GetTabId
"
)
{
sendResponse
(
sender
.
tab
.
id
);
}
else
if
(
request
.
requestType
==
"
GetTabData
"
)
{
observation
.
sources
=
observation
.
sources
.
concat
(
detectDataOnLinks
(
request
.
payload
)
);
onObservedTabUpdated
(
sender
.
tab
.
id
);
}
else
if
(
request
.
requestType
==
"
GetObservations
"
)
{
let
tabId
=
request
.
payload
;
if
(
tabId
==
null
||
tabId
==
undefined
)
{
// deduce from the sender
tabId
=
sender
.
tab
.
id
;
}
let
data
=
resolveTabData
(
allTabs
,
tabId
);
sendResponse
(
data
);
}
else
if
(
request
.
requestType
==
"
SetTabData
"
)
{
let
data
=
resolveTabData
(
allTabs
,
request
.
payload
.
tabId
);
data
.
updateWith
(
request
.
payload
.
tabData
);
onTabUpdated
(
request
.
payload
.
tabId
);
sendResponse
(
data
);
}
else
if
(
request
.
requestType
==
"
NavigateTo
"
)
{
// trampoline the request back to the tab
navigateTabTo
(
request
.
payload
.
tabId
,
request
.
payload
.
uri
);
let
observation
=
resolveObservationsForTab
(
allObservations
,
tabId
);
sendResponse
(
observation
);
}
else
if
(
request
.
requestType
==
"
GetViewRegistry
"
)
{
sendResponse
(
registry
);
}
else
if
(
request
.
requestType
==
"
AddNewSource
"
)
{
...
...
@@ -442,3 +397,24 @@ chrome.runtime.onMessage.addListener(
}
}
);
chrome
.
pageAction
.
onClicked
.
addListener
((
tab
:
chrome
.
tabs
.
Tab
)
=>
{
let
observation
=
resolveObservationsForTab
(
allObservations
,
tab
.
id
);
let
url
=
chrome
.
extension
.
getURL
(
"
ldbrowser/index.html
"
);
let
callback
=
(
openedTab
:
chrome
.
tabs
.
Tab
)
=>
{
allObservations
[
openedTab
.
id
]
=
observation
;
};
let
promise
:
any
=
chrome
.
tabs
.
create
(
{
windowId
:
tab
.
windowId
,
index
:
tab
.
index
+
1
,
url
:
url
,
active
:
true
,
openerTabId
:
tab
.
id
},
callback
);
if
(
promise
!=
undefined
&&
promise
!=
null
)
{
promise
.
then
(
callback
);
}
});
extension/src/common/data.ts
View file @
ef6bafcc
...
...
@@ -315,137 +315,150 @@ function compareSources(x: DataSource, y: DataSource): number {
export
const
NO_DATA
=
new
DataSourceNone
();
/**
* The
u
ser
command for a tab
* The
ob
ser
ved data about a web resource
*/
export
class
TabCommand
{
export
class
ResourceObservedData
{
constructor
()
{
this
.
isActive
=
false
;
this
.
isAutomatic
=
true
;
this
.
selectedSource
=
""
;
this
.
selectedView
=
""
;
this
.
selectedLanguage
=
application
.
NO_LANGUAGE
;
this
.
url
=
""
;
this
.
sources
=
[];
this
.
primaryTopic
=
""
;
}
/**
* Whether the user activated the extension for this tab
*/
isActive
:
boolean
;
/**
* Whether the user is using automatic selection of data sources and views
* The resource's url
*/
isAutomatic
:
boolean
;
/**
* The identifier of the selected data source (if not automatic)
*/
selectedSource
:
string
;
url
:
string
;
/**
*
The identifier of the selected view (if not automatic)
*
All the alternative data sources
*/
s
electedView
:
string
;
s
ources
:
DataSource
[]
;
/**
* The
sel
ected
language (if not automatic)
* The
det
ected
primary topic if any
*/
selectedLanguage
:
application
.
Language
;
primaryTopic
:
string
;
}
/**
* Updates this command with the specified one
* @param command The updated command
*/
updateWith
(
command
:
TabCommand
)
{
this
.
isActive
=
command
.
isActive
;
this
.
isAutomatic
=
command
.
isAutomatic
;
this
.
selectedSource
=
command
.
selectedSource
;
this
.
selectedView
=
command
.
selectedView
;
this
.
selectedLanguage
=
command
.
selectedLanguage
;
}
/**
* Gets whether data has been detected
* @param observation The current observation
*/
export
function
hasDetectedData
(
observation
:
ResourceObservedData
):
boolean
{
let
main
=
observation
.
sources
.
find
(
(
source
:
DataSource
)
=>
source
!=
NO_DATA
);
return
main
!=
undefined
&&
main
!=
null
&&
main
!=
NO_DATA
;
}
/**
*
Data about a tab
*
The user command for a specific resource for the linked data browser
*/
export
class
TabData
{
export
class
ResourceUserCommand
{
constructor
()
{
this
.
command
=
new
TabCommand
()
;
this
.
main
Source
=
NO_DATA
;
this
.
s
ources
=
[]
;
this
.
primaryTopic
=
null
;
this
.
url
=
null
;
this
.
isAutomatic
=
true
;
this
.
selected
Source
=
""
;
this
.
s
electedTopic
=
""
;
this
.
selectedView
=
""
;
this
.
selectedLanguage
=
application
.
NO_LANGUAGE
;
}
/**
*
T
he
user
command
for this tab
*
W
he
ther the
command
use the defaults
*/
command
:
TabComm
an
d
;
isAutomatic
:
boole
an
;
/**
* The
data associated to this tab
* The
identifier of the user-selected data source
*/
mainSource
:
DataSource
;
selectedSource
:
string
;
/**
*
All the alternative data sources
*
The URI of the user-selected topic, if any
*/
s
ources
:
DataSource
[]
;
s
electedTopic
:
string
;
/**
* The
primary topic
o
n
th
is tab
* The
identifier
o
f
th
e user-selected view
*/
primaryTopic
:
string
;
selectedView
:
string
;
/**
* The
current url for the tab
* The
user-selected language
*/
url
:
string
;
selectedLanguage
:
application
.
Language
;
}
/**
* The data about a resource for the linked data browser
*/
export
class
ResourceData
{
/**
* Updates this data with the specified one
* @param data The updated data
* The observed data
*/
updateWith
(
data
:
TabData
)
{
this
.
command
.
updateWith
(
data
.
command
);
this
.
selectMain
();
}
observations
:
ResourceObservedData
;
/**
*
Clears this data
*
The associated user command
*/
clear
():
void
{
this
.
command
.
isAutomatic
=
true
;
this
.
command
.
selectedSource
=
""
;
this
.
command
.
selectedView
=
""
;
this
.
command
.
selectedLanguage
=
application
.
NO_LANGUAGE
;
this
.
mainSource
=
NO_DATA
;
this
.
sources
=
[];
this
.
primaryTopic
=
null
;
command
:
ResourceUserCommand
;
}
/**
* Selects the main resource among the provided one
* @param resource The current data about a resource
*/
export
function
selectDataSource
(
resource
:
ResourceData
):
DataSource
{
if
(
resource
.
command
.
isAutomatic
||
resource
.
command
.
selectedSource
==
null
||
resource
.
command
.
selectedSource
==
""
)
{
if
(
resource
.
observations
.
sources
.
length
==
0
)
{
return
NO_DATA
;
}
let
sources
=
resource
.
observations
.
sources
.
filter
((
source
:
DataSource
)
=>
{
return
source
!=
NO_DATA
;
})
.
sort
(
compareSources
);
return
sources
.
length
==
0
?
NO_DATA
:
sources
[
0
];
}
else
{
let
source
=
resource
.
observations
.
sources
.
find
(
(
source
:
DataSource
)
=>
source
.
url
==
resource
.
command
.
selectedSource
);
return
source
!=
null
&&
source
!=
undefined
?
source
:
NO_DATA
;
}
}
/**
* Selects the relevant primay topic
* @param resource The current data about a resource
*/
export
function
selectPrimaryTopic
(
resource
:
ResourceData
):
string
{
if
(
resource
.
command
.
isAutomatic
||
resource
.
command
.
selectedTopic
==
null
||
resource
.
command
.
selectedTopic
==
""
)
{
return
resource
.
observations
.
primaryTopic
;
}
else
{
return
resource
.
command
.
selectedTopic
;
}
}
/**
* The data of an LD browser
*/
export
class
LDBrowserData
{
constructor
(
observation
:
ResourceObservedData
)
{
let
init
=
new
ResourceData
();
init
.
observations
=
observation
;
init
.
command
=
new
ResourceUserCommand
();
this
.
history
=
[
init
];
this
.
byResource
=
{};
this
.
byResource
[
observation
.
url
]
=
init
;
}
/**
*
Selects the main resource among the provided one
*
The history of resources
*/
selectMain
():
DataSource
{
if
(
this
.
command
.
isAutomatic
||
this
.
command
.
selectedSource
==
null
||
this
.
command
.
selectedSource
==
""
)
{
if
(
this
.
sources
.
length
==
0
)
{
this
.
mainSource
=
NO_DATA
;
}
else
{
this
.
sources
=
this
.
sources
.
filter
((
source
:
DataSource
)
=>
{
return
source
!=
NO_DATA
;
})
.
sort
(
compareSources
);
this
.
mainSource
=
this
.
sources
.
length
==
0
?
NO_DATA
:
this
.
sources
[
0
];
}
}
else
{
this
.
mainSource
=
this
.
sources
.
reduce
(
(
acc
:
DataSource
,
current
:
DataSource
)
=>
{
if
(
acc
!=
null
)
return
acc
;
if
(
current
.
url
==
this
.
command
.
selectedSource
)
return
current
;
return
null
;
},
null
);
if
(
this
.
mainSource
==
null
)
this
.
mainSource
=
NO_DATA
;
}
return
this
.
mainSource
;
}
history
:
ResourceData
[];
/**
* The data for each known resource
*/
byResource
:
{
[
url
:
string
]:
ResourceData
};
}
/**
...
...
@@ -488,20 +501,23 @@ export function tryNegotiateData(target: string): Promise<DataSourceLinked> {
}
/**
* A registry
of tab
data
* A registry
for observed
data
*/
export
interface
Tab
Registry
{
[
index
:
number
]:
Tab
Data
;
export
interface
ObservedResource
Registry
{
[
index
:
number
]:
ResourceObserved
Data
;
}
/**
* Gets the
data about
a tab
* Gets the
observed data for
a tab
* @param registry The registry of tab data
* @param id The identifier of a tab
*/
export
function
resolveTabData
(
registry
:
TabRegistry
,
id
:
number
):
TabData
{
export
function
resolveObservationsForTab
(
registry
:
ObservedResourceRegistry
,
id
:
number
):
ResourceObservedData
{
if
(
!
registry
.
hasOwnProperty
(
id
))
{
registry
[
id
]
=
new
Tab
Data
();
registry
[
id
]
=
new
ResourceObserved
Data
();
}
return
registry
[
id
];
}
extension/src/common/messages.ts
View file @
ef6bafcc
...
...
@@ -18,7 +18,7 @@
* with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
import
{
Tab
Data
}
from
"
./data
"
;
import
{
ResourceObserved
Data
}
from
"
./data
"
;
import
{
definition
}
from
"
@logilab/libview
"
;
import
"
chrome
"
;
...
...
@@ -153,130 +153,24 @@ export function getResourceContent(
}
/**
* Gets the identifier of the current tab from the background
*/
export
function
getTabId
():
Promise
<
number
>
{
return
new
Promise
<
number
>
(
(
resolve
:
(
tabId
:
number
)
=>
void
,
reject
:
(
reason
:
any
)
=>
void
)
=>
{
chrome
.
runtime
.
sendMessage
(
{
requestType
:
"
GetTabId
"
,
payload
:
null
},
(
tabId
:
number
)
=>
{
resolve
(
tabId
);
}
);
}
);
}
/**
* Gets data about the current tab to the background
* Gets the observations about a tab
* @param tabId The corresponding tab number
*/
export
function
getTabData
(
tabId
:
number
):
Promise
<
TabData
>
{
return
new
Promise
<
TabData
>
(
(
resolve
:
(
tabData
:
TabData
)
=>
void
,
reject
:
(
reason
:
any
)
=>
void
)
=>
{
export
function
getObservationsFor
(
tabId
:
number
):
Promise
<
ResourceObservedData
>
{
return
new
Promise
<
ResourceObservedData
>
(
(
resolve
:
(
data
:
ResourceObservedData
)
=>
void
,
reject
:
(
reason
:
any
)
=>
void
)
=>
{
chrome
.
runtime
.
sendMessage
(
{
requestType
:
"
Get
TabData
"
,
requestType
:
"
Get
Observations
"
,
payload
:
tabId
},