1
+ import { stringify } from '../../utils/stringify' ;
2
+ import getExpressionPrecedence from '../../utils/getExpressionPrecedence' ;
3
+ import Node from './shared/Node' ;
4
+ import Block from '../dom/Block' ;
5
+
6
+ export default class Title extends Node {
7
+ build (
8
+ block : Block ,
9
+ parentNode : string ,
10
+ parentNodes : string
11
+ ) {
12
+ const isDynamic = ! ! this . children . find ( node => node . type !== 'Text' ) ;
13
+
14
+ if ( isDynamic ) {
15
+ let value ;
16
+
17
+ const allDependencies = new Set ( ) ;
18
+ let shouldCache ;
19
+
20
+ // TODO some of this code is repeated in Tag.ts — would be good to
21
+ // DRY it out if that's possible without introducing crazy indirection
22
+ if ( this . children . length === 1 ) {
23
+ // single {{tag}} — may be a non-string
24
+ const { expression } = this . children [ 0 ] ;
25
+ const { indexes } = block . contextualise ( expression ) ;
26
+ const { dependencies, snippet } = this . children [ 0 ] . metadata ;
27
+
28
+ value = snippet ;
29
+ dependencies . forEach ( d => {
30
+ allDependencies . add ( d ) ;
31
+ } ) ;
32
+
33
+ shouldCache = (
34
+ expression . type !== 'Identifier' ||
35
+ block . contexts . has ( expression . name )
36
+ ) ;
37
+ } else {
38
+ // '{{foo}} {{bar}}' — treat as string concatenation
39
+ value =
40
+ ( this . children [ 0 ] . type === 'Text' ? '' : `"" + ` ) +
41
+ this . children
42
+ . map ( ( chunk : Node ) => {
43
+ if ( chunk . type === 'Text' ) {
44
+ return stringify ( chunk . data ) ;
45
+ } else {
46
+ const { indexes } = block . contextualise ( chunk . expression ) ;
47
+ const { dependencies, snippet } = chunk . metadata ;
48
+
49
+ dependencies . forEach ( d => {
50
+ allDependencies . add ( d ) ;
51
+ } ) ;
52
+
53
+ return getExpressionPrecedence ( chunk . expression ) <= 13 ? `(${ snippet } )` : snippet ;
54
+ }
55
+ } )
56
+ . join ( ' + ' ) ;
57
+
58
+ shouldCache = true ;
59
+ }
60
+
61
+ const last = shouldCache && block . getUniqueName (
62
+ `title_value`
63
+ ) ;
64
+
65
+ if ( shouldCache ) block . addVariable ( last ) ;
66
+
67
+ let updater ;
68
+ const init = shouldCache ? `${ last } = ${ value } ` : value ;
69
+
70
+ block . builders . init . addLine (
71
+ `document.title = ${ init } ;`
72
+ ) ;
73
+ updater = `document.title = ${ shouldCache ? last : value } ;` ;
74
+
75
+ if ( allDependencies . size ) {
76
+ const dependencies = Array . from ( allDependencies ) ;
77
+ const changedCheck = (
78
+ ( block . hasOutroMethod ? `#outroing || ` : '' ) +
79
+ dependencies . map ( dependency => `changed.${ dependency } ` ) . join ( ' || ' )
80
+ ) ;
81
+
82
+ const updateCachedValue = `${ last } !== (${ last } = ${ value } )` ;
83
+
84
+ const condition = shouldCache ?
85
+ ( dependencies . length ? `(${ changedCheck } ) && ${ updateCachedValue } ` : updateCachedValue ) :
86
+ changedCheck ;
87
+
88
+ block . builders . update . addConditional (
89
+ condition ,
90
+ updater
91
+ ) ;
92
+ }
93
+ } else {
94
+ const value = stringify ( this . children [ 0 ] . data ) ;
95
+ block . builders . hydrate . addLine ( `document.title = ${ value } ;` ) ;
96
+ }
97
+ }
98
+ }
0 commit comments