Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Implemented url and regroup tags

  • Loading branch information...
commit 3ccef9d7cc7f7a183212b1c5b563fae7765d4a5e 1 parent abad5be
Anders Hellerup Madsen authored
View
6 djangode.js
@@ -94,7 +94,8 @@ exports.makeApp = function(urls, options) {
options = options || {};
var show_404 = (options.show_404 || default_show_404);
var show_500 = (options.show_500 || default_show_500);
- return function(req, res) {
+
+ var app = function(req, res) {
debuginfo.last_request = req;
debuginfo.last_response = res;
var path = url.parse(req.url)["pathname"];
@@ -120,6 +121,9 @@ exports.makeApp = function(urls, options) {
show_500(req, res, e);
}
}
+ app.urls = {};
+ urls.forEach(function (item) { app.urls[item[2]] = item[0]; });
+ return app;
}
function default_show_404(req, res) {
View
2  example.js
@@ -1,4 +1,4 @@
-var dj = require('djangode');
+var dj = require('./djangode');
var app = dj.makeApp([
['^/$', function(req, res) {
View
64 template/template_defaults.js
@@ -23,17 +23,12 @@ NOTE:
Missing tags:
ssi (will require ALLOWED_INCLUDE_ROOTS somehow)
-
debug
- regroup
- widthratio
-
- url
-
NOTE:
cycle tag does not support legacy syntax (row1,row2,row3)
load takes a path - like require. Loaded module must expose tags and filters objects.
+ url tag relies on app being set in process.djangode_app_config
*/
var filters = exports.filters = {
@@ -590,8 +585,43 @@ var nodes = exports.nodes = {
callback(false, Math.round(current_val / max_val * constant_val) + "");
}
- }
+ },
+
+ RegroupNode: function (item, key, name) {
+ return function (context, callback) {
+ var list = context.get(item);
+ if (!list instanceof Array) { callback(false, ''); }
+
+ var dict = {};
+ var grouped = list
+ .map(function (x) { return x[key]; })
+ .filter(function (x) { var val = dict[x]; dict[x] = x; return !val; })
+ .map(function (grp) {
+ return { grouper: grp, list: list.filter(function (o) { return o[key] === grp }) };
+ });
+ context.set(name, grouped);
+ callback(false, '');
+ }
+ },
+
+ UrlNode: function (url_name, replacements, item_name) {
+
+ return function (context, callback) {
+ var match = process.djangode_urls[context.get(url_name)]
+ if (!match) { return callback('no matching urls for ' + url_name_val); }
+
+ var url = string_utils.regex_to_string(match, replacements.map(function (x) { return context.get(x); }));
+ url = '/' + url;
+
+ if (item_name) {
+ context.set( item_name, url);
+ callback(false, '');
+ } else {
+ callback(false, url);
+ }
+ }
+ }
};
var tags = exports.tags = {
@@ -798,5 +828,25 @@ var tags = exports.tags = {
return nodes.SpacelessNode(node_list);
},
'widthratio': simple_tag(nodes.WithRatioNode, { argcount: 3 }),
+ 'regroup': simple_tag(nodes.RegroupNode, { argcount: 5, mustbe: { 2: 'by', 4: 'as' }, exclude: [2, 4] }),
+
+ 'url': function (parser, token) {
+ var parts = token.split_contents();
+ parts.shift();
+
+ var url_name = parts.shift();
+
+ if (parts[parts.length - 2] === 'as') {
+ var item_name = parts.pop();
+ parts.pop();
+ }
+
+ // TODO: handle qouted strings with commas in them correctly
+ var replacements = parts.join('').split(/\s*,\s*/)
+
+ return nodes.UrlNode(url_name, replacements, item_name);
+ }
+
+
};
View
62 template/template_defaults.tags.test.js
@@ -243,19 +243,9 @@ testcase('include')
make_parse_and_execute_test('her er en hestgiraf.', '{% include name %}');
testcase('load')
-
- exports.filters = { testfilter: function () { return 'hestgiraf'; } }
- exports.tags = {
- testtag: function () {
- return function (context, callback) {
- callback('', 'hestgiraf')
- };
- }
- };
-
- make_parse_and_execute_test('hestgiraf', '{% load ./template_defaults.tags.test %}{{ 100|testfilter }}');
- make_parse_and_execute_test('hestgiraf', '{% load "./template_defaults.tags.test" %}{{ 100|testfilter }}');
- make_parse_and_execute_test('hestgiraf', '{% load ./template_defaults.tags.test %}{% testtag %}');
+ make_parse_and_execute_test('hestgiraf', '{% load ./load_tag_test %}{{ 100|testfilter }}');
+ make_parse_and_execute_test('hestgiraf', '{% load "./load_tag_test" %}{{ 100|testfilter }}');
+ make_parse_and_execute_test('hestgiraf', '{% load ./load_tag_test %}{% testtag %}');
testcase('templatetag')
make_parse_and_execute_test('{%', '{% templatetag openblock %}');
@@ -275,5 +265,51 @@ testcase('widthratio')
setup(function () { return {obj:{this_value: 175, max_value: 200 } }; });
make_parse_and_execute_test('88', '{% widthratio this_value max_value 100 %}');
+testcase('regroup')
+ setup(function () {
+ return {
+ obj: {
+ people: [
+ {'first_name': 'George', 'last_name': 'Bush', 'gender': 'Male'},
+ {'first_name': 'Bill', 'last_name': 'Clinton', 'gender': 'Male'},
+ {'first_name': 'Margaret', 'last_name': 'Thatcher', 'gender': 'Female'},
+ {'first_name': 'Condoleezza', 'last_name': 'Rice', 'gender': 'Female'},
+ {'first_name': 'Pat', 'last_name': 'Smith', 'gender': 'Unknown'}
+ ]
+ }
+ };
+ });
+
+ make_parse_and_execute_test('<ul>' +
+ '<li>Male:<ul><li>George Bush</li><li>Bill Clinton</li></ul></li>' +
+ '<li>Female:<ul><li>Margaret Thatcher</li><li>Condoleezza Rice</li></ul></li>' +
+ '<li>Unknown:<ul><li>Pat Smith</li></ul></li></ul>',
+ '{% regroup people by gender as gender_list %}' +
+ '<ul>{% for gender in gender_list %}<li>{{ gender.grouper }}:' +
+ '<ul>{% for item in gender.list %}<li>{{ item.first_name }} {{ item.last_name }}</li>{% endfor %}' +
+ '</ul></li>{% endfor %}</ul>');
+
+testcase('url')
+ setup(function () {
+ process.djangode_urls = {
+ 'news-views-special_case_2003': /^articles\/2003\/$/,
+ 'news-views-year_archive': /^articles\/(\d{4})\/$/,
+ 'news-views-month_archive': /^articles\/(\d{4})\/(\d{2})\/$/,
+ 'news-views-article_detail': /^articles\/(\d{4})\/(\d{2})\/(\d+)\/$/
+ };
+ return { obj: { year: 1981, month: 12, date: 2, url_name: 'news-views-article_detail' } };
+ });
+ teardown( function () {
+ delete process.djangode_urls;
+ });
+ make_parse_and_execute_test("/articles/2003/", "{% url 'news-views-special_case_2003' %}");
+ make_parse_and_execute_test("/articles/1981/", "{% url 'news-views-year_archive' 1981 %}");
+ make_parse_and_execute_test("/articles/1981/12/", "{% url 'news-views-month_archive' 1981 , 12 %}");
+ make_parse_and_execute_test("/articles/1981/12/2/", "{% url url_name year, month, date %}");
+
+ make_parse_and_execute_test("/articles/2003/",
+ "{% url 'news-views-special_case_2003' as the_url %}{{ the_url }}");
+ make_parse_and_execute_test("/articles/1981/12/",
+ "{% url 'news-views-month_archive' 1981, 12 as the_url %}{{ the_url }}");
run();
View
1  template_example.js
@@ -59,4 +59,5 @@ var app = dj.makeApp([
]);
dj.serve(app, 8009);
+process.djangode_urls = app.urls;
View
53 utils/string.js
@@ -203,4 +203,57 @@ function wordwrap (str, int_width, str_break, cut) {
exports.wordwrap = wordwrap;
+// replace groups in regex like string with replacer
+function replace_groups(input, replacer) {
+ var i, out = '', cnt = 0;
+ for (i = 0; i < input.length; i += 1) {
+ if (input[i] === '\\') {
+ if (cnt === 0) {
+ out += input[i] + input[i + 1];
+ }
+ i += 1;
+ continue;
+ }
+ if (cnt === 0 && input[i] !== '(') {
+ out += input[i];
+ continue;
+ }
+ if (input[i] === '(') {
+ cnt += 1;
+ } else if (input[i] === ')') {
+ cnt -= 1;
+ if (cnt === 0) {
+ out += replacer;
+ }
+ }
+ }
+ return out;
+}
+
+exports.regex_to_string = function (re, group_replacements) {
+ var s = re.toString();
+
+ // remove leading and trailing slashes
+ s = s.substr(1, s.length - 2);
+
+ // replace groups with '(())'
+ s = replace_groups(s, '(())');
+
+ // remove special chars
+ s = s.replace(/\^|\$|\*|\+|\?|\.|\\cX|\\xhh|\\uhhhh|\\./g, function (m) {
+ if (m[0] === '\\') {
+ if (m.substr(1).match(/f|r|n|t|v|\d+|b|s|S|w|W|d|D|b|B/)) { return ''; }
+ if (m.substr(1).match(/c.|x..|u..../)) { return eval("'" + m + "'"); }
+ return m[1];
+ }
+ return '';
+ });
+
+ // replace groups with replacers
+ s = s.replace(/\(\(\)\)/g, function () { return (group_replacements || []).shift() || ''; });
+
+ return s;
+}
+
+
View
15 utils/string.test.js
@@ -1,4 +1,5 @@
var sys = require('sys');
+
process.mixin(GLOBAL, require('./test').dsl);
process.mixin(GLOBAL, require('./string'));
@@ -29,5 +30,19 @@ testcase('wrap')
test('should wrap text', function () {
assertEquals('Joel \nis a \nslug', wordwrap('Joel is a slug', 5));
});
+testcase('regex_to_string')
+ test('should work without groups', function () {
+ assertEquals('hest', regex_to_string(/hest/));
+ assertEquals('hest', regex_to_string(/^hest$/));
+ assertEquals('hestgiraf', regex_to_string(/hest\s*giraf\d+/));
+ assertEquals('hest*', regex_to_string(/hest\*/));
+ assertEquals('hestgiraf', regex_to_string(/hest(tobis)giraf/));
+ });
+
+ test('should replace groups with input', function () {
+ assertEquals('shows/hest/34/', regex_to_string(/^shows\/(\w+)\/(\d+)\/$/, ['hest', 34]));
+ assertEquals('shows/giraf/90/', regex_to_string(/^shows\/(hest(?:laks|makrel))\/(\d+)\/$/, ['giraf', 90]));
+ });
run();
+
Please sign in to comment.
Something went wrong with that request. Please try again.