2021-05-12 21:00:55 +00:00
|
|
|
import {CellValue} from 'app/common/DocActions';
|
2020-10-07 21:58:43 +00:00
|
|
|
import {DataRowModel} from 'app/client/models/DataRowModel';
|
|
|
|
import {ViewFieldRec} from 'app/client/models/entities/ViewFieldRec';
|
|
|
|
import {colors, testId} from 'app/client/ui2018/cssVars';
|
|
|
|
import {icon} from 'app/client/ui2018/icons';
|
|
|
|
import {NTextBox} from 'app/client/widgets/NTextBox';
|
|
|
|
import {dom, styled} from 'grainjs';
|
2021-07-23 16:24:17 +00:00
|
|
|
import {constructUrl, sameDocumentUrlState, urlState} from "app/client/models/gristUrlState";
|
2020-10-07 21:58:43 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a widget for displaying links. Links can entered directly or following a title.
|
|
|
|
* The last entry following a space is used as the url.
|
|
|
|
* ie 'google https://www.google.com' would apears as 'google' to the user but link to the url.
|
|
|
|
*/
|
|
|
|
export class HyperLinkTextBox extends NTextBox {
|
|
|
|
constructor(field: ViewFieldRec) {
|
2021-03-02 12:27:08 +00:00
|
|
|
super(field, {defaultTextColor: colors.lightGreen.value});
|
2020-10-07 21:58:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public buildDom(row: DataRowModel) {
|
|
|
|
const value = row.cells[this.field.colId()];
|
|
|
|
return cssFieldClip(
|
|
|
|
dom.style('text-align', this.alignment),
|
|
|
|
dom.cls('text_wrapping', this.wrapping),
|
2021-05-12 21:00:55 +00:00
|
|
|
dom.maybe((use) => Boolean(use(value)), () =>
|
2020-10-07 21:58:43 +00:00
|
|
|
dom('a',
|
2021-07-23 16:24:17 +00:00
|
|
|
dom.attr('href', (use) => constructUrl(use(value))),
|
2020-10-07 21:58:43 +00:00
|
|
|
dom.attr('target', '_blank'),
|
2021-05-20 23:37:38 +00:00
|
|
|
dom.on('click', (ev) =>
|
2021-07-23 16:24:17 +00:00
|
|
|
_onClickHyperlink(ev, value.peek())),
|
2020-10-07 21:58:43 +00:00
|
|
|
// As per Google and Mozilla recommendations to prevent opened links
|
|
|
|
// from running on the same process as Grist:
|
|
|
|
// https://developers.google.com/web/tools/lighthouse/audits/noopener
|
|
|
|
dom.attr('rel', 'noopener noreferrer'),
|
2021-02-09 10:12:53 +00:00
|
|
|
cssLinkIcon('FieldLink', testId('tb-link-icon')),
|
2020-10-07 21:58:43 +00:00
|
|
|
testId('tb-link')
|
|
|
|
)
|
|
|
|
),
|
|
|
|
dom.text((use) => _formatValue(use(value))),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Formats value like `foo bar baz` by discarding `baz` and returning `foo bar`.
|
|
|
|
*/
|
2021-05-12 21:00:55 +00:00
|
|
|
function _formatValue(value: CellValue): string {
|
2020-10-07 21:58:43 +00:00
|
|
|
if (typeof value !== 'string') { return ''; }
|
|
|
|
const index = value.lastIndexOf(' ');
|
|
|
|
return index >= 0 ? value.slice(0, index) : value;
|
|
|
|
}
|
|
|
|
|
2021-05-20 23:37:38 +00:00
|
|
|
/**
|
|
|
|
* If possible (i.e. if `url` points to somewhere in the current document)
|
|
|
|
* use pushUrl to navigate without reloading or opening a new tab
|
|
|
|
*/
|
2021-07-23 16:24:17 +00:00
|
|
|
async function _onClickHyperlink(ev: MouseEvent, url: CellValue) {
|
2021-05-20 23:37:38 +00:00
|
|
|
// Only override plain-vanilla clicks.
|
|
|
|
if (ev.shiftKey || ev.metaKey || ev.ctrlKey || ev.altKey) { return; }
|
|
|
|
|
2021-07-23 16:24:17 +00:00
|
|
|
const newUrlState = sameDocumentUrlState(url);
|
|
|
|
if (!newUrlState) { return; }
|
2021-05-20 23:37:38 +00:00
|
|
|
|
|
|
|
ev.preventDefault();
|
|
|
|
await urlState().pushUrl(newUrlState);
|
|
|
|
}
|
|
|
|
|
2020-10-07 21:58:43 +00:00
|
|
|
const cssFieldClip = styled('div.field_clip', `
|
2021-02-09 10:12:53 +00:00
|
|
|
color: var(--grist-actual-cell-color, ${colors.lightGreen});
|
2020-10-07 21:58:43 +00:00
|
|
|
`);
|
|
|
|
|
|
|
|
const cssLinkIcon = styled(icon, `
|
2021-02-09 10:12:53 +00:00
|
|
|
background-color: var(--grist-actual-cell-color, ${colors.lightGreen});
|
2020-10-07 21:58:43 +00:00
|
|
|
margin: -1px 2px 2px 0;
|
|
|
|
`);
|