I am creating a search with autocomplete based on a XML file.
I would like when the user enter a word, the text will be hightligh.
What I have done so far :
$(function() {
function log( message ) {
$( "<div/>" ).text( message ).prependTo( "#log" );
$( "#log" ).scrollTop( 0 );
}
$.ajax({
url: "ecole.xml",
dataType: "xml",
success: function( xmlResponse ) {
var data = $( "school", xmlResponse ).map(function() {
return {
value: $( "name", this ).text() + ", " +
( $.trim( $( "adress", this ).text() ) + ", " + $( "description", this ).text() || "(unknown article)" ),
id: $( "id", this ).text(),
text: $( "description", this ).text()
};
}).get();
$( "#birds" ).autocomplete({
source: data,
minLength: 0,
select: function( event, ui ) {
log( ui.item ?
"Selected: " + ui.item.value + ", Id: " + ui.item.id + ", Text: " + ui.item.text :
"Nothing selected, input was " + this.value );
},
});
}
});
});
I don't really understand how to do to highlight the text.
I use this code :
$(function() {
highlight: function(match, keywords) {
keywords = keywords.split(' ').join('|');
return match.replace(new RegExp("("+keywords+")", "gi"),'<b>$1</b>');
}
});
But I don't really now why and it doesn't work
Here's my HTML / PHP :
<div id="RecentEdition">
<?php
$schools = simplexml_load_file('ecoles.xml');
foreach ($schools->RecentEdition as $RecentEdition):
foreach ($RecentEdition->school as $school): ?>
<figure>
<img src='<?php echo "{$school->image} \n"; ?>' title='' />
<figcaption>
<h3>Contents</h3>
<p class="over">
<ul>
<?php foreach ($school->content as $content): ?>
<?php foreach ($content->chap as $chap): ?>
<li><?php echo "{$chap} \n"; ?></li>
<?php endforeach; ?>
<?php endforeach; ?>
</ul>
</p>
<p class="go">
View »
</p>
</figcaption>
</figure>
<?php endforeach; ?>
<?php endforeach; ?>
</div>
And here's my XML:
<?xml version="1.0" encoding="utf-8"?>
<schools>
<RecentEdition>
<school>
<name>École1</name>
<id>1</id>
<link>./Marlburian0809/index.html</link>
<image>./img/zine.jpg</image>
<content>
<chap link="./Marlburian0708/#/2/">The Master's Speech</chap>
<chap link="./Marlburian0809/#/8/">College Community</chap>
<chap link="./Marlburian0809/#/50/">Trips n Expeditions</chap>
<chap link="./Marlburian0809/#/64/">Creative Arts</chap>
<chap link="./Marlburian0809/#/92/">Sports</chap>
</content>
<description>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer luctus porta turpis, id congue nisi dapibus nec. Maecenas pulvinar blandit turpis, sit amet viverra arcu convallis id. Donec varius blandit orci nec molestie. Cras auctor, metus eget volutpat hendrerit, massa nibh tempor nunc, volutpat ultrices nibh eros vestibulum nulla. Aenean libero risus, auctor sed blandit ut, tincidunt non est. Nullam bibendum nunc non tortor eleifend consectetur. Proin porttitor, diam ac varius semper, leo odio mattis erat, id luctus ligula libero eu mi. Proin et lacus ligula. Quisque non consequat mauris. Morbi dolor mi, dapibus a condimentum ac, luctus at elit. Praesent sit amet felis at magna sagittis pharetra et vitae neque.
</description>
</school>
</RecentEdition>
</schools>
And an another question.
If I have a big text in my autocomplete e.g :
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis
vulputate nibh urna. Aliquam in arcu vel diam malesuada malesuada. Ut
volutpat hendrerit sollicitudin. Quisque vestibulum adipiscing
rhoncus. Curabitur laoreet interdum tempus. Aliquam sit amet urna quis
dui rhoncus venenatis iaculis id arcu. Proin sit amet tincidunt est.
Aenean ut tellus lectus. Vestibulum ac enim orci.
I would like that if you write the world « Interdum tempus », the result display :
« …laoreet interdum tempus. Aliquam sit… »
Is it possible ?
Many thanks for you help.
You might be confusing AutoComplete and Search Term Highlighting. Do you want to:
Slowly reveal possible text choices as the user types more letters (i.e. Google Suggestions)
-OR-
Highlight the already searched for term in a search results page
Or maybe you want to do both, but it looks like you're talking about Highlighting from the sample code, although your question is about AutoComplete...
Anyway here's some code for Autocomplete of the description and Search Term highlighting:
<?php
$q = filter_var($_REQUEST['q'], FILTER_SANITIZE_STRING);
$query = (isset($q) && !empty($q)) ? $q : "";
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Autocomplete/SearchHighlighting Example</title>
<link type="text/css" href="css/ui-lightness/jquery-ui-1.8.20.custom.css" rel="stylesheet" />
<style type="text/css">
span.highlighted {
background-color: #FFF6C6;
font-weight: bold;
}
span.term0 {
color: #161633;
}
span.term1 {
color: #331616;
}
span.term2 {
color: #163316;
}
</style>
<script type="text/javascript" src="js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.8.20.custom.min.js"></script>
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<style type="text/css">
header, section, footer, aside, nav, article, figure, figcaption, audio, video, canvas { display:block; }
</style>
</head>
<body>
<form id="search" name="search">
<label for="q">Search: </label><input type="text" id="q" name="q" value="<?php echo $query; ?>" placeholder="Enter a search term" />
</form>
<div id="RecentEdition">
<?php
$schools = simplexml_load_file('ecoles.xml');
foreach ($schools->RecentEdition as $RecentEdition):
foreach ($RecentEdition->school as $school): ?>
<figure>
<img src='<?php echo "{$school->image} \n"; ?>' title='' />
<figcaption>
<h3>Contents</h3>
<p class="over">
<ul id="results">
<?php foreach ($school->content as $content): ?>
<?php foreach ($content->chap as $chap): ?>
<li><?php echo "{$chap} \n"; ?></li>
<?php endforeach; ?>
<?php endforeach; ?>
</ul>
</p>
<p class="desc"><?php echo "{$school->description} \n"; ?></p>
<p class="go">
View »
</p>
</figcaption>
</figure>
<?php endforeach; ?>
<?php endforeach; ?>
</div>
<script type="text/javascript">
$(function() {
//Autocomplete
$("#q").autocomplete({
//define callback to format results
source: function(req, add){
//pass request to server
$.getJSON('search.php?callback=?', req, function(data) {
var suggestions = []; //create array for response objects
//process response
$.each(data, function(i, terms){
suggestions.push(terms.term);
});
add(suggestions); //pass array to callback
});
},
//define select handler: Search Term Highlighting function
select: function(match, keywords) {
var rawSearchString = $('#q').val().replace(/[a-zA-Z0-9\?\&\=\%\#]+s\=(\w+)(\&.*)?/,"$1"); // Return sanitized search string if it exists (term should be FIRST URL PARAMETER)
var searchString = rawSearchString.replace(/ /g,"\|").replace("?term=",""); // Replace '+' and '%20' with '|' for regex
var searchTerms = searchString.split('|'); // Split search terms on '|' and iterate over resulting array
for (var j in searchTerms) {
var regex = new RegExp(">([^<]*)?("+searchTerms[j]+")([^>]*)?<", "ig"); // this regex is the secret, it prevents text within tag declarations from being affected
var tempHTML = $('#RecentEdition').html(); // Do regex replace
$('#RecentEdition').html(tempHTML.replace(regex, '>$1<span class="highlighted term'+j+'">$2</span>$3<')); // Inject span with class of 'highlighted termX' for term highlighting
}
}
});
});
</script>
</body>
</html>
And the PHP search file (call it "search.php") using xPath:
<?php
header('content-type: application/json; charset=utf-8');
$term = urldecode($_REQUEST['term']);
$callback = $_GET["callback"];
$html = new DOMDocument();
#$html->load("ecoles.xml");
$xpath = new DOMXPath($html);
$query = "//schools/RecentEdition/school/description[contains(.,'".$term."')]";
$nodelist = $xpath->query($query);
$i = 0;
foreach ($nodelist as $n) {
$result = trim($n->nodeValue);
$resultArray[$i] = array( "term" => str_replace('"',"'",substr($result,strpos($result,$term),25)) );
$i++;
}
$resultJSON = json_encode($resultArray);
echo $callback."(".$resultJSON.")";
?>
DEMO here:
http://bcmoney-mobiletv.com/widgets/autocomplete/
Related
I have a ScrollView in SwiftUI with multiple elements, some of them expands on tap.
struct ExpandingView: View {
#State var showContent = false
var body: some View {
VStack {
HStack {
Button(action: {withAnimation {
self.showContent.toggle()
}
}) {
Image(systemName: "chevron.right.circle")
}
Text("TITLE")
.padding(.leading, 10)
Spacer()
}
if showContent {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras volutpat dapibus ante eget laoreet. Aenean lacus elit, auctor ut nisl id, fermentum pretium mi. Quisque lacus nisl, suscipit hendrerit est sed, congue dictum augue. Suspendisse semper viverra accumsan. Maecenas commodo turpis convallis nisl bibendum pharetra.")
.transition(AnyTransition.move(edge: .top).combined(with: .opacity))
}
}
}
}
struct Test: View {
var body: some View {
ScrollView {
ExpandingView()
ExpandingView()
ExpandingView()
Text("Some static text")
}
}
}
If you try to open one of the expanding texts, you will see that the transition is not smooth, it kind of like jumps and then the transition starts.
So here is what I've tried:
If I remove the scrollview and put this to VStack for example it is working fine, but that is not an option because I have much more elements which will not fit on the screen.
I've tried to set an animation for the scrollview because I read that it solves this kind of problem, like this:
ScrollView {
ExpandingView()
ExpandingView()
ExpandingView()
Text("Some static text")
}.animation(.spring())
It works fine in terms of the opening transition, it even looks better with the spring effect, but the spring animation for the whole scrollview plays when the view appears, which I don't want.
Again, if I change the ScrollView to a VStack, the animation does not play on appearing which is nice, but I have to use a scrollview. So the best solution for me would be to keep the animation for opening the texts, but somehow remove it when the view appears.
Here is possible solution. Read also comments inline. Tested with Xcode 11.4 / iSO 13.4
struct ExpandingView: View {
#State var showContent = false
var body: some View {
VStack {
HStack {
Button(action: {
self.showContent.toggle()
}) {
Image(systemName: "chevron.right.circle")
}
Text("TITLE")
.padding(.leading, 10)
Spacer()
}
if showContent {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras volutpat dapibus ante eget laoreet. Aenean lacus elit, auctor ut nisl id, fermentum pretium mi. Quisque lacus nisl, suscipit hendrerit est sed, congue dictum augue. Suspendisse semper viverra accumsan. Maecenas commodo turpis convallis nisl bibendum pharetra.")
.fixedSize(horizontal: false, vertical: true)
.transition(AnyTransition.move(edge: .top).combined(with: .opacity))
}
}
}
}
struct DemoExpandingView: View {
// initial nil to avoid initial animation
#State private var animation: Animation? = nil
var body: some View {
ScrollView {
VStack {
ExpandingView()
ExpandingView()
ExpandingView()
Text("Some static text")
}.animation(animation) // << needed to animate static section
}
.onAppear {
DispatchQueue.main.async {
// assign in-container animation `after` container rendered
self.animation = .default
}
}
}
}
I know there are other issues with the error "addImage does not support files of type 'UNKNOWN'", but the difference is that I'm not using addImage directly, but fromHTML to convert an HTML that contains images in an Angular 5+ app.
Curiosly, the images by themselves are not the problem, because they are successfully converted to PDF in this fiddle which uses simple jQUery instead of Angular. So the problem lays in the NPM version of the jsPDF code. Maybe that version of the code does not support images in formats other than PNG?
In this particular case, I don't have control over the images, I only need grab the HTML section and convert it to PDF.
The error message is:
ERROR Error: addImage does not support files of type 'UNKNOWN', please ensure that a plugin for 'UNKNOWN' support is added.
at Object.x.addImage (jspdf.min.js:50)
at k (jspdf.min.js:202)
at jspdf.min.js:202
at l (jspdf.min.js:202)
at Image.i.onerror.i.onload (jspdf.min.js:202)
at Image.wrapFn (zone.js:1188)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:16147)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)
The TS code is:
#ViewChild('content') recipeView: ElementRef;
downloadPDF() {
const doc = new jsPDF();
const specialElementHandlers = {
'#editor': function (element, renderer) {
return true;
}
};
const content = this.recipeView.nativeElement;
doc.fromHTML(content, 15, 15, {
'width': 190,
'elementHandlers': specialElementHandlers
}, (dispose) => {
doc.save('test.pdf');
});
}
<div class="row" #content>
<h1>The Title</h1>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Eos, modi dolores? Aliquam cum fuga vero velit! Vel
temporibus natus quasi accusantium! Recusandae quaerat qui exercitationem, debitis omnis deserunt dolorem non.</p>
<br />
<img src="http://a5.mzstatic.com/eu/r30/Purple3/v4/3d/57/31/3d573127-31d5-e4a9-9f8e-986c4616d467/icon175x175.png"
alt="" width="175" height="175">
<img src="https://http2.mlstatic.com/corte-para-hallacas-produccion-nacional-60-unidades-para-60-D_NQ_NP_869908-MLA25589543992_052017-F.webp"
alt="" width="175" height="175">
<img src="https://4.bp.blogspot.com/-C-PxcAwhHXo/WlWDzAmHB7I/AAAAAAAAG8k/hblgAA_HrIIYW_VPzVNuXb7ZjFnxKpduwCLcBGAs/s1600/como-hacer-empanadas-venezolanas.jpg"
alt="" width="175" height="175">
<br />
</div>
<button class="btn" (click)="downloadPDF()">PDF</button>
How can I have a different Text when a Element is selected then what is displayed yet.
Background: The Text I display for in the Option is pretty long, so I want to show a shorter version, when it is slected.
You can use the templateSelection option of Select2 with some custom attribute to option tag
HTML:
<select id="long" class="js-example-basic-multiple" multiple="multiple">
<option data-custom="" value="all">All </option>
<option data-custom="Lorem ipsum" value="#FF0000">Lorem ipsum dolor sit amet consectetur adipiscing elit</option>
<option data-custom="Sed do" value="#00FF00">Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</option>
<option data-custom="Ut enim" value="#0000FF">Ut enim ad minim veniam quis nostrud exercitation</option>
<option data-custom="Duis aute" value="#FFFF00">Duis aute irure dolor in reprehenderit in voluptate velit esse</option>
</select>
Javascript:
jQuery(function() {
jQuery('#long').select2({
templateSelection: function (selection) {
return jQuery(selection.element).data('custom');
}
});
});
https://jsfiddle.net/rijokpaul/phz9e5cs/4/
im trying to restrict 120 characters to be displayed.while the rest should be represented as "(more..)".which is make clickable to view the entire content.when i enter desc with space..the "(more..)" moves to the second..if i dont use space...it moves to the first line.
<h:outputScript>interaction360();
function interaction360(){
$(document).ready(function(){
var maxLength = 120;
$(".show-read-more").each(function(){
var myStr = $(this).text();
if($.trim(myStr).length > maxLength){
var newStr = myStr.substring(0, maxLength);
var removedStr = myStr.substring(maxLength, $.trim(myStr).length);
$(this).empty().html(newStr);
$(this).append('<span class="more-text"> (more...) </span>');
}
});
$(".more-text").css("color","blue");
});
}
Live Demo Link : CodePen
HTML code :
<span class="more">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</span>
CSS Code :
.morecontent span { display: none; }
.morelink { display: block; }
jQuery Code:
$(document).ready(function() {
// Configure/customize these variables.
var showChar = 120; // How many characters are shown by default
var ellipsestext = "...";
var moretext = "Show more ...";
var lesstext = "Show less";
$('.more').each(function() {
var content = $(this).html();
if(content.length > showChar) {
var c = content.substr(0, showChar);
var h = content.substr(showChar, content.length - showChar);
var html = c + '<span class="moreellipses">' + ellipsestext+ ' </span><span class="morecontent"><span>' + h + '</span> ' + moretext + '</span>';
$(this).html(html);
}
});
$(".morelink").click(function(){
if($(this).hasClass("less")) {
$(this).removeClass("less");
$(this).html(moretext);
} else {
$(this).addClass("less");
$(this).html(lesstext);
}
$(this).parent().prev().toggle();
$(this).prev().toggle();
return false;
});
});
Hope it will work for you.
For the problem I'm trying to solve, I have a table with unique content for each row. The rows are allowed to be reordered via a handle, and the content of each row is not always of uniform height. Sometimes large amounts of text and / or images appear within a row.
There can also be multiple tables with rows that can be reordered, so I'm using the containment property to prevent dragging into other zones and other problematic issues that occur when dragging outside the desired area.
The problem is when I attempt to drag a "tall" row to the top or bottom of the order when the top and bottom are "short" by comparison. Essentially I am not allowed to drag tall rows to the these positions. I have searched for a solution and have come up short. Any help would be appreciated.
Working example here: http://jsfiddle.net/jeffvoigt/XyPzf/
Neither of the two middle rows can be dragged to the top or bottom of the list.
HTML:
<div class="container">
<table id="sortable">
<tr class="odd">
<td><p>[=]</p></td>
<td>Single Line of Text</td>
</tr>
<tr class="even">
<td><p>[=]</p></td>
<td>Aenean porta, tellus quis auctor elementum, risus ante ornare augue, eu elementum nunc libero ut nisi. Pellentesque sed vestibulum tellus. Proin convallis enim eget felis iaculis viverra vestibulum lorem semper. Aliquam imperdiet viverra lorem, ut dignissim felis laoreet vel. Suspendisse fermentum neque eu est vestibulum bibendum. Maecenas dignissim egestas tempor. Ut tincidunt metus sed felis ornare nec sollicitudin risus gravida. Duis vitae mauris quis risus ultricies malesuada. Nulla facilisi. Phasellus fringilla, arcu eget congue sollicitudin, lorem elit ullamcorper ante, non fermentum orci mauris at tellus. Maecenas suscipit sodales molestie. Mauris luctus porta dui non volutpat.</td>
</tr>
<tr class="odd">
<td><p>[=]</p></td>
<td><img src="http://www.google.com/intl/en_ALL/images/logos/images_logo_lg.gif" /></td>
</tr>
<tr class="even">
<td><p>[=]</p></td>
<td>Single Line of Text</td>
</tr>
</table>
</div>
Javascript:
$( "#sortable tbody" ).sortable({
axis: "y",
containment: ".container",
cursor: "move",
handle: "p"
});
I faced the same issue. This is the quick solution:
$('.collections').sortable({
handle: 'h3',
axis: 'y',
containment: 'parent',
items: '.collection',
cursor: 'move',
tolerance: 'pointer',
scroll: true,
beforeStop: function(event, ui) {
var lastElemTop = $('.collections .collection:last-child').position().top;
var currElemTop = ui.position.top;
var currElemHeight = ui.item.height();
if (currElemTop + currElemHeight * 2 > lastElemTop) {
$('.collections .collection:last-child').insertBefore(ui.item);
}
}
});
The problem is the placement of your handle determines the Y position of the sort in relation to the handle it is on top of. So, to demonstrate, go to jsFiddle and add a valign=top to your big text area. The handle moves to the top of the sortable element, and when you drag it to the top where the short line of text is it will snap into place, but you cannot get it to sort to the bottom. However, if you update the fiddle to be valign=bottom, you may snap it to the bottom but not the top.
Solutions would be to either make your entire content area a sortable handle or perhaps move your handles out to the left of the content (making that the 'sortable' area only) and drag only the handles (not the content), then allow the the content area to update upon a new sort.
Basically, it needs to be some how re-envisioned or designed to function properly.
I encountered this very same problem. It seems like this only happens when there is no content or spacing beneath the jQuery Sortable list.
Just adding some spacing (e.g. <div id="end-of-page-spacer" style="height: 500px;"></div>) allowed me to drag large rows beneath smaller rows situated at the bottom of the list.