draft8
September 8, 2020, 6:47pm
#21
I see no end to this process, so I’ll probably have to pause there, alas, and get on with other things :-)
It should be possible, however, to learn enough to do this kind of experimentation and discovery yourself.
The trick is just to learn to think concretely and specifically about the values that you are trying to define.
rob
September 8, 2020, 7:08pm
#22
You’ve been more than generous, and I appreciate it.
1 Like
draft8
September 8, 2020, 8:10pm
#23
Won’t have time to update or amend this one, and no guarantees,
(in particular not at all sure that I can parse your meaning in the phrase enter the last Column name
… perhaps you mean that you want memory of the MRU tag value ? The column name is fixed anyway, as Tag
as far as I am aware … )
but you could try this:
add-tags-in-subtree.omnijs 2.zip (2.0 KB)
JS Source
/*{
"type": "action",
"name": "Append string to Tags cell for all descendants",
"author": "Rob Trew",
"version": "0.10",
"description": "Append string to Tags cell for all descendants",
"mediumLabel": "Batch tag",
"paletteLabel": "Batch tag",
}*/
(() => {
let defaultTag = '';
return Object.assign(
new PlugIn.Action(selection => {
'use strict';
// main :: IO ()
const main = () => {
// List of fields,
[
new Form.Field.String(
'colValue',
'Value:',
defaultTag
)
]
// consolidated into a form,
.reduce(
(frm, fld) => (
frm.addField(fld),
frm
),
new Form()
)
// and displayed.
.show(
'Value for empty tag cells:',
'OK'
)
// With processing of any form values.
.then(result => {
const
dteStart = new Date(),
tagString = result.values.colValue,
n = itemsTagged(
columnFoundOrCreated(Column.Type.Text)('Tag')
)(tagString)(
document.editors[0].selection.items
),
plural = (1 !== n) ? 's' : '',
elapsed = (new Date() - dteStart) / 1000;
new Alert(
'Subtree tagging',
`${n} '${tagString}' tag${plural} ` + (
`applied in ${elapsed} seconds.`
)
).show();
defaultTag = tagString;
});
};
// ---------------- OO EFFECTS -----------------
// columnFoundOrCreated :: ColumnType ->
// String -> Column
const columnFoundOrCreated = colType =>
colName => {
const outline = document.outline;
return outline.columns.byTitle(
colName
) || outline.addColumn(
colType,
document.editors[0].afterColumn(null),
col => col.title = colName
);
};
// itemsTagged :: Column -> String ->
// [OOItem] -> Int
const itemsTagged = col =>
tag => items => commonAncestors(items)
.flatMap(
x => [x].concat(
x.descendants
).flatMap(x => {
const
v = x.valueForColumn(col),
sv = null !== v ? (
v.string
) : '';
return !sv.includes(tag) ? [(
x.setValueForColumn(
sv ? (
sv + ' ' + tag
) : tag,
col
),
1
)] : [];
})
).length;
// --------------- GENERIC FUNCTIONS ---------------
// https://github.com/RobTrew/prelude-jxa
// commonAncestors :: [OOItem] -> [OOItem]
const commonAncestors = items => {
// Only items which do not descend
// from other items in the list.
const
dct = items.reduce(
(a, x) => (a[x.identifier] = true, a), {}
);
return items.filter(
x => !until(
y => (null === y) || dct[y.identifier]
)(v => v.parent)(x.parent)
);
};
// showLog :: a -> IO ()
const showLog = (...args) =>
console.log(
args
.map(JSON.stringify)
.join(' -> ')
);
// until :: (a -> Bool) -> (a -> a) -> a -> a
const until = p =>
// Iterative application of f to x
// until the resulting value matches p.
f => x => {
let v = x;
while (!p(v)) v = f(v);
return v;
};
// MAIN ---
return main();
}), {
validate: selection => 0 < selection.items.length
});
})();
rob
September 8, 2020, 9:06pm
#24
Wow. That did it.
(And what I meant by “enter the last column name” was in reference to the tag-subtree script, not this script.)
Many, many thanks! Put yourself in for a raise.
draft8
September 11, 2020, 8:04pm
#25
Updated here and in the post above:
Now creates a Tag column if none is found in the front document,
and holds the MRU tag value memory in a more sensible scope.
add-tags-in-subtree.omnijs.zip (2.0 KB)
JS Source
/*{
"type": "action",
"name": "Append string to Tags cell for all descendants",
"author": "Rob Trew",
"version": "0.10",
"description": "Append string to Tags cell for all descendants",
"mediumLabel": "Batch tag",
"paletteLabel": "Batch tag",
}*/
(() => {
// -------------------- MRU MEMORY ---------------------
let defaultTag = '';
// ---------------------- PLUGIN -----------------------
return Object.assign(
new PlugIn.Action(selection => {
'use strict';
// main :: IO ()
const main = () => {
// List of fields,
[
new Form.Field.String(
'colValue',
'Value:',
defaultTag
)
]
// consolidated into a form,
.reduce(
(frm, fld) => (
frm.addField(fld),
frm
),
new Form()
)
// and displayed.
.show(
'Value for empty tag cells:',
'OK'
)
// With processing of any form values.
.then(result => {
const
dteStart = new Date(),
tagString = result.values.colValue,
n = itemsTagged(
columnFoundOrCreated(Column.Type.Text)('Tag')
)(tagString)(
document.editors[0].selection.items
),
plural = (1 !== n) ? 's' : '',
elapsed = (new Date() - dteStart) / 1000;
// ------------ RESULTS ------------
new Alert(
'Subtree tagging',
`${n} '${tagString}' tag${plural} ` + (
`applied in ${elapsed} seconds.`
)
).show();
defaultTag = tagString;
});
};
// ---------------- OO EFFECTS -----------------
// columnFoundOrCreated :: ColumnType ->
// String -> Column
const columnFoundOrCreated = colType =>
colName => {
const outline = document.outline;
return outline.columns.byTitle(
colName
) || outline.addColumn(
colType,
document.editors[0].afterColumn(null),
col => col.title = colName
);
};
// itemsTagged :: Column -> String ->
// [OOItem] -> Int
const itemsTagged = col =>
tag => items => commonAncestors(items)
.flatMap(
x => [x].concat(x.descendants)
.flatMap(x => {
const
v = x.valueForColumn(col),
sv = null !== v ? (
v.string
) : '';
return !sv.includes(tag) ? [(
x.setValueForColumn(
sv ? (
sv + ' ' + tag
) : tag,
col
),
1
)] : [];
})
).length;
// ------------- GENERIC FUNCTIONS -------------
// https://github.com/RobTrew/prelude-jxa
// commonAncestors :: [OOItem] -> [OOItem]
const commonAncestors = items => {
// Only items which do not descend
// from other items in the list.
const
dct = items.reduce(
(a, x) => (a[x.identifier] = true, a), {}
);
return items.filter(
x => !until(
y => (null === y) || dct[y.identifier]
)(v => v.parent)(x.parent)
);
};
// showLog :: a -> IO ()
const showLog = (...args) =>
console.log(
args
.map(JSON.stringify)
.join(' -> ')
);
// until :: (a -> Bool) -> (a -> a) -> a -> a
const until = p =>
// Iterative application of f to x
// until the resulting value matches p.
f => x => {
let v = x;
while (!p(v)) v = f(v);
return v;
};
// MAIN ---
return main();
}), {
validate: selection => 0 < selection.items.length
});
})();
ddflr
March 3, 2021, 10:16pm
#26
Can I send you a private message on a script I need?