Skip to content

Commit ddb9975

Browse files
author
Tim Berners-Lee
committed
Adding deelete recuruve for folders; an fixing prefrence file case for diff origin
1 parent 119ca85 commit ddb9975

3 files changed

Lines changed: 121 additions & 26 deletions

File tree

src/folders.js

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/** UI To Delete Folder and content
22
*
33
*/
4-
5-
var UI = {
4+
/* global confirm */
5+
const UI = {
66
icons: require('./iconBase'),
77
log: require('./log'),
88
ns: require('./ns'),
@@ -13,21 +13,72 @@ var UI = {
1313
utils: require('./utils')
1414
}
1515

16-
/** Delete Folder and contents
16+
const ns = UI.ns
17+
18+
function deleteRecursive (kb, folder) {
19+
return new Promise(function (resolve, reject) {
20+
kb.fetcher.load(folder).then(function () {
21+
let promises = kb.each(folder, ns.ldp('contains')).map(file => {
22+
if (kb.holds(file, ns.rdf('type'), ns.ldp('BasicContainer'))) {
23+
return deleteRecursive(kb, file)
24+
} else {
25+
console.log('deleteRecirsive file: ' + file)
26+
if (!confirm(' Really DELETE File ' + file)) {
27+
throw new Error('User aborted delete file')
28+
}
29+
return kb.fetcher.webOperation('DELETE', file.uri)
30+
}
31+
})
32+
console.log('deleteRecirsive folder: ' + folder)
33+
if (!confirm(' Really DELETE folder ' + folder)) {
34+
throw new Error('User aborted delete file')
35+
}
36+
promises.push(kb.fetcher.webOperation('DELETE', folder.uri))
37+
Promise.all(promises).then(res => { resolve() })
38+
})
39+
})
40+
}
41+
42+
/** Iterate over files depth first
1743
*
18-
* @param {NamedNode} folder - The LDP container to be deleted
19-
* @param {DOMElement} containingElement - Where to put the user interface
20-
* @param {IndexedForumula} store - Quadstore (optional)
21-
* @param {Document} dom - The browser 'document' gloabl or equivalent (or iuse global)
22-
* @returns {DOMElement} - The control which has eben inserted in the
44+
* @param folder - The folder whose contents we iterate over
45+
* @param store - The quadstore
46+
* @param action - returns a promise. All the promises must be resolved
2347
*/
24-
/* global document */
25-
module.exports.deleteFolder(folder, containingElement, store, dom) {
48+
function forAllFiles (folder, kb, action) {
49+
return new Promise(function (resolve, reject) {
50+
kb.fetcher.load(folder).then(function () {
51+
let promises = kb.each(folder, ns.ldp('contains')).map(file => {
52+
if (kb.holds(file, ns.rdf('type'), ns.ldp('BasicContainer'))) {
53+
return forAllFiles(file, kb, action)
54+
} else {
55+
return action(file)
56+
}
57+
})
58+
promises.push(action(folder))
59+
Promise.all(promises).then(res => { resolve() })
60+
})
61+
})
62+
}
63+
64+
module.exports.deleteRecursive = deleteRecursive
65+
66+
/** Delete Folder and contents
67+
*
68+
* @param {NamedNode} folder - The LDP container to be deleted
69+
* @param {DOMElement} containingElement - Where to put the user interface
70+
* @param {IndexedForumula} store - Quadstore (optional)
71+
* @param {Document} dom - The browser 'document' gloabl or equivalent (or iuse global)
72+
* @returns {DOMElement} - The control which has eben inserted in the
73+
*/
74+
/* global document */
75+
module.exports.deleteFolder = function (folder, store, dom) {
2676
store = store || UI.store
27-
if (typeof docuent !=== 'undefined') {
77+
if (typeof docuent !== 'undefined') {
2878
dom = dom || document
2979
}
30-
const table = dom.createElement('table')
80+
const div = dom.createElement('div')
81+
const table = div.appendChild(dom.createElement('table'))
3182
const mainTR = table.appendChild(dom.createElement('tr'))
3283
const mainTD = mainTR.appendChild(dom.createElement('td'))
3384

@@ -37,7 +88,29 @@ module.exports.deleteFolder(folder, containingElement, store, dom) {
3788
const buttonsTD1 = buttonsTR.appendChild(dom.createElement('td'))
3889
const buttonsTD2 = buttonsTR.appendChild(dom.createElement('td'))
3990
const buttonsTD3 = buttonsTR.appendChild(dom.createElement('td'))
40-
4191

42-
return table
92+
let cancel = buttonsTD1.appendChild(UI.widgets.cancelButton)
93+
cancel.addEventListener('click', function (e) {
94+
div.parentNode.removeChild(div)
95+
}, false)
96+
97+
let doit = buttonsTD3.appendChild(UI.widgets.button(UI.icons.iconBase + 'noun_925021.svg', 'Yes, delete'))
98+
doit.addEventListener('click', function (e) {
99+
deleteThem(folder).then(() => {
100+
console.log('All deleted.')
101+
})
102+
}, false)
103+
104+
function deleteThem (folder) {
105+
return forAllFiles(folder, (file) => store.fetcher.webOperation('DELETE', file.uri))
106+
}
107+
var count = 0
108+
forAllFiles(folder, store, () => { count += 1 }) // Count files
109+
.then(() => {
110+
let msg = ' Files to delete: ' + count
111+
console.log(msg)
112+
p.textContent += msg
113+
})
114+
115+
return div
43116
}

src/signin.js

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,14 @@ function logInLoadPreferences (context) {
228228
reject(new Error(message))
229229
}
230230

231+
/** Are we working cross-origin?
232+
*
233+
* @returns {Boolean} True if we are in a webapp at an origin, and the file origin is different
234+
*/
235+
function differentOrigin () {
236+
return window.location && (window.location.origin + '/' !== preferencesFile.site().uri)
237+
}
238+
231239
if (!preferencesFile) {
232240
let message = "Can't find a preferences file pointer in profile " + context.publicProfile
233241
return reject(new Error(message))
@@ -250,6 +258,11 @@ function logInLoadPreferences (context) {
250258
if (status === 401) {
251259
m2 = 'Strange - you are not authenticated (properly logged on) to read preferences file.'
252260
} else if (status === 403) {
261+
if (differentOrigin()) {
262+
m2 = 'Unauthorized: Assuming prefs file blocked for origin ' + window.location.origin
263+
context.preferencesFileError = m2
264+
return resolve(context)
265+
}
253266
m2 = 'Strange - you are not authorized to read your preferences file.'
254267
} else if (status === 404) {
255268
if (confirm('You do not currently have a Preferences file. Ok for me to create an empty one? ' + preferencesFile)) {
@@ -287,13 +300,15 @@ function loadTypeIndexes (context) {
287300
logInLoadPreferences(context).then(context => {
288301
var me = context.me
289302
context.index = context.index || {}
290-
context.index.private = kb.each(me, ns.solid('privateTypeIndex'), undefined, context.preferencesFile)
291-
if (context.index.private.length === 0) {
292-
return reject(new Error('Your preference file ' + context.preferencesFile + ' does not point to a private type index.'))
303+
if (!context.preferencesFileError) {
304+
context.index.private = kb.each(me, ns.solid('privateTypeIndex'), undefined, context.preferencesFile)
305+
if (context.index.private.length === 0) {
306+
return reject(new Error('Your preference file ' + context.preferencesFile + ' does not point to a private type index.'))
307+
}
293308
}
294309
context.index.public = kb.each(me, ns.solid('publicTypeIndex'), undefined, context.publicProfile)
295310
if (context.index.public.length === 0) {
296-
return reject(new Error('Your preference file ' + context.preferencesFile + ' does not point to a public type index.'))
311+
return reject(new Error('Your profile ' + context.publicProfile + ' does not point to a public type index.'))
297312
}
298313
var ix = context.index.private.concat(context.index.public)
299314
kb.fetcher.load(ix).then(responses => {
@@ -316,6 +331,7 @@ function loadTypeIndexes (context) {
316331
* @param context {Object}
317332
* @param context.me
318333
* @param context.preferencesFile
334+
* @param context.preferencesFileError - Set if preferences file is blocked at theis origin so don't use it
319335
* @param context.publicProfile
320336
* @param context.index
321337
*
@@ -496,13 +512,17 @@ function registrationControl (context, instance, klass) {
496512
tbody.children[1].appendChild(widgets.buildCheckboxForm(
497513
context.dom, UI.store, 'Personal note of this ' + context.noun, null, statements, form, index))
498514
}
499-
500-
// widgets.buildCheckboxForm(dom, kb, lab, del, ins, form, store)
501515
return context
502516
},
503517
function (e) {
504-
var msg = 'registrationControl: Type indexes not available: ' + e
505-
context.div.appendChild(UI.error.errorMessageBlock(context.dom, e))
518+
var msg
519+
if (content.preferencesFileError) {
520+
msg = '(Preferences not available)'
521+
context.div.appendChild(dom.createElement('p')).textContent = msg
522+
} else {
523+
var msg = 'registrationControl: Type indexes not available: ' + e
524+
context.div.appendChild(UI.error.errorMessageBlock(context.dom, e))
525+
}
506526
console.log(msg)
507527
})
508528
.catch(function (e) {

src/widgets/index.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,12 @@ UI.widgets.shortTime = function () {
140140
return UI.widgets.formatDateTime(new Date(), '{Hours}:{Minutes}:{Seconds}.{Milliseconds}')
141141
}
142142

143-
UI.widgets.newThing = function (store) {
143+
/** Mint local ID using timestamp
144+
* @param {NamedNode} doc - the document in which the ID is to be generated
145+
*/
146+
UI.widgets.newThing = function (doc) {
144147
var now = new Date()
145-
// http://www.w3schools.com/jsref/jsref_obj_date.asp
146-
return $rdf.sym(store.uri + '#' + 'id' + ('' + now.getTime()))
148+
return $rdf.sym(doc.uri + '#' + 'id' + ('' + now.getTime()))
147149
}
148150

149151
// ///////////////////// Handy UX widgets
@@ -921,7 +923,7 @@ UI.widgets.field[UI.ns.ui('PhoneField').uri] =
921923
}
922924
}
923925
}
924-
926+
925927
updateMany(ds, is, function (uri, ok, body) {
926928
// kb.updater.update(ds, is, function (uri, ok, body) {
927929
if (ok) {

0 commit comments

Comments
 (0)