I have an TYPO3 extension which shows a list of records. As it are more than 40 pages I would like to provide an additional alphabetic index which enables visitors to jump directly to the beginning of a character.
In general all is working - except the link to the n-th page.
I have the fluid variables cur containing current character (e.g. M) and the necessary page number in pageNumber (e.g. 23).
How can I get the correct url which should look like:
https://mydomain.tld/path/to/list?tx_myextension_myextension[#widget_0][currentPage]=23&cHash=a6193a7eab129df4789343911221584b#jumplabel_M
either
<a class="page-link" href="{f:uri.page(additionalParams:{tx_myextension_myextension{#widget_0:{currentPage:pageNumber}}})}#jmplabel_{cur}">{cur}</a>
nor
<a class="page-link" href="{f:uri.page(additionalParams:{tx_myextension_myextension[#widget_0][currentPage]:pageNumber})}#jmplabel_{cur}">{cur}</a>
call the f:uri.page VH. The result is an unreplaced string in the href-parameter.
<a class="page-link" href="{f:uri.page()}?tx_phonebook_phonebook[#widget_0][currentPage]={pageNumber}#jmplabel_{cur}">{cur}</a>
looks ok, but misses the cHash and therefore results in 404 page not found.
Check how Georg Ringer does it in his News extension. Actually that's a solution for your pagination.
PaginateAdditionalParamsViewHelper.php:
https://github.com/georgringer/news/blob/master/Classes/ViewHelpers/Widget/Ajax/PaginateAdditionalParamsViewHelper.php#L30
public function render()
{
$page = (int)$this->arguments['page'];
if ($page === 0) {
return [];
}
$params = [
'tx_news_pi1' => [
'#widget_0' => [
'currentPage' => $page
]
]
];
return $params;
}
And in some template:
https://github.com/georgringer/news/blob/master/Resources/Private/Templates/Styles/Twb/Templates/ViewHelpers/Widget/Paginate/IndexAjax.html#L56, especially additionalParams key.
<f:widget.link data="{container:recordId,link:'{t:uri.ajaxAction(contextRecord:\'tt_content:{recordId}\', pluginName: \'pi1\',additionalParams:\'{n:widget.ajax.paginateAdditionalParams(page:0)}\')}'}">
<f:translate key="paginate_previous" />
</f:widget.link>
Related
I have a textarea id="task", which has a word counter id="count" connected. The counter is set to count spaces between words, so a word is only accounted for if one puts a space after it. However, if for whatever reason one finds themself in a frenzy of hitting the spacebar, each and every space is then counted as a word which thwarts the final count. Below is the code for you to see for yourselves.
What I am asking is as follows:
1) Is there a way to count only one space after each word and ignore multiple spaces?
2) Can I prevent multiple spaces in the textarea?
Since I am suspecting that the solution dwells within the realm of javascript, I kindly ask for your help as I am still a noob. I will be grateful for any suggestions, be it 1) or 2).
HTML:
<div class="options">
Task:
<textarea type="text" rows="10" cols="97" name="task" id="task" onkeypress="onTestChange01();"
autocorrect="off" spellcheck="false"></textarea>
<p>Word count: <textarea cols="10" name="count" id="count" readonly>0</textarea></p>
</div>
JAVASCRIPT:
// WORD COUNTER FUNCTION
var count = document.getElementById('count');
var input = document.getElementById('task');
input.addEventListener('keyup', function(e){
wordCounter(e.target.value);
});
function wordCounter(text) {
var text = input.value;
var wordCount = 0;
for (var i = 0; i <= text.length; i++) {
if (text.charAt(i) == ' ') {
wordCount++;
}
}
count.innerText = wordCount;
}
I tried fiddling with the JS function and its values.
Also, I found a function to change multiple spaces to one space, which did not work as expected and it disrupted the original function and the counting.
Finally, I tried preventing 'space' altogether in the textarea properties but all in vain.
Looking forward to your ideas. Thanks.
tk
I am working on Ruby on Rails project and I have implemented markdown syntax for some text descriptions in my project using redcarpet gem.
It works like charm allowing to convert markdown text to HTML as simply as
<%= markdown some_text_variable %>
But now I want to implement preview feature rendering just small part of the full text.
The following naive construction
<%= markdown some_text_variable[0..preview_length] %>
will not work because it can easily break down MD syntax resulting in confusing constructions (imagine, for example, spliting original string on the half of image link).
I came up with
<%= markdown some_text_variable[0..preview_length].split(/\r?\n/)[0..-2].join("\r\n")) %>
but it does not deal, for example, with code blocks.
Is there any way to implement such kind of preview for MD text?
Using markdown.js and / or showdown should work. Here's a StackO with the same question and answer. I personally have used showdown in an Ember app before to render a live preview of the text as it's being typed (via 2-way data binding), and it worked flawlessly.
In the fiddle below, I wrote a little Showdown parser that takes in a string of markdown, splits it on a newline (returns an array of tags), and iterates through the array. On each iteration, it removes the tags, checks the length of the resulting string, and then compares it to the max character count for the preview. Once the next iteration surpasses the max character count, it returns the preview. The do loop ensures that you will always get at least one blob of html as a preview.
Fiddle
$(function() {
var converter = new Showdown.converter();
var previewMax = 200;
$('button').click(function() {
var content = $('#markdown').val(),
charCount = 0,
i = 0,
output = '';
if (!content) {
return $('div.preview').html("Please enter some text.");
}
var mark = converter.makeHtml(content);
var mark_arr = mark.split('\n');
while (charCount < previewMax) {
var html = mark_arr[i];
var text = htmlStrip(html);
if ((charCount + text.length) > previewMax) {
var overflow = (charCount + text.length) - previewMax;
var clipAmount = text.length - overflow;
html = jQuery.truncate(mark_arr[i], { length: clipAmount });
}
output += html;
charCount += text.length;
i++;
};
$('div.preview').html(output);
$('div.full').html(mark);
});
function htmlStrip (html) {
var div = document.createElement('div');
div.innerHTML = html;
var text = div.textContent || div.innerText || "";
return text;
}
});
REVISION
I updated the function using jQuery Truncate to cut the final string into an elipses so that all your previews are the same length as the others. Also, I realized that the original function returned a long string of undefined' over and over when no text was entered, so there is a check to eliminate that. Since this loop will always return at least one html item now, I changed the do loop to a while loop for easier reading. Finally, if you want your truncation to always end at a word boundary, pass the words: true option when you call it. Obviously, this will not give you the same level of truncation for every preview, but it will improve legibility. That's it!
I want to share my preview version it was quite simple with showdown.js and prism.js syntax highlighting.
Prism.js is syntaxing easily with JavaScript and CSS. All you need to pick specific languages and download it to assets folder. Or you can specify it to specific pages.
This is going to happen in realtime preview, in a form.
In Rails form:
<div class="col-md-12">
<div class="form-group">
<%= f.label :body %>
<%= f.text_area :body, class: "form-control", rows: 10 %>
</div>
</div>
<div class="col-md-12">
<h1> Preview Markdown </h1>
<div class="form-group markdownOutput"></div>
</div>
And add this script right below a form page.
<script>
function mkdown(){
var converter = new showdown.Converter(),
$post_body = $("#post_body");
// This line will keep adding new rows for textarea.
function postBodyLengthDetector(post_body){
var lines = post_body.val().split("\n");
post_body.prop('rows', lines.length+5);
}
// Textarea rows in default '10', when focusing on this. It will expand.
$post_body.focus(function(){
postBodyLengthDetector($(this));
$('.markdownOutput').html(converter.makeHtml($post_body.val()));
});
// All simple magic goes here, each time when texting anything into textarea
//it will be generated to markdown. You are able to see preview right below of textarea.
$post_body.keyup(function() {
postBodyLengthDetector($(this));
var value = $( this ).val(),
html = converter.makeHtml(value);
$('.markdownOutput').html(html);
});
}
$(mkdown);
$(document).on("turbolinks:load", mkdown);
</script>
Here's the scenario:
I am using an ASP.NET MVC site with Angular JS and Boostrap UI. I have a dynamic ul list populated by data fed through a controller call to AngularJS, filtering on that list through an input search box. The list is also controlled through pagination (UI Bootstrap control) that I've setup to show 10 results per page for the list of 100 or so items. This list is filtered as the user types in the search box, however I would like the pagination to update as well so consider the following example:
The list has 10 pages of items (100 items), the user types some text in the input search box which filters the list down to 20 or so items, so the pagination should be updated from 10 pages to two pages.
I figure there must be a $watch setup somewhere, perhaps on the list items after it has been filtered and then update the pagination page count, however I'm pretty new to AngularJS so can someone please explain to me how this could be done?
Thanks very much. I have posted my code below:
<div data-ng-app="dealsPage">
<input type="text" data-ng-model="cityName" />
<div data-ng-controller="DestinationController">
<ul>
<li data-ng-repeat="deals in destinations | filter: cityName |
startFrom:currentPage*pageSize | limitTo:pageSize">{{deals.Location}}</li>
</ul>
<br />
<pagination rotate="true" num-pages="noOfPages" current-page="currentPage"
max-size="maxSize" class="pagination-small" boundary-links="true"></pagination>
</div>
var destApp = angular.module('dealsPage', ['ui.bootstrap', 'uiSlider']);
destApp.controller('DestinationController', function ($scope, $http) {
$scope.destinations = {};
$scope.currentPage = 1;
$scope.pageSize = 10;
$http.get('/Deals/GetDeals').success(function (data) {
$scope.destinations = data;
$scope.noOfPages = data.length / 10;
$scope.maxSize = 5;
});
});
destApp.filter('startFrom', function () {
return function (input, start) {
start = +start; //parse to int
return input.slice(start);
};
});
Because your pagination is a combination of chained filters, Angular has no idea that when cityName changes, it should reset currentPage to 1. You'll need to handle that yourself with your own $watch.
You'll also want to adjust your startFrom filter to say (currentPage - 1) * pageSize, otherwise, you always start at page 2.
Once you get that going, you'll notice that your pagination is not accurate, because it's still based on destination.length, and not the filtered sub-set of destinations. For that, you're going to need to move your filtering logic from your view to your controller like so:
http://jsfiddle.net/jNYfd/
HTML
<div data-ng-app="dealsPage">
<input type="text" data-ng-model="cityName" />
<div data-ng-controller="DestinationController">
<ul>
<li data-ng-repeat="deals in filteredDestinations | startFrom:(currentPage - 1)*pageSize | limitTo:pageSize">{{deals.Location}}</li>
</ul>
<br />
<pagination rotate="true" num-pages="noOfPages" current-page="currentPage" max-size="maxSize" class="pagination-small" boundary-links="true"></pagination>
</div>
JavaScript
var destApp = angular.module('dealsPage', ['ui.bootstrap']);
destApp.controller('DestinationController', function ($scope, $http, $filter) {
$scope.destinations = [];
$scope.filteredDestinations = [];
for (var i = 0; i < 1000; i += 1) {
$scope.destinations.push({
Location: 'city ' + (i + 1)
});
}
$scope.pageSize = 10;
$scope.maxSize = 5;
$scope.$watch('cityName', function (newCityName) {
$scope.currentPage = 1;
$scope.filteredDestinations = $filter('filter')($scope.destinations, $scope.cityName);
$scope.noOfPages = $scope.filteredDestinations.length / 10;
});
});
destApp.filter('startFrom', function () {
return function (input, start) {
start = +start; //parse to int
return input.slice(start);
};
});
The version shared on jsfiddle is compatible with ui-bootstrap 0.5.0 but from 0.6.0 onwards there have been breaking changes.
Here is a version that uses the following libraries:
angular 1.2.11
angular-ui-bootstrap 0.10.0
bootstrap 3.1.0
Here is a plunker for the same:
Angular UI Bootstrap Pagination
Hello I tried to hook this up with Firebase using Angular Fire and it only works after I type something in the search input. In the $scope.$watch method, I used Angular Fire's orderByPriorityFilter to convert the object to an array.
$scope.$watch('search', function(oldTerm, newTerm) {
$scope.page = 1;
// Use orderByPriorityFilter to convert Firebase Object into Array
$scope.filtered = filterFilter(orderByPriorityFilter($scope.contacts), $scope.search);
$scope.lastSearch.search = oldTerm;
$scope.contactsCount = $scope.filtered.length;
});
Initial load doesn't load any contacts. It's only after I start typing in the input search field.
Is there anything I can use instead of 'a' selector. Maybe something like <url href=""> or something similar. I'm trying to avoid 'a'. The reason for that is that I'm working with jQuery and its code modyfying every 'a' in the section. I want to keep some 'a's untouched. This is what i have:
HTML:
<div> <!-- █ POST █ -->
<h3>14 June 2012 - Noisettes for Spotify</h3>
<p>
We have supplied a sound equipment for the Noisettes concert on Spotify company event. Please enjoy <a class="inlink" target="_blank" href="http://www.youtube.com/watch?v=KRFHiBW9RE8">Noisettes on YouTube</a>.
</p>
</div>
JQUERY:
$(document).ready(function(){
var $posts = $('#items > div');
var maxHeight = 32;
$('a', $posts).live('click', function(){
var $par = $(this).prev('p');
var oH = parseInt($par.attr('class'));
if($par.height() == oH){
$par.animate({
'height': maxHeight
}, 'medium');
$(this).text('read more...');
}else{
$par.animate({
'height': oH
}, 'medium');
$(this).text('read less...');
}
});
$posts.each(function(){
if($('p', this).height() > maxHeight){
$('p', this)
.attr('class', $('p', this).height())
.css('height', maxHeight+'px');
$(this).append($('<a class="link">').text('read more...'));
}
});
});
It replaces my 'Noisettes on YouTube' (from html code) with 'read less...' (still working but wording changes. I was trying to use CSS but it still replaces it.
I hope I made myself clear on this :) Thanks for help in advance.
You should use a more specific selector:
$posts.find('a.SomeClass')...
Then change the links that you want this to apply to to <a class="SomeClass">.
Give all the "a" that you want to change a particular class, say "changeable", and then change your selector from $('a', $posts) to $('a.changeable', $posts)
Facebook has this unique and clever approach to localization of their site: translators (in their case users that help to translate the site voluntarily) can simply click on the not-yet-translated strings – which are marked with a green bottom border – in their natural context on the site. See http://www.facebook.com/translations/.
Now, if you ever had to deal with the translation of a website, you'll be well aware of how odd and funny some of these translations can be when using tools like poedit where the translator isn't fully aware of the spot the translated string will lated appear in on the website.
Example: Please translate "Home". In German, for instance, the start page of a website would be "Home" while the house you live in is "Heim". Now, you as the translator basically have to guess which context this term is likely to appear in on the website and translate accordingly. Chances are, you're new website on home furniture now translates as "Home-Einrichtung" which sounds ridiculous to any German.
So, my question boils down to:
Do you know any open source PHP projects that work on something like this? I'm basically looking for a framework that allows you to put your internationalized website in "translation mode" and make strings clickable and translatable e.g. through a Javascript modal.
I'm not so much looking for a full-fledged and ready-made solution, but would love to know about similar projects that I can contribute code to.
Thanks in advance!
If you want to roll your own with jquery & jquery browserLanguage, this might get you going.
Tag all translatable text's contain elements with class="i18n", and include jquery, jquery browserLanguage, and your i18n script.
1. the internationalization javascript
— this needs to accept translations via ajax from your server, like:
var i18n = {};
i18n.bank = new Array();
i18n.t = function ( text, tl=$.browserLanguage ) {
var r = false;
$.ajax({
url: "/i18n_t.php?type=request&from="+ escape(text) +"&tl="+ tl,
success: function(){ i18n.bank[text] = this; r = true; }
});
return r;
};
2. php i18n translation service
— now we need to serve up translations, and accept them
the database will look like a bunch of tables, one for each language.
// SCHEMA for each language:
CREATE TABLE `en`
(
`id` INT PRIMARY KEY AUTO INCREMENT NOT NULL,
`from` VARCHAR(500) NOT NULL,
`to` VARCHAR(500) NOT NULL
)
the php will need some connection and db manipulation.. for now this may do:
//Connect to the database
$connection = mysql_connect('host (usually localhost)', 'mysql_username' , 'mysql_password');
$selection = mysql_select_db('mysql_database', $connection);
function table_exists($tablename, $database = false) {
if(!$database) {
$res = mysql_query("SELECT DATABASE()");
$database = mysql_result($res, 0);
}
$res = mysql_query("SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = '$database' AND table_name = '$tablename'
");
return mysql_result($res, 0) == 1;
}
the code is simply:
<?php
// .. database stuff from above goes here ..
$type=$_GET["type"];
$from=$_GET["from"];
$to=$_GET["to"];
$tl=$_GET["tl"];
if (! table_exists($tl)) {
...
}
if ($type == "request") { // might want to set $tl="en" when ! table_exists($tl)
$find = mysql_query("SELECT to FROM `'$tl'` WHERE from='$from'");
$row = mysql_fetch_array($find);
echo $row['to'];
} elsif ($type == "suggest") {
$find = mysql_query("SELECT COUNT(*) AS count FROM `'$tl'` WHERE from='$from'");
if ( !(mysql_result($res, 0)) == 0 ) {
$ins = mysql_query("INSERT INTO `'$tl'` (from, to) VALUES ('$from','$to')");
}
}
?>
3. page translation mechanics
— finally we can tie them together in your webpages with some further jquery:
i18n.suggest = function (from) { // post user translation to our php
$.ajax({
url: "/i18n_t.php?type=suggest&from='+from+'&to="+ escape( $('#i18n_s').contents() ) +"&tl="+ $.browserLanguage,
success: function(){ $('#i18n_t_div').html('<em>Thanks!</em>').delay(334).fadeOut().remove(); }
});
};
$(document).ready(function() {
i18n.t("submit");
i18n.t("Thanks!");
$('.i18n').click( function(event) { //add an onClick event for all i18n spans
$('#i18n_t_div').remove;
$(this).parent().append(
'<div id="i18n_t_div"><form class="i18n_t_form">
<input type="text" id="i18n_s" name="suggestion" value="+$(this).contents()+" />
<input type="button" value="'+ i18n.bank[ "submit" ] +'" onclick="i18n.suggest( '+$(this).contents()+' )" />
</form></div>'
);
}).each(function(){
var c = $(this).contents(); //now load initial translations for browser language for all the internationalized content on the page
if ( i18n.t(c) ){
$(this).html(i18n.bank[c]);
}
});
});
Mind you I don't have a server to test this on... and I don't actually code php. :D It will take some debugging but the scaffolding should be correct.