Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
P
purr-data
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Jonathan Wilkes
purr-data
Commits
053f6f20
Commit
053f6f20
authored
9 years ago
by
Jonathan Wilkes
Browse files
Options
Downloads
Patches
Plain Diff
first draft of a functioning "Find" bar for the Pd console
parent
d4fbe0a8
No related branches found
No related tags found
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
pd/nw/console_search.js
+632
-0
632 additions, 0 deletions
pd/nw/console_search.js
pd/nw/css/default.css
+17
-2
17 additions, 2 deletions
pd/nw/css/default.css
pd/nw/index.html
+9
-9
9 additions, 9 deletions
pd/nw/index.html
pd/nw/index.js
+149
-8
149 additions, 8 deletions
pd/nw/index.js
with
807 additions
and
19 deletions
pd/nw/console_search.js
0 → 100644
+
632
−
0
View file @
053f6f20
/**
* findAndReplaceDOMText v 0.4.3
* @author James Padolsey http://james.padolsey.com
* @license http://unlicense.org/UNLICENSE
*
* Matches the text of a DOM node against a regular expression
* and replaces each match (or node-separated portions of the match)
* in the specified element.
*/
(
function
(
root
,
factory
)
{
if
(
typeof
module
===
'
object
'
&&
module
.
exports
)
{
// Node/CommonJS
module
.
exports
=
factory
();
}
else
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
// AMD. Register as an anonymous module.
define
(
factory
);
}
else
{
// Browser globals
root
.
findAndReplaceDOMText
=
factory
();
}
}(
this
,
function
factory
()
{
var
PORTION_MODE_RETAIN
=
'
retain
'
;
var
PORTION_MODE_FIRST
=
'
first
'
;
var
doc
=
document
;
var
toString
=
{}.
toString
;
var
hasOwn
=
{}.
hasOwnProperty
;
function
isArray
(
a
)
{
return
toString
.
call
(
a
)
==
'
[object Array]
'
;
}
function
escapeRegExp
(
s
)
{
return
String
(
s
).
replace
(
/
([
.*+?^=!:${}()|[
\]\/\\])
/g
,
'
\\
$1
'
);
}
function
exposed
()
{
// Try deprecated arg signature first:
return
deprecated
.
apply
(
null
,
arguments
)
||
findAndReplaceDOMText
.
apply
(
null
,
arguments
);
}
function
deprecated
(
regex
,
node
,
replacement
,
captureGroup
,
elFilter
)
{
if
((
node
&&
!
node
.
nodeType
)
&&
arguments
.
length
<=
2
)
{
return
false
;
}
var
isReplacementFunction
=
typeof
replacement
==
'
function
'
;
if
(
isReplacementFunction
)
{
replacement
=
(
function
(
original
)
{
return
function
(
portion
,
match
)
{
return
original
(
portion
.
text
,
match
.
startIndex
);
};
}(
replacement
));
}
// Awkward support for deprecated argument signature (<0.4.0)
var
instance
=
findAndReplaceDOMText
(
node
,
{
find
:
regex
,
wrap
:
isReplacementFunction
?
null
:
replacement
,
replace
:
isReplacementFunction
?
replacement
:
'
$
'
+
(
captureGroup
||
'
&
'
),
prepMatch
:
function
(
m
,
mi
)
{
// Support captureGroup (a deprecated feature)
if
(
!
m
[
0
])
throw
'
findAndReplaceDOMText cannot handle zero-length matches
'
;
if
(
captureGroup
>
0
)
{
var
cg
=
m
[
captureGroup
];
m
.
index
+=
m
[
0
].
indexOf
(
cg
);
m
[
0
]
=
cg
;
}
m
.
endIndex
=
m
.
index
+
m
[
0
].
length
;
m
.
startIndex
=
m
.
index
;
m
.
index
=
mi
;
return
m
;
},
filterElements
:
elFilter
});
exposed
.
revert
=
function
()
{
return
instance
.
revert
();
};
return
true
;
}
/**
* findAndReplaceDOMText
*
* Locates matches and replaces with replacementNode
*
* @param {Node} node Element or Text node to search within
* @param {RegExp} options.find The regular expression to match
* @param {String|Element} [options.wrap] A NodeName, or a Node to clone
* @param {String|Function} [options.replace='$&'] What to replace each match with
* @param {Function} [options.filterElements] A Function to be called to check whether to
* process an element. (returning true = process element,
* returning false = avoid element)
*/
function
findAndReplaceDOMText
(
node
,
options
)
{
return
new
Finder
(
node
,
options
);
}
exposed
.
NON_PROSE_ELEMENTS
=
{
br
:
1
,
hr
:
1
,
// Media / Source elements:
script
:
1
,
style
:
1
,
img
:
1
,
video
:
1
,
audio
:
1
,
canvas
:
1
,
svg
:
1
,
map
:
1
,
object
:
1
,
// Input elements
input
:
1
,
textarea
:
1
,
select
:
1
,
option
:
1
,
optgroup
:
1
,
button
:
1
};
exposed
.
NON_CONTIGUOUS_PROSE_ELEMENTS
=
{
// Elements that will not contain prose or block elements where we don't
// want prose to be matches across element borders:
// Block Elements
address
:
1
,
article
:
1
,
aside
:
1
,
blockquote
:
1
,
dd
:
1
,
div
:
1
,
dl
:
1
,
fieldset
:
1
,
figcaption
:
1
,
figure
:
1
,
footer
:
1
,
form
:
1
,
h1
:
1
,
h2
:
1
,
h3
:
1
,
h4
:
1
,
h5
:
1
,
h6
:
1
,
header
:
1
,
hgroup
:
1
,
hr
:
1
,
main
:
1
,
nav
:
1
,
noscript
:
1
,
ol
:
1
,
output
:
1
,
p
:
1
,
pre
:
1
,
section
:
1
,
ul
:
1
,
// Other misc. elements that are not part of continuous inline prose:
br
:
1
,
li
:
1
,
summary
:
1
,
dt
:
1
,
details
:
1
,
rp
:
1
,
rt
:
1
,
rtc
:
1
,
// Media / Source elements:
script
:
1
,
style
:
1
,
img
:
1
,
video
:
1
,
audio
:
1
,
canvas
:
1
,
svg
:
1
,
map
:
1
,
object
:
1
,
// Input elements
input
:
1
,
textarea
:
1
,
select
:
1
,
option
:
1
,
optgroup
:
1
,
button
:
1
,
// Table related elements:
table
:
1
,
tbody
:
1
,
thead
:
1
,
th
:
1
,
tr
:
1
,
td
:
1
,
caption
:
1
,
col
:
1
,
tfoot
:
1
,
colgroup
:
1
};
exposed
.
NON_INLINE_PROSE
=
function
(
el
)
{
return
hasOwn
.
call
(
exposed
.
NON_CONTIGUOUS_PROSE_ELEMENTS
,
el
.
nodeName
.
toLowerCase
());
};
// Presets accessed via `options.preset` when calling findAndReplaceDOMText():
exposed
.
PRESETS
=
{
prose
:
{
forceContext
:
exposed
.
NON_INLINE_PROSE
,
filterElements
:
function
(
el
)
{
return
!
hasOwn
.
call
(
exposed
.
NON_PROSE_ELEMENTS
,
el
.
nodeName
.
toLowerCase
());
}
}
};
exposed
.
Finder
=
Finder
;
/**
* Finder -- encapsulates logic to find and replace.
*/
function
Finder
(
node
,
options
)
{
var
preset
=
options
.
preset
&&
exposed
.
PRESETS
[
options
.
preset
];
options
.
portionMode
=
options
.
portionMode
||
PORTION_MODE_RETAIN
;
if
(
preset
)
{
for
(
var
i
in
preset
)
{
if
(
hasOwn
.
call
(
preset
,
i
)
&&
!
hasOwn
.
call
(
options
,
i
))
{
options
[
i
]
=
preset
[
i
];
}
}
}
this
.
node
=
node
;
this
.
options
=
options
;
// ENable match-preparation method to be passed as option:
this
.
prepMatch
=
options
.
prepMatch
||
this
.
prepMatch
;
this
.
reverts
=
[];
this
.
matches
=
this
.
search
();
if
(
this
.
matches
.
length
)
{
this
.
processMatches
();
}
}
Finder
.
prototype
=
{
/**
* Searches for all matches that comply with the instance's 'match' option
*/
search
:
function
()
{
var
match
;
var
matchIndex
=
0
;
var
offset
=
0
;
var
regex
=
this
.
options
.
find
;
var
textAggregation
=
this
.
getAggregateText
();
var
matches
=
[];
var
self
=
this
;
regex
=
typeof
regex
===
'
string
'
?
RegExp
(
escapeRegExp
(
regex
),
'
g
'
)
:
regex
;
matchAggregation
(
textAggregation
);
function
matchAggregation
(
textAggregation
)
{
for
(
var
i
=
0
,
l
=
textAggregation
.
length
;
i
<
l
;
++
i
)
{
var
text
=
textAggregation
[
i
];
if
(
typeof
text
!==
'
string
'
)
{
// Deal with nested contexts: (recursive)
matchAggregation
(
text
);
continue
;
}
if
(
regex
.
global
)
{
while
(
match
=
regex
.
exec
(
text
))
{
matches
.
push
(
self
.
prepMatch
(
match
,
matchIndex
++
,
offset
));
}
}
else
{
if
(
match
=
text
.
match
(
regex
))
{
matches
.
push
(
self
.
prepMatch
(
match
,
0
,
offset
));
}
}
offset
+=
text
.
length
;
}
}
return
matches
;
},
/**
* Prepares a single match with useful meta info:
*/
prepMatch
:
function
(
match
,
matchIndex
,
characterOffset
)
{
if
(
!
match
[
0
])
{
throw
new
Error
(
'
findAndReplaceDOMText cannot handle zero-length matches
'
);
}
match
.
endIndex
=
characterOffset
+
match
.
index
+
match
[
0
].
length
;
match
.
startIndex
=
characterOffset
+
match
.
index
;
match
.
index
=
matchIndex
;
return
match
;
},
/**
* Gets aggregate text within subject node
*/
getAggregateText
:
function
()
{
var
elementFilter
=
this
.
options
.
filterElements
;
var
forceContext
=
this
.
options
.
forceContext
;
return
getText
(
this
.
node
);
/**
* Gets aggregate text of a node without resorting
* to broken innerText/textContent
*/
function
getText
(
node
,
txt
)
{
if
(
node
.
nodeType
===
3
)
{
return
[
node
.
data
];
}
if
(
elementFilter
&&
!
elementFilter
(
node
))
{
return
[];
}
var
txt
=
[
''
];
var
i
=
0
;
if
(
node
=
node
.
firstChild
)
do
{
if
(
node
.
nodeType
===
3
)
{
txt
[
i
]
+=
node
.
data
;
continue
;
}
var
innerText
=
getText
(
node
);
if
(
forceContext
&&
node
.
nodeType
===
1
&&
(
forceContext
===
true
||
forceContext
(
node
))
)
{
txt
[
++
i
]
=
innerText
;
txt
[
++
i
]
=
''
;
}
else
{
if
(
typeof
innerText
[
0
]
===
'
string
'
)
{
// Bridge nested text-node data so that they're
// not considered their own contexts:
// I.e. ['some', ['thing']] -> ['something']
txt
[
i
]
+=
innerText
.
shift
();
}
if
(
innerText
.
length
)
{
txt
[
++
i
]
=
innerText
;
txt
[
++
i
]
=
''
;
}
}
}
while
(
node
=
node
.
nextSibling
);
return
txt
;
}
},
/**
* Steps through the target node, looking for matches, and
* calling replaceFn when a match is found.
*/
processMatches
:
function
()
{
var
matches
=
this
.
matches
;
var
node
=
this
.
node
;
var
elementFilter
=
this
.
options
.
filterElements
;
var
startPortion
,
endPortion
,
innerPortions
=
[],
curNode
=
node
,
match
=
matches
.
shift
(),
atIndex
=
0
,
// i.e. nodeAtIndex
matchIndex
=
0
,
portionIndex
=
0
,
doAvoidNode
,
nodeStack
=
[
node
];
out
:
while
(
true
)
{
if
(
curNode
.
nodeType
===
3
)
{
if
(
!
endPortion
&&
curNode
.
length
+
atIndex
>=
match
.
endIndex
)
{
// We've found the ending
endPortion
=
{
node
:
curNode
,
index
:
portionIndex
++
,
text
:
curNode
.
data
.
substring
(
match
.
startIndex
-
atIndex
,
match
.
endIndex
-
atIndex
),
indexInMatch
:
atIndex
-
match
.
startIndex
,
indexInNode
:
match
.
startIndex
-
atIndex
,
// always zero for end-portions
endIndexInNode
:
match
.
endIndex
-
atIndex
,
isEnd
:
true
};
}
else
if
(
startPortion
)
{
// Intersecting node
innerPortions
.
push
({
node
:
curNode
,
index
:
portionIndex
++
,
text
:
curNode
.
data
,
indexInMatch
:
atIndex
-
match
.
startIndex
,
indexInNode
:
0
// always zero for inner-portions
});
}
if
(
!
startPortion
&&
curNode
.
length
+
atIndex
>
match
.
startIndex
)
{
// We've found the match start
startPortion
=
{
node
:
curNode
,
index
:
portionIndex
++
,
indexInMatch
:
0
,
indexInNode
:
match
.
startIndex
-
atIndex
,
endIndexInNode
:
match
.
endIndex
-
atIndex
,
text
:
curNode
.
data
.
substring
(
match
.
startIndex
-
atIndex
,
match
.
endIndex
-
atIndex
)
};
}
atIndex
+=
curNode
.
data
.
length
;
}
doAvoidNode
=
curNode
.
nodeType
===
1
&&
elementFilter
&&
!
elementFilter
(
curNode
);
if
(
startPortion
&&
endPortion
)
{
curNode
=
this
.
replaceMatch
(
match
,
startPortion
,
innerPortions
,
endPortion
);
// processMatches has to return the node that replaced the endNode
// and then we step back so we can continue from the end of the
// match:
atIndex
-=
(
endPortion
.
node
.
data
.
length
-
endPortion
.
endIndexInNode
);
startPortion
=
null
;
endPortion
=
null
;
innerPortions
=
[];
match
=
matches
.
shift
();
portionIndex
=
0
;
matchIndex
++
;
if
(
!
match
)
{
break
;
// no more matches
}
}
else
if
(
!
doAvoidNode
&&
(
curNode
.
firstChild
||
curNode
.
nextSibling
)
)
{
// Move down or forward:
if
(
curNode
.
firstChild
)
{
nodeStack
.
push
(
curNode
);
curNode
=
curNode
.
firstChild
;
}
else
{
curNode
=
curNode
.
nextSibling
;
}
continue
;
}
// Move forward or up:
while
(
true
)
{
if
(
curNode
.
nextSibling
)
{
curNode
=
curNode
.
nextSibling
;
break
;
}
curNode
=
nodeStack
.
pop
();
if
(
curNode
===
node
)
{
break
out
;
}
}
}
},
/**
* Reverts ... TODO
*/
revert
:
function
()
{
// Reversion occurs backwards so as to avoid nodes subsequently
// replaced during the matching phase (a forward process):
for
(
var
l
=
this
.
reverts
.
length
;
l
--
;)
{
this
.
reverts
[
l
]();
}
this
.
reverts
=
[];
},
prepareReplacementString
:
function
(
string
,
portion
,
match
,
matchIndex
)
{
var
portionMode
=
this
.
options
.
portionMode
;
if
(
portionMode
===
PORTION_MODE_FIRST
&&
portion
.
indexInMatch
>
0
)
{
return
''
;
}
string
=
string
.
replace
(
/
\$(\d
+|&|`|'
)
/g
,
function
(
$0
,
t
)
{
var
replacement
;
switch
(
t
)
{
case
'
&
'
:
replacement
=
match
[
0
];
break
;
case
'
`
'
:
replacement
=
match
.
input
.
substring
(
0
,
match
.
startIndex
);
break
;
case
'
\'
'
:
replacement
=
match
.
input
.
substring
(
match
.
endIndex
);
break
;
default
:
replacement
=
match
[
+
t
];
}
return
replacement
;
});
if
(
portionMode
===
PORTION_MODE_FIRST
)
{
return
string
;
}
if
(
portion
.
isEnd
)
{
return
string
.
substring
(
portion
.
indexInMatch
);
}
return
string
.
substring
(
portion
.
indexInMatch
,
portion
.
indexInMatch
+
portion
.
text
.
length
);
},
getPortionReplacementNode
:
function
(
portion
,
match
,
matchIndex
)
{
var
replacement
=
this
.
options
.
replace
||
'
$&
'
;
var
wrapper
=
this
.
options
.
wrap
;
if
(
wrapper
&&
wrapper
.
nodeType
)
{
// Wrapper has been provided as a stencil-node for us to clone:
var
clone
=
doc
.
createElement
(
'
div
'
);
clone
.
innerHTML
=
wrapper
.
outerHTML
||
new
XMLSerializer
().
serializeToString
(
wrapper
);
wrapper
=
clone
.
firstChild
;
}
if
(
typeof
replacement
==
'
function
'
)
{
replacement
=
replacement
(
portion
,
match
,
matchIndex
);
if
(
replacement
&&
replacement
.
nodeType
)
{
return
replacement
;
}
return
doc
.
createTextNode
(
String
(
replacement
));
}
var
el
=
typeof
wrapper
==
'
string
'
?
doc
.
createElement
(
wrapper
)
:
wrapper
;
replacement
=
doc
.
createTextNode
(
this
.
prepareReplacementString
(
replacement
,
portion
,
match
,
matchIndex
)
);
if
(
!
replacement
.
data
)
{
return
replacement
;
}
if
(
!
el
)
{
return
replacement
;
}
el
.
appendChild
(
replacement
);
return
el
;
},
replaceMatch
:
function
(
match
,
startPortion
,
innerPortions
,
endPortion
)
{
var
matchStartNode
=
startPortion
.
node
;
var
matchEndNode
=
endPortion
.
node
;
var
preceedingTextNode
;
var
followingTextNode
;
if
(
matchStartNode
===
matchEndNode
)
{
var
node
=
matchStartNode
;
if
(
startPortion
.
indexInNode
>
0
)
{
// Add `before` text node (before the match)
preceedingTextNode
=
doc
.
createTextNode
(
node
.
data
.
substring
(
0
,
startPortion
.
indexInNode
));
node
.
parentNode
.
insertBefore
(
preceedingTextNode
,
node
);
}
// Create the replacement node:
var
newNode
=
this
.
getPortionReplacementNode
(
endPortion
,
match
);
node
.
parentNode
.
insertBefore
(
newNode
,
node
);
if
(
endPortion
.
endIndexInNode
<
node
.
length
)
{
// ?????
// Add `after` text node (after the match)
followingTextNode
=
doc
.
createTextNode
(
node
.
data
.
substring
(
endPortion
.
endIndexInNode
));
node
.
parentNode
.
insertBefore
(
followingTextNode
,
node
);
}
node
.
parentNode
.
removeChild
(
node
);
this
.
reverts
.
push
(
function
()
{
if
(
preceedingTextNode
===
newNode
.
previousSibling
)
{
preceedingTextNode
.
parentNode
.
removeChild
(
preceedingTextNode
);
}
if
(
followingTextNode
===
newNode
.
nextSibling
)
{
followingTextNode
.
parentNode
.
removeChild
(
followingTextNode
);
}
newNode
.
parentNode
.
replaceChild
(
node
,
newNode
);
});
return
newNode
;
}
else
{
// Replace matchStartNode -> [innerMatchNodes...] -> matchEndNode (in that order)
preceedingTextNode
=
doc
.
createTextNode
(
matchStartNode
.
data
.
substring
(
0
,
startPortion
.
indexInNode
)
);
followingTextNode
=
doc
.
createTextNode
(
matchEndNode
.
data
.
substring
(
endPortion
.
endIndexInNode
)
);
var
firstNode
=
this
.
getPortionReplacementNode
(
startPortion
,
match
);
var
innerNodes
=
[];
for
(
var
i
=
0
,
l
=
innerPortions
.
length
;
i
<
l
;
++
i
)
{
var
portion
=
innerPortions
[
i
];
var
innerNode
=
this
.
getPortionReplacementNode
(
portion
,
match
);
portion
.
node
.
parentNode
.
replaceChild
(
innerNode
,
portion
.
node
);
this
.
reverts
.
push
((
function
(
portion
,
innerNode
)
{
return
function
()
{
innerNode
.
parentNode
.
replaceChild
(
portion
.
node
,
innerNode
);
};
}(
portion
,
innerNode
)));
innerNodes
.
push
(
innerNode
);
}
var
lastNode
=
this
.
getPortionReplacementNode
(
endPortion
,
match
);
matchStartNode
.
parentNode
.
insertBefore
(
preceedingTextNode
,
matchStartNode
);
matchStartNode
.
parentNode
.
insertBefore
(
firstNode
,
matchStartNode
);
matchStartNode
.
parentNode
.
removeChild
(
matchStartNode
);
matchEndNode
.
parentNode
.
insertBefore
(
lastNode
,
matchEndNode
);
matchEndNode
.
parentNode
.
insertBefore
(
followingTextNode
,
matchEndNode
);
matchEndNode
.
parentNode
.
removeChild
(
matchEndNode
);
this
.
reverts
.
push
(
function
()
{
preceedingTextNode
.
parentNode
.
removeChild
(
preceedingTextNode
);
firstNode
.
parentNode
.
replaceChild
(
matchStartNode
,
firstNode
);
followingTextNode
.
parentNode
.
removeChild
(
followingTextNode
);
lastNode
.
parentNode
.
replaceChild
(
matchEndNode
,
lastNode
);
});
return
lastNode
;
}
}
};
return
exposed
;
}));
This diff is collapsed.
Click to expand it.
pd/nw/css/default.css
+
17
−
2
View file @
053f6f20
/* Global CSS */
@font-face
{
font-family
:
"DejaVu Sans Mono"
;
src
:
url("../DejaVuSansMono.ttf")
;
font-family
:
"Droid Sans Mono Dotted"
;
/* src: url("../DejaVuSansMono.ttf"); */
src
:
url("../DroidSansMonoDotted.ttf")
;
}
.noselect
{
...
...
@@ -48,6 +49,20 @@
overflow-y
:
scroll
;
}
/* marks for matches to console_find */
mark
{
background
:
white
;
}
mark
.console_find_current.console_find_highlighted
,
mark
.console_find_current
{
background
:
yellow
;
}
mark
.console_find_highlighted
{
background
:
red
;
}
#console_find
{
width
:
100%
;
height
:
1em
;
...
...
This diff is collapsed.
Click to expand it.
pd/nw/index.html
+
9
−
9
View file @
053f6f20
...
...
@@ -14,7 +14,6 @@
</label>
</div>
</div>
<script
type=
"text/javascript"
src=
"index.js"
></script>
<input
style=
"display:none;"
id=
"saveDialog"
type=
"file"
nwsaveas
/>
<div
id =
"console_bottom"
>
<div
id =
"printout"
>
...
...
@@ -29,16 +28,17 @@
id=
"console_find_text"
name=
"console_find_text"
defaultValue=
"Search in Console"
style=
"width:10em;"
onfocus=
"console_find_input_focus(this)"
onblur=
"console_find_input_blur(this)"
/>
XXXXXX
style=
"width:10em;"
/>
</label>
<label>
Highlight All
<input
type=
"checkbox"
id=
"console_find_highlight"
name=
"console_find_highlight"
onchange=
"console_find_highlight_all(this);"
/>
</label>
</div>
</div>
<script>
var
t
=
document
.
getElementById
(
'
console_find_text
'
);
t
.
defaultValue
=
"
Search in Console
"
;
console_find_input_blur
(
t
);
</script>
<script
src=
"./console_search.js"
></script>
<script
type=
"text/javascript"
src=
"index.js"
></script>
</body>
</html>
This diff is collapsed.
Click to expand it.
pd/nw/index.js
+
149
−
8
View file @
053f6f20
...
...
@@ -36,6 +36,24 @@ document.getElementById("dsp_control").addEventListener("click",
}
);
var
find_bar
=
document
.
getElementById
(
'
console_find_text
'
);
find_bar
.
addEventListener
(
"
keydown
"
,
function
(
e
)
{
return
console_find_keydown
(
this
,
e
);
},
false
);
find_bar
.
addEventListener
(
"
keypress
"
,
function
(
e
)
{
console_find_keypress
(
this
,
e
);
},
false
);
find_bar
.
defaultValue
=
"
Search in Console
"
;
console_find_set_default
(
find_bar
);
// Invoke some functions to create main menus, etc.
nw
.
Window
.
get
().
on
(
"
close
"
,
function
()
{
pdgui
.
menu_quit
();
...
...
@@ -55,18 +73,138 @@ pdgui.init_socket_events();
pdgui
.
set_new_window_fn
(
nw_create_window
);
pdgui
.
set_close_window_fn
(
nw_close_window
);
// Greyed out text for the "Find" bar
function
console_find_input_focus
(
e
)
{
function
console_find_check_default
(
e
)
{
if
(
e
.
value
===
e
.
defaultValue
)
{
e
.
value
=
''
;
e
.
style
.
color
=
"
#000
"
;
return
true
;
}
else
{
return
false
;
}
}
function
console_find_set_default
(
e
)
{
e
.
value
=
e
.
defaultValue
;
e
.
setSelectionRange
(
0
,
0
);
e
.
style
.
color
=
"
#888
"
;
}
function
console_unwrap_tag
(
console_elem
,
tag_name
)
{
var
b
=
console_elem
.
getElementsByTagName
(
tag_name
),
parent_elem
;
while
(
b
.
length
)
{
parent_elem
=
b
[
0
].
parentNode
;
while
(
b
[
0
].
firstChild
)
{
parent_elem
.
insertBefore
(
b
[
0
].
firstChild
,
b
[
0
]);
}
parent_elem
.
removeChild
(
b
[
0
]);
parent_elem
.
normalize
();
}
}
function
console_find_text
(
elem
,
evt
,
callback
)
{
var
console_text
=
document
.
getElementById
(
'
p1
'
),
wrap_tag
=
'
mark
'
,
wrapper_count
;
// Check the input for default text before the event happens
if
(
console_find_check_default
(
elem
))
{
// if so, erase it
elem
.
value
=
''
;
// put this in css and use class here
elem
.
style
.
color
=
"
#000
"
;
}
window
.
setTimeout
(
function
()
{
console_unwrap_tag
(
console_text
,
wrap_tag
);
// Check after the event if the value is empty, and if
// so set it to default value
if
(
elem
.
value
===
undefined
||
elem
.
value
===
''
)
{
console_find_set_default
(
elem
);
}
else
if
(
!
console_find_check_default
(
elem
))
{
window
.
findAndReplaceDOMText
(
console_text
,
{
//preset: 'prose',
find
:
elem
.
value
.
toLowerCase
(),
wrap
:
wrap_tag
});
// The searchAndReplace API is so bad you can't even know how
// many matches there were without traversing the DOM and
// counting the wrappers!
wrapper_count
=
console_text
.
getElementsByTagName
(
wrap_tag
).
length
;
if
(
wrapper_count
<
1
)
{
elem
.
style
.
setProperty
(
'
background
'
,
'
red
'
);
}
else
{
elem
.
style
.
setProperty
(
'
background
'
,
'
white
'
);
}
}
if
(
callback
)
{
callback
();
}
},
0
);
}
// start at top and highlight the first result after a search
function
console_find_callback
()
{
console_find_traverse
.
set_index
(
0
);
console_find_traverse
.
next
();
}
function
console_find_keypress
(
elem
,
e
)
{
console_find_text
(
elem
,
e
,
console_find_callback
);
}
function
console_find_input_blur
(
e
)
{
if
(
e
.
value
===
''
||
e
.
value
===
e
.
defaultValue
)
{
e
.
value
=
e
.
defaultValue
;
e
.
style
.
color
=
"
#888
"
;
function
console_find_highlight_all
(
elem
)
{
var
matches
=
document
.
getElementById
(
'
p1
'
).
getElementsByTagName
(
'
mark
'
),
highlight_tag
=
'
console_find_highlighted
'
,
state
=
elem
.
checked
,
i
;
for
(
i
=
0
;
i
<
matches
.
length
;
i
++
)
{
if
(
state
)
{
matches
[
i
].
classList
.
add
(
highlight_tag
);
}
else
{
matches
[
i
].
classList
.
remove
(
highlight_tag
);
}
}
}
var
console_find_traverse
=
(
function
()
{
var
count
=
0
,
console_text
=
document
.
getElementById
(
'
p1
'
),
wrap_tag
=
'
mark
'
;
return
{
next
:
function
()
{
var
i
,
last
,
next
,
elements
=
console_text
.
getElementsByTagName
(
wrap_tag
);
if
(
elements
.
length
>
0
)
{
i
=
count
%
elements
.
length
;
elements
[
i
].
classList
.
add
(
'
console_find_current
'
);
if
(
elements
.
length
>
1
)
{
last
=
i
===
0
?
elements
.
length
-
1
:
i
-
1
;
next
=
(
i
+
1
)
%
elements
.
length
;
elements
[
last
].
classList
.
remove
(
'
console_find_current
'
);
elements
[
next
].
classList
.
remove
(
'
console_find_current
'
);
}
// adjust the scrollbar to make sure the element is visible,
// but only if necessary.
// I don't think this is available on all browsers...
elements
[
i
].
scrollIntoViewIfNeeded
();
count
++
;
}
},
set_index
:
function
(
c
)
{
count
=
c
;
}
}
}());
function
console_find_keydown
(
elem
,
evt
)
{
if
(
evt
.
keyCode
===
13
)
{
console_find_traverse
.
next
();
evt
.
stopPropagation
();
evt
.
preventDefault
();
return
false
;
}
else
if
(
evt
.
keyCode
===
27
)
{
// escape
}
else
if
(
evt
.
keyCode
===
8
||
// backspace or delete
evt
.
keyCode
===
46
)
{
console_find_text
(
elem
,
evt
,
console_find_callback
);
}
}
...
...
@@ -312,6 +450,7 @@ function nw_create_pd_window_menus () {
label
:
l
(
'
menu.find
'
),
click
:
function
()
{
var
find_bar
=
document
.
getElementById
(
'
console_find
'
),
find_bar_text
=
document
.
getElementById
(
'
console_find_text
'
),
text_container
=
document
.
getElementById
(
'
console_bottom
'
),
state
=
find_bar
.
style
.
getPropertyValue
(
'
display
'
);
if
(
state
===
'
none
'
)
{
...
...
@@ -319,6 +458,8 @@ function nw_create_pd_window_menus () {
find_bar
.
style
.
setProperty
(
'
display
'
,
'
inline
'
);
find_bar
.
style
.
setProperty
(
'
height
'
,
'
1em
'
);
text_container
.
scrollTop
=
text_container
.
scrollHeight
;
find_bar_text
.
focus
();
find_bar_text
.
select
();
}
else
{
text_container
.
style
.
setProperty
(
'
bottom
'
,
'
0px
'
);
find_bar
.
style
.
setProperty
(
'
display
'
,
'
none
'
);
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment