Just for myself not to forget - good constructor for bootstrap buttons with icons - http://www.bootsnipp.com/buttons
понедельник, 19 января 2015 г.
воскресенье, 4 января 2015 г.
Lazy loaded list with infinite scroll in AngularJS
I've created small project on GitHub to demonstrate how to display lazy loaded list on the page with infinite scrolling of remote webservice results. Feel free to checkout / comment / participate / whatever else - https://github.com/maxaus/ng-lazy-load :) Run it with Grunt and you should get the same list of public events, retrieved from GitHub public API.
четверг, 4 декабря 2014 г.
Make text in ExtJS GridPanel cell selectable
I suppose it one of the most annoying thing in great in general ExtJS framework, that user can't select and copy-paste text from the grid. To fix this for your users pleasure just add simple fix to gridPanel configuration
new Ext.create('Ext.grid.Panel', {
title: 'My Grid with selectable text',
// Here the fix comes!
viewConfig: {
enableTextSelection: true
},
...
пятница, 31 октября 2014 г.
Calculating linear trend line for the chart components in JS
Display trend line is quite common problem while working with charts as front-end developer. Here I provide example of JS function for calculation linear trend line values and adding values to provided array of JSON values.
function(scores) {
// Calculating the Slope (m) of the Trendline
var count = scores.length;
var ySum = 0, xSum = 0, xySum = 0, xSqSum = 0;
$.each(scores, function( index, value ) {
xSum += value.day;
ySum += value.score;
xySum += value.day * value.score;
xSqSum += Math.pow(value.day, 2);
});
var slope = ((count * xySum) - (xSum * ySum)) / ((count * xSqSum) - Math.pow(ySum, 2));
// Calculating the y-intercept (b) of the Trendline
var yIntercept = (ySum - slope*xSum) / count;
$.each(scores, function( index, value ) {
value.trend = (value.day * slope) + yIntercept;
});
};
пятница, 17 октября 2014 г.
Correctly display of negative ranges on ExtJS bar graphs
Bar graphs from Sencha ExtJS are great, but not without challenges for developers:) On of such issue I found during building graph with both, positive and negative, ranges. For example, your values are in the range [-100, 100]. In this case default behaviour of bar chart will be to have bars drawn from "zero" vertical line, but you need to be drawn from -100. My solution was to change values first to be "actualValue+100" (always positive in our case) and then make labels display correct value, it's done with customized render function:
axes: [{
type: 'numeric',
position: 'bottom',
fields: 'score',
minimum: 0,
maximum: 200,
majorTickSteps: 4,
renderer: function (v) {
// Make axis label display correct actual value
return v - 100;
}
},
...
четверг, 16 октября 2014 г.
Crossbrowser solution to copy canvas elements
Sometimes you need to clone exisitng canvas elements to the new place, keeping its content. Solution for this problem is simple, but for IE additional workaround should be implemented, as always:)
/**
* Copy canvas element image content.
* @param oldCanvas old canvas element
* @param newCanvas new canvas element
* @param document current window document
*/
copyCanvas: function (oldCanvas, newCanvas, document) {
if (oldCanvas) {
try {
// For IE browser replace canvas element with img with
// source of old canvas, as drawImage causes
// TypeMismatchError
var agent = window.navigator.userAgent;
// Check for both, IE11 and older versions
if ((agent.indexOf('MSIE ') > -1) || (agent.indexOf('Trident/') > -1)) {
var oldImage = oldCanvas.toDataURL();
var img = document.createElement("img");
img.src = oldImage;
$(newCanvas).replaceWith(img);
} else {
var context = newCanvas.getContext('2d');
context.drawImage(oldCanvas, 0, 0);
}
} catch (e) {
console.log(e.name);
}
}
}
вторник, 30 сентября 2014 г.
Sample app on modern Java and JS stack
I'm ready to announce that started open project with sample application, having Java EE stack on backend (including Spring and build up with Gradle) and AngularJS on front-end part. Now it uses embedded HSQLDB storage, but will be migrated to MongoDB. Checkout: https://github.com/maxaus/ee-grad
среда, 17 сентября 2014 г.
Printing grids in ExtJS
In many ExtJS applications grids have to be correctly printed, but as ExtJS has no such functionality out of the box, you should use some third-party or your own solution. One of the best start points is to use Ext.ux.Printer plugin. It can be used not only for grids, but also other components, but you need to define custom renderer classes for your component, see article http://edspencer.net/2009/07/28/extuxprinter-printing-for-any-ext/. After that printing from your code is very simple:
Ext.ux.Printer.print(MyApp.components.MyGrid);
четверг, 24 июля 2014 г.
Emoticons AngularJS directive
If you have ever developed web applications including social activity, like messaging, you definitely had a moment, when you need to add emoticons to your message board. Here is an example of AngularJS directive to convert symbols to emotional icons.
Emoticons map:
Directive:
In HTML:
Emoticons map:
angular.module("myApp").value('Emoticons', {
':-)': 'http://www.freesmileys.org/smileys/smiley-basic/biggrin.gif',
':)': 'http://www.freesmileys.org/smileys/smiley-basic/biggrin.gif',
':D': 'http://www.freesmileys.org/smileys/smiley-basic/laugh.gif',
':-D': 'http://www.freesmileys.org/smileys/smiley-basic/laugh.gif',
':-|': 'http://www.freesmileys.org/smileys/smiley-basic/mellow.gif',
':|': 'http://www.freesmileys.org/smileys/smiley-basic/mellow.gif',
':-p': 'http://www.freesmileys.org/smileys/smiley-basic/tongue.gif',
':p': 'http://www.freesmileys.org/smileys/smiley-basic/tongue.gif',
':-(': 'http://www.freesmileys.org/smileys/smiley-basic/sad.gif',
':(': 'http://www.freesmileys.org/smileys/smiley-basic/sad.gif'
});
Directive:
angular.module("myApp").directive("withEmoticons", function (Emoticons, $timeout) {
return {
link: function postLink(scope, element, attrs) {
scope.replaceEmoticons = function (text) {
var patterns = [];
var metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g;
// build a regex pattern for each defined property
for (var i in Emoticons) {
if (Emoticons.hasOwnProperty(i)) { // escape metacharacters
patterns.push('(' + i.replace(metachars, '\\$&') + ')');
}
}
// build the regular expression and replace
return text.replace(new RegExp(patterns.join('|'), 'g'), function (match) {
return Emoticons[match] ?
'
' :
match;
});
};
$timeout(function () {
element.html(scope.replaceEmoticons(element.html()));
});
scope.$watch(function () {
return element.html();
}, function onChange(newVal, oldVal) {
if (newVal !== oldVal) {
$timeout(function () {
element.html(scope.replaceEmoticons(element.html()));
});
}
});
}
};
});
In HTML:
{{message}}
пятница, 30 мая 2014 г.
Plain text AngularJS filter
Many times on different web projects there is an requirement to remove HTML tags from the text (that comes from some remote place and should be displayed on the web page). Here I will provide approach, how to do it through AngularJS filter. So, filter code itself:
And how it is being used on HTML page;
/**
* Filter removes HTML from given string value.
*/
angular.module("myApp").filter('plainText', function() {
return function(val) {
//remove html tags
var s1 = val.replace(/<\/?[^>]+(>|$)/g, "");
//translate special symbols
var translate_re = /&(nbsp|amp|quot|lt|gt);/g;
var translate = {"nbsp": " ","amp" : "&","quot": "\"","lt" : "<","gt" : ">"};
return ( s1.replace(translate_re, function(match, entity) {
return translate[entity];
}) );
};
});
And how it is being used on HTML page;
{{htmlMessage.body | plainText}}
пятница, 5 июля 2013 г.
Exporting Excel spreadsheet from Spring MVC application.
Here I will provide solution for common situation, when you need to export some kind of Excel doc (e.g. report) from web application built on Spring MVC framework. It's made with help of Apache POI library, which generates spreadsheet.
In Spring config spring-excel-views.xml it should be declared like that:
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.springframework.web.servlet.view.document.AbstractExcelView;
/**
* @author Maxim Baev
*/
public class ExcelRecipeWishListView extends AbstractExcelView {
@Override
protected void buildExcelDocument(Map model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
Map productMap = (Map) model.get("productMap");
//create a wordsheet
HSSFSheet sheet = workbook.createSheet("Product list");
HSSFRow header = sheet.createRow(0);
CellStyle cellStyle = workbook.createCellStyle();
Font font = workbook.createFont();
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
cellStyle.setFont(font);
Cell headerCell1 = header.createCell(0);
headerCell1.setCellStyle(cellStyle);
headerCell1.setCellValue("Product");
Cell headerCell2 = header.createCell(1);
headerCell2.setCellStyle(cellStyle);
headerCell2.setCellValue("Quantity");
int rowNum = 1;
for (Map.Entry entry : productMap.entrySet()) {
//create the row data
HSSFRow row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(entry.getKey());
row.createCell(1).setCellValue(entry.getValue());
}
response.setHeader("Content-Disposition", "attachment; filename=\"product_list.xls\"");
}
}
In Spring config spring-excel-views.xml it should be declared like that:
Then used in main config:
And finally on your controller:
@RequestMapping(value = "/xls_wish_list")
public ModelAndView exportWishListToExcel(HttpSession session) {
List recipes = null;
Map productMap = null;
if (session.getAttribute("recipeIds") != null) {
Set recipeIdSet = (Set) session.getAttribute("recipeIds");
List recipeIds = new ArrayList(recipeIdSet);
List searchCriteria = new ArrayList(1);
searchCriteria.add(new IdSearchCriterion(recipeIds));
recipes = recipeService.getRecipes(searchCriteria);
productMap = makeProductMap(recipes);
}
//return excel view
Map model = new HashMap(1);
model.put("productMap", productMap);
return new ModelAndView(new ExcelRecipeWishListView(), model);
}
вторник, 26 февраля 2013 г.
Spring MVC form validator example
Here I provide and example of custom validation of a form fields, made with Spring MVC framework.
import com.baev.cook365.model.Recipe;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
/**
* Created by Maxim Baev.
*/
public class RecipeValidator implements Validator {
@Override
public boolean supports(Class aClass) {
return Recipe.class.equals(aClass);
}
@Override
public void validate(Object o, Errors errors) {
Recipe recipe = (Recipe) o;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "recipe.title", "fill-in-the-name", "Is required");
}
}
пятница, 11 января 2013 г.
JSF custom converter
Example of rather simple JSF converter to transform string with separated by semicolon words to the list of strings. In my case it was useful for mailbox application for email address input field with multiple email addresses.
/**
* Custom converter to transform input string value to the list of strings.
*
* @author Maxim Baev
*/
@FacesConverter(value = "stringListConverter")
public class StringListConverter implements Converter {
private static final Logger LOGGER = LoggerFactory.getLogger(StringListConverter.class);
private static final String DELIMITER = ";";
private static final String WHITESPACE = " ";
/**
* {@inheritDoc}
*/
@Override
public Object getAsObject(final FacesContext context, final UIComponent component, final String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
return Arrays.asList(value.replaceAll(WHITESPACE, StringUtils.EMPTY).split(DELIMITER));
} catch (Exception e) {
LOGGER.error("Failed to convert string to list", e);
throw new ConverterException(new FacesMessage(String.format("Cannot convert %s to list", value)), e);
}
}
/**
* {@inheritDoc}
*/
@Override
public String getAsString(final FacesContext context, final UIComponent component, final Object value) {
if (!(value instanceof List)) {
return null;
}
return StringUtils.join((List) value, DELIMITER + WHITESPACE);
}
}
пятница, 18 мая 2012 г.
Oracle XE: changing HTTP port
To change default http port used by Oracle XE all you need is execute simple command. Run SQL Command line:
SQL> connect
Enter user-name: system
Enter password:
Connected.
SQL> exec dbms_xdb.sethttpport(8088); // or any other port you want
PL/SQL procedure successfully completed.
SQL> quit
That's it!
SQL> connect
Enter user-name: system
Enter password:
Connected.
SQL> exec dbms_xdb.sethttpport(8088); // or any other port you want
PL/SQL procedure successfully completed.
SQL> quit
That's it!
вторник, 31 января 2012 г.
Running executable jar file in windows vista or windows 7
In Windows Vista or Windows 7 the manual file association editor has been removed. So you can have problems with running executable jar by double-clicking it. You can solve it in different ways:
1) Most easiest way is to use program Jarfix
2) Also you can add file association in your command prompt window using "Run as administrator”:
C:\>assoc .jar=jarfile
C:\>ftype jarfile="C:\path\to\your\javaw.exe" -jar "%1" %*
среда, 25 января 2012 г.
Resolving problems with running Apache Nutch on Windows. Part 2.
When Nutch crawling process started with '-solr' argument you can face a problem with Solr schema.xml.Some fields can be absent and you will see errors in log:
2012-01-25 11:03:46,484 WARN mapred.LocalJobRunner - job_local_0020 org.apache.solr.common.SolrException: ERROR: [doc=http://business.ngs.ru/] unknown field 'content' ERROR: [doc=http://business.ngs.ru/] unknown field 'content' request: http://localhost:8983/solr/update?wt=javabin&version=2 at org.apache.solr.client.solrj.impl.CommonsHttpSolrServer.request(CommonsHttpSolrServer.java:436) at org.apache.solr.client.solrj.impl.CommonsHttpSolrServer.request(CommonsHttpSolrServer.java:245) at org.apache.solr.client.solrj.request.AbstractUpdateRequest.process(AbstractUpdateRequest.java:105) at org.apache.solr.client.solrj.SolrServer.add(SolrServer.java:49) at org.apache.nutch.indexer.solr.SolrWriter.close(SolrWriter.java:93) at org.apache.nutch.indexer.IndexerOutputFormat$1.close(IndexerOutputFormat.java:48) at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:474) at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:411) at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:216)To fix this I've copied schema.xml for Solr from http://svn.apache.org/viewvc/nutch/branches/branch-1.4/conf/schema.xml?view=markup.
вторник, 24 января 2012 г.
Resolving problems with running Apache Nutch on Windows. Part 1.
First root of some problems with running Apache Nutch on Windows is Cygwin, as Nutch has bash scripts to run. So, install Cygwin and add its root directory to 'path' system variable (e.g. C:\Cygwin). But if you added only root directory to path you can see exception in Nutch log:
To resolve this you should add Cygwin 'bin' directory to your system path (e.g. C:\Cygwin\bin)
java.io.IOException: Expecting a line not the end of stream at org.apache.hadoop.fs.DF.parseExecResult(DF.java:109) at org.apache.hadoop.util.Shell.runCommand(Shell.java:179) at org.apache.hadoop.util.Shell.run(Shell.java:134) at org.apache.hadoop.fs.DF.getAvailable(DF.java:73) at org.apache.hadoop.fs.LocalDirAllocator$AllocatorPerContext.getLocalPathForWrite(LocalDirAllocator.java:329) at org.apache.hadoop.fs.LocalDirAllocator.getLocalPathForWrite(LocalDirAllocator.java:124) at org.apache.hadoop.mapred.MapOutputFile.getSpillFileForWrite(MapOutputFile.java:107) at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.sortAndSpill(MapTask.java:1221) at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.flush(MapTask.java:1129) at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:359) at org.apache.hadoop.mapred.MapTask.run(MapTask.java:307) at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:177)
To resolve this you should add Cygwin 'bin' directory to your system path (e.g. C:\Cygwin\bin)
среда, 18 января 2012 г.
Disabled fields in ExtJS form
If you want to disable input field in your form, don't make it:
disabled: true
In this case value of the field won't be submitted (this is standard behaviour for HTML forms). Insted of this use:
readOnly: true, fieldClass: "x-item-disabled"
In this case field value will be submitted but field itself will look like disabled and will be not editable.
среда, 11 января 2012 г.
GIT - working on a side branch
It is best to work on a side branch and follow the “merge
master/merge side” delivery procedure. The overall flow is defined here:
Here is refined set of commands, which details branch switch, and substitutes rebases on the side branch instead of merges:
1. Starting on local master, update from remote master then create a side branch
git pull origingit checkout -b JIRA-1122 origin/master
2. Now on side branch named JIRA-1122
Notice that I’ve told it to rebase
|
3. Back to local master branch
|
This updates your local master to mirror what the upstream master looks like.
4.
git mergeJIRA-1122
Your changes are merged onto master not the other way around:
git push origin master
5. You may now throw away the side branch.
git branch -dJIRA-1122
понедельник, 9 января 2012 г.
Hibernate Search re-index
I had to solve problem with re-indexing recipes for my own russian cooking portal cook365.ru when I add new entries from MySql dump to database on live server. So I added this method in my service implementation class.
@Transactional
public List<Recipe> reindexAll() {
List<Recipe> recipes = recipeDao.findAll();
EntityManager entityManager = entityManagerFactory.createEntityManager();
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
for (Recipe recipe : recipes) {
recipe = fullTextEntityManager.merge(recipe);
fullTextEntityManager.index(recipe);
}
fullTextEntityManager.flushToIndexes();
return recipes;
}
At first time I didn't added fullTextEntityManager.flushToIndexes(); and indexes were not updated, spent some time to figure out the problem.
Подписаться на:
Сообщения (Atom)
