Skip to content

Commit 8c62b8e

Browse files
authored
Add Auto Authentication (#13)
* Move Context Menus to onChanged * Add Auto Auth * Update options.html * Update README.md
1 parent 80206f8 commit 8c62b8e

File tree

10 files changed

+161
-67
lines changed

10 files changed

+161
-67
lines changed

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,15 @@ You can pin the Addon by clicking the `Puzzle Piece`, find the `Django Files ico
5050
**Firefox**, click the `Settings Wheel` and `Pin to Toolbar`.
5151
**Chrome**, click the `Pin` icon.
5252

53-
1. Click on the `Django Files icon` and click on `Open Options`.
54-
1. Log in to your Django Files instance, and select `Copy URL` from the menu in the top right.
55-
1. Go back to the Django Files Options tab and paste the `URL` into the URL box.
56-
1. Repeat #3 and #4 for Auth Token and then click `Save Settings`!
53+
To automatically configure the web extension to work with your Django Files instance do the following:
54+
55+
- Log in to your Django Files Instance
56+
- Click the Popup Icon (from above)
57+
- Click `Add Auth from Current Site`
5758

5859
The addon should now be configured to work with your Django Files instance.
5960

60-
Click the Django Files add-on icon to view your recent uploads.
61+
You can now click the Django Files icon to view your recent uploads.
6162
Right-click on any Image, Video, Audio, or URL upload to Django Files or Shorten URL.
6263

6364
# Development

manifest.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"manifest_version": 3,
3-
"version": "0.2.3",
3+
"version": "0.2.4",
44
"name": "Django Files",
55
"description": "Django Files Web Extension designed to work with django-files/django-files.",
66
"homepage_url": "https://github.com/django-files/web-extension",
@@ -13,10 +13,15 @@
1313
"description": "Show Popup"
1414
}
1515
},
16-
"permissions": ["clipboardWrite", "contextMenus", "notifications", "storage"],
17-
"background": {
18-
"type": "module"
19-
},
16+
"permissions": [
17+
"activeTab",
18+
"clipboardWrite",
19+
"contextMenus",
20+
"notifications",
21+
"scripting",
22+
"storage"
23+
],
24+
"background": {},
2025
"options_ui": {
2126
"page": "html/options.html",
2227
"open_in_tab": true

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"scripts": {
33
"postinstall": "npx gulp",
44
"lint:eslint": "npx eslint src/js",
5-
"lint:web-ext": "npx web-ext lint --source-dir ./src/",
5+
"lint:web-ext": "npm run manifest:firefox && npx web-ext lint --source-dir ./src/",
66
"lint": "npm run lint:eslint && npm run lint:web-ext",
77
"chrome": "npm run manifest:chrome && web-ext run --source-dir ./src/ --target=chromium",
88
"firefox": "npm run manifest:firefox && web-ext run --source-dir ./src/",

src/html/options.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ <h1 class="align-middle">Django Files Extension</h1>
8585
<script type="text/javascript" src="../dist/bootstrap/bootstrap.bundle.min.js"></script>
8686
<script type="text/javascript" src="../dist/fontawesome/js/all.min.js"></script>
8787
<script type="text/javascript" src="../dist/clipboard/clipboard.min.js"></script>
88-
<script type="module" src="../js/options.js"></script>
88+
<script type="text/javascript" src="../js/options.js"></script>
8989

9090
</body>
9191
</html>

src/html/popup.html

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
<img src="../media/logo32.png" class="float-start" alt="Django Files" height="32" width="32">
1616
<h2>Django Files Extension</h2>
1717
</div>
18-
<div class="d-grid g-2">
19-
<div id="django-files-links" class="btn-group btn-group-sm" role="group" aria-label="Django Files Links" style="display: none;">
18+
<div class="d-grid g-2" id="popup-buttons">
19+
<div id="django-files-links" class="btn-group btn-group-sm visually-hidden" role="group" aria-label="Django Files Links">
2020
<a role="button" class="btn btn-outline-success" data-href="" data-location="/files/">
2121
<i class="fa-regular fa-folder-open me-2"></i> Files</a>
2222
<a role="button" class="btn btn-outline-success" data-href="" data-location="/gallery/">
@@ -25,20 +25,23 @@ <h2>Django Files Extension</h2>
2525
<a class="btn btn-outline-primary btn-sm my-1" role="button" data-href="options">
2626
<i class="fa-solid fa-gear me-2"></i> Open Options</a>
2727
</div>
28-
<p class="mb-0" id="recent-uploads">Recent Uploads:</p>
2928

30-
<div class="d-flex justify-content-center mt-2" id="loading-spinner">
29+
<a role="button" class="btn btn-lg btn-success w-100 my-2 visually-hidden" id="auth-button">
30+
<i class="fa-solid fa-key"></i>
31+
Add Auth from Current Site</a>
32+
33+
<div class="d-flex justify-content-center mt-2 visually-hidden" id="loading-spinner">
3134
<span class="visually-hidden">Loading...</span>
3235
<div class="spinner-grow mx-1" role="status"></div>
3336
<div class="spinner-grow mx-1" role="status"></div>
3437
<div class="spinner-grow mx-1" role="status"></div>
3538
</div>
36-
<table id="recent" class="table table-striped table-sm mb-0 ">
39+
<table id="recent" class="table table-striped table-sm mt-2 mb-0 visually-hidden">
3740
<caption class="visually-hidden">Recent Uploads</caption>
3841
<thead class="visually-hidden"><tr><th>Number</th><th>File URL</th></tr></thead>
3942
<tbody></tbody>
4043
</table>
41-
<div id="error-alert" class="alert alert-warning mt-2" role="alert" style="display: none;" ></div>
44+
<div id="error-alert" class="alert alert-warning mt-2 mb-0" role="alert" style="display: none;" ></div>
4245
</div>
4346

4447
<script type="text/javascript" src="../dist/polyfill/browser-polyfill.min.js"></script>

src/js/auth.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// JS auth.js
2+
3+
// eslint-disable-next-line no-extra-semi
4+
;(async () => {
5+
console.log('auth.js')
6+
const response = await chrome.runtime.sendMessage(getCredentials())
7+
console.log(response)
8+
})()
9+
10+
/**
11+
* Handle Messages
12+
* @function getCredentials
13+
* @return {Object}
14+
*/
15+
function getCredentials() {
16+
const siteUrl = document.getElementById('site-url')
17+
const authToken = document.getElementById('auth-token')
18+
if (siteUrl && authToken) {
19+
return {
20+
siteUrl: siteUrl.value,
21+
authToken: authToken.value,
22+
}
23+
}
24+
}

src/js/exports.js

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/js/options.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// JS for options.html
22

3-
import { createContextMenus } from './exports.js'
4-
53
document.addEventListener('DOMContentLoaded', initOptions)
64
document.getElementById('options-form').addEventListener('submit', saveOptions)
5+
document.getElementById('submit').addEventListener('click', saveOptions)
76

87
/**
98
* Options Init Function
@@ -23,12 +22,12 @@ async function initOptions() {
2322
document.getElementById('version').textContent =
2423
chrome.runtime.getManifest().version
2524
document.getElementById('token').value = auth?.token || ''
25+
document.getElementById('recentFiles').value = options.recentFiles || '10'
2626
document.getElementById('contextMenu').checked = options.contextMenu
2727
document.getElementById('showUpdate').checked = options.showUpdate
2828
const commands = await chrome.commands.getAll()
2929
document.getElementById('mainKey').textContent =
3030
commands.find((x) => x.name === '_execute_action').shortcut || 'Not Set'
31-
document.getElementById('recentFiles').value = options.recentFiles || '10'
3231
}
3332

3433
/**
@@ -48,12 +47,6 @@ async function saveOptions(event) {
4847
options.recentFiles = document.getElementById('recentFiles').value
4948
options.contextMenu = document.getElementById('contextMenu').checked
5049
options.showUpdate = document.getElementById('showUpdate').checked
51-
if (options.contextMenu) {
52-
chrome.contextMenus.removeAll()
53-
createContextMenus()
54-
} else {
55-
chrome.contextMenus.removeAll()
56-
}
5750
console.log('options:', options)
5851
await chrome.storage.sync.set({ auth, options })
5952
document.getElementById('url').value = auth.url

src/js/popup.js

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ document.addEventListener('DOMContentLoaded', initPopup)
55
const popupLinks = document.querySelectorAll('[data-href]')
66
popupLinks.forEach((el) => el.addEventListener('click', popLinks))
77

8+
chrome.runtime.onMessage.addListener(onMessage)
9+
810
/**
911
* Popup Init Function
1012
* TODO: Overhaul this function
@@ -15,20 +17,29 @@ async function initPopup() {
1517
const { auth, options } = await chrome.storage.sync.get(['auth', 'options'])
1618
console.log('auth:', auth)
1719
if (!auth?.url || !auth?.token) {
18-
return displayError('Missing URL or Token.')
20+
displayError('Missing URL or Token.')
21+
const [tab] = await chrome.tabs.query({
22+
currentWindow: true,
23+
active: true,
24+
})
25+
console.log('tab:', tab)
26+
await chrome.scripting.executeScript({
27+
target: { tabId: tab.id },
28+
files: ['/js/auth.js'],
29+
})
30+
return
1931
}
32+
2033
document.getElementById('django-files-links').style.display = 'flex'
21-
console.log('options.recentFiles:', options.recentFiles)
34+
2235
if (options.recentFiles === '0') {
23-
document
24-
.getElementById('loading-spinner')
25-
.classList.add('visually-hidden')
26-
document
27-
.getElementById('recent-uploads')
28-
.classList.add('visually-hidden')
2936
return console.log('Recent Files Disabled. Enable in Options.')
3037
}
3138

39+
document
40+
.getElementById('loading-spinner')
41+
.classList.remove('visually-hidden')
42+
3243
let opts = {
3344
method: 'GET',
3445
headers: { Authorization: auth.token },
@@ -61,6 +72,7 @@ async function initPopup() {
6172
}
6273

6374
updateTable(data)
75+
document.getElementById('recent').classList.remove('visually-hidden')
6476

6577
const clipboard = new ClipboardJS('.clip') // eslint-disable-line
6678
// Re-Initialize data-href after updateTable
@@ -101,6 +113,38 @@ async function popLinks(event) {
101113
return window.close()
102114
}
103115

116+
/**
117+
* On Command Callback
118+
* @function onMessage
119+
* @param {Object} message
120+
* @param {MessageSender} sender
121+
* @param {Function} sendResponse
122+
*/
123+
async function onMessage(message, sender, sendResponse) {
124+
console.log('message, sender, sendResponse:', message, sender, sendResponse)
125+
if (message?.siteUrl && message?.authToken) {
126+
console.log(`url: ${message.siteUrl}`)
127+
console.log(`token: ${message.authToken}`)
128+
const auth = { url: message.siteUrl, token: message.authToken }
129+
await chrome.storage.local.set({ auth })
130+
const btn = document.getElementById('auth-button')
131+
btn.classList.remove('visually-hidden')
132+
btn.addEventListener('click', authCredentials)
133+
}
134+
}
135+
136+
async function authCredentials(event) {
137+
console.log('authCredentials:', event)
138+
const { auth } = await chrome.storage.local.get(['auth'])
139+
console.log('auth:', auth)
140+
if (auth) {
141+
await chrome.storage.sync.set({ auth })
142+
document.getElementById('auth-button').classList.add('visually-hidden')
143+
document.getElementById('error-alert').classList.add('visually-hidden')
144+
await initPopup()
145+
}
146+
}
147+
104148
/**
105149
* Update Popup Table with Data
106150
* @function updateTable

src/js/service-worker.js

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
1-
// Background Service Worker JS
2-
3-
import { createContextMenus } from './exports.js'
1+
// JS Background Service Worker
42

53
chrome.runtime.onInstalled.addListener(onInstalled)
64
chrome.contextMenus.onClicked.addListener(contextMenuClick)
5+
chrome.storage.onChanged.addListener(onChanged)
76

87
chrome.notifications.onClicked.addListener((notificationId) => {
98
console.log(`notifications.onClicked: ${notificationId}`)
109
chrome.notifications.clear(notificationId)
1110
})
1211

13-
const ghUrl = 'https://github.com/django-files/web-extension'
14-
1512
/**
1613
* Init Context Menus and Options
1714
* @function onInstalled
1815
* @param {InstalledDetails} details
1916
*/
2017
async function onInstalled(details) {
2118
console.log('onInstalled:', details)
19+
const ghUrl = 'https://github.com/django-files/web-extension'
2220
const defaultOptions = {
2321
contextMenu: true,
2422
recentFiles: '10',
@@ -28,7 +26,6 @@ async function onInstalled(details) {
2826
options = setDefaults(options, defaultOptions)
2927
console.log('options:', options)
3028
await chrome.storage.sync.set({ options })
31-
3229
if (options.contextMenu) {
3330
createContextMenus()
3431
}
@@ -73,6 +70,59 @@ async function contextMenuClick(ctx) {
7370
}
7471
}
7572

73+
/**
74+
* On Changed Callback
75+
* @function onChanged
76+
* @param {Object} changes
77+
* @param {String} namespace
78+
*/
79+
function onChanged(changes, namespace) {
80+
console.log('onChanged:', changes, namespace)
81+
if (namespace === 'sync') {
82+
for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
83+
if (
84+
key === 'options' &&
85+
oldValue &&
86+
newValue &&
87+
oldValue.contextMenu !== newValue.contextMenu
88+
) {
89+
if (newValue?.contextMenu) {
90+
console.log('Enabled contextMenu...')
91+
createContextMenus()
92+
} else {
93+
console.log('Disabled contextMenu...')
94+
chrome.contextMenus.removeAll()
95+
}
96+
}
97+
}
98+
}
99+
}
100+
101+
/**
102+
* Create Context Menus
103+
* @function createContextMenus
104+
*/
105+
function createContextMenus() {
106+
console.log('createContextMenus')
107+
const ctx = ['link', 'image', 'video', 'audio']
108+
const contexts = [
109+
[['link'], 'short', 'normal', 'Create Short URL'],
110+
[['image'], 'upload-image', 'normal', 'Upload Image'],
111+
[['video'], 'upload-video', 'normal', 'Upload Video'],
112+
[['audio'], 'upload-audio', 'normal', 'Upload Audio'],
113+
[ctx, 'separator-1', 'separator', 'separator'],
114+
[ctx, 'options', 'normal', 'Open Options'],
115+
]
116+
contexts.forEach((context) => {
117+
chrome.contextMenus.create({
118+
contexts: context[0],
119+
id: context[1],
120+
type: context[2],
121+
title: context[3],
122+
})
123+
})
124+
}
125+
76126
async function postURL(endpoint, url) {
77127
console.log('Processing URL: ' + url)
78128
const { auth } = await chrome.storage.sync.get(['auth'])

0 commit comments

Comments
 (0)