Skip to content
This repository has been archived by the owner on Aug 30, 2024. It is now read-only.

Commit

Permalink
Implement "any" filtering for Instances landing page.
Browse files Browse the repository at this point in the history
  • Loading branch information
kamalgill committed Nov 4, 2013
1 parent 4f1aff8 commit b27eaf8
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 4 deletions.
20 changes: 19 additions & 1 deletion koala/static/js/pages/landingpage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @fileOverview Common JS for Landing pages
* @requires AngularJS
* @requires AngularJS and Purl jQuery URL parser
*
*/

Expand All @@ -9,13 +9,31 @@ angular.module('LandingPage', [])
$scope.items = [];
$scope.unfilteredItems = [];
$scope.sortBy = '-launch_time';
$scope.urlParams = $.url().param();
$scope.applyAnyGetRequestFilters = function() {
$scope.items = $scope.items.filter(function(item) {
for (var key in $scope.urlParams) {
if ($scope.urlParams.hasOwnProperty(key) && $.url().param(key)) {
console.log(key + ': ' + $.url().param(key));
if (item[key] === $.url().param(key)) {
return item
}
}
}
});
};
$scope.getItems = function(jsonItemsEndpoint) {
$scope.itemsLoading = true;
$http.get(jsonItemsEndpoint).success(function(oData) {
var results = oData ? oData.results : [];
$scope.itemsLoading = false;
$scope.items = results;
$scope.unfilteredItems = results;
if ($.url().param('filter')) {
if ($.url().param('anyall') === 'any') {
$scope.applyAnyGetRequestFilters();
}
}
});
};
/* Filter items client side based on search criteria.
Expand Down
267 changes: 267 additions & 0 deletions koala/static/js/thirdparty/utils/purl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/*
* Purl (A JavaScript URL parser) v2.3.1
* Developed and maintanined by Mark Perkins, mark@allmarkedup.com
* Source repository: https://github.com/allmarkedup/jQuery-URL-Parser
* Licensed under an MIT-style license. See https://github.com/allmarkedup/jQuery-URL-Parser/blob/master/LICENSE for details.
*/

;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else {
window.purl = factory();
}
})(function() {

var tag2attr = {
a : 'href',
img : 'src',
form : 'action',
base : 'href',
script : 'src',
iframe : 'src',
link : 'href',
embed : 'src',
object : 'data'
},

key = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'], // keys available to query

aliases = { 'anchor' : 'fragment' }, // aliases for backwards compatability

parser = {
strict : /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, //less intuitive, more accurate to the specs
loose : /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs
},

isint = /^[0-9]+$/;

function parseUri( url, strictMode ) {
var str = decodeURI( url ),
res = parser[ strictMode || false ? 'strict' : 'loose' ].exec( str ),
uri = { attr : {}, param : {}, seg : {} },
i = 14;

while ( i-- ) {
uri.attr[ key[i] ] = res[i] || '';
}

// build query and fragment parameters
uri.param['query'] = parseString(uri.attr['query']);
uri.param['fragment'] = parseString(uri.attr['fragment']);

// split path and fragement into segments
uri.seg['path'] = uri.attr.path.replace(/^\/+|\/+$/g,'').split('/');
uri.seg['fragment'] = uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/');

// compile a 'base' domain attribute
uri.attr['base'] = uri.attr.host ? (uri.attr.protocol ? uri.attr.protocol+'://'+uri.attr.host : uri.attr.host) + (uri.attr.port ? ':'+uri.attr.port : '') : '';

return uri;
}

function getAttrName( elm ) {
var tn = elm.tagName;
if ( typeof tn !== 'undefined' ) return tag2attr[tn.toLowerCase()];
return tn;
}

function promote(parent, key) {
if (parent[key].length === 0) return parent[key] = {};
var t = {};
for (var i in parent[key]) t[i] = parent[key][i];
parent[key] = t;
return t;
}

function parse(parts, parent, key, val) {
var part = parts.shift();
if (!part) {
if (isArray(parent[key])) {
parent[key].push(val);
} else if ('object' == typeof parent[key]) {
parent[key] = val;
} else if ('undefined' == typeof parent[key]) {
parent[key] = val;
} else {
parent[key] = [parent[key], val];
}
} else {
var obj = parent[key] = parent[key] || [];
if (']' == part) {
if (isArray(obj)) {
if ('' !== val) obj.push(val);
} else if ('object' == typeof obj) {
obj[keys(obj).length] = val;
} else {
obj = parent[key] = [parent[key], val];
}
} else if (~part.indexOf(']')) {
part = part.substr(0, part.length - 1);
if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
parse(parts, obj, part, val);
// key
} else {
if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
parse(parts, obj, part, val);
}
}
}

function merge(parent, key, val) {
if (~key.indexOf(']')) {
var parts = key.split('[');
parse(parts, parent, 'base', val);
} else {
if (!isint.test(key) && isArray(parent.base)) {
var t = {};
for (var k in parent.base) t[k] = parent.base[k];
parent.base = t;
}
if (key !== '') {
set(parent.base, key, val);
}
}
return parent;
}

function parseString(str) {
return reduce(String(str).split(/&|;/), function(ret, pair) {
try {
pair = decodeURIComponent(pair.replace(/\+/g, ' '));
} catch(e) {
// ignore
}
var eql = pair.indexOf('='),
brace = lastBraceInKey(pair),
key = pair.substr(0, brace || eql),
val = pair.substr(brace || eql, pair.length);

val = val.substr(val.indexOf('=') + 1, val.length);

if (key === '') {
key = pair;
val = '';
}

return merge(ret, key, val);
}, { base: {} }).base;
}

function set(obj, key, val) {
var v = obj[key];
if (typeof v === 'undefined') {
obj[key] = val;
} else if (isArray(v)) {
v.push(val);
} else {
obj[key] = [v, val];
}
}

function lastBraceInKey(str) {
var len = str.length,
brace,
c;
for (var i = 0; i < len; ++i) {
c = str[i];
if (']' == c) brace = false;
if ('[' == c) brace = true;
if ('=' == c && !brace) return i;
}
}

function reduce(obj, accumulator){
var i = 0,
l = obj.length >> 0,
curr = arguments[2];
while (i < l) {
if (i in obj) curr = accumulator.call(undefined, curr, obj[i], i, obj);
++i;
}
return curr;
}

function isArray(vArg) {
return Object.prototype.toString.call(vArg) === "[object Array]";
}

function keys(obj) {
var key_array = [];
for ( var prop in obj ) {
if ( obj.hasOwnProperty(prop) ) key_array.push(prop);
}
return key_array;
}

function purl( url, strictMode ) {
if ( arguments.length === 1 && url === true ) {
strictMode = true;
url = undefined;
}
strictMode = strictMode || false;
url = url || window.location.toString();

return {

data : parseUri(url, strictMode),

// get various attributes from the URI
attr : function( attr ) {
attr = aliases[attr] || attr;
return typeof attr !== 'undefined' ? this.data.attr[attr] : this.data.attr;
},

// return query string parameters
param : function( param ) {
return typeof param !== 'undefined' ? this.data.param.query[param] : this.data.param.query;
},

// return fragment parameters
fparam : function( param ) {
return typeof param !== 'undefined' ? this.data.param.fragment[param] : this.data.param.fragment;
},

// return path segments
segment : function( seg ) {
if ( typeof seg === 'undefined' ) {
return this.data.seg.path;
} else {
seg = seg < 0 ? this.data.seg.path.length + seg : seg - 1; // negative segments count from the end
return this.data.seg.path[seg];
}
},

// return fragment segments
fsegment : function( seg ) {
if ( typeof seg === 'undefined' ) {
return this.data.seg.fragment;
} else {
seg = seg < 0 ? this.data.seg.fragment.length + seg : seg - 1; // negative segments count from the end
return this.data.seg.fragment[seg];
}
}

};

}

purl.jQuery = function($){
if ($ != null) {
$.fn.url = function( strictMode ) {
var url = '';
if ( this.length ) {
url = $(this).attr( getAttrName(this[0]) ) || '';
}
return purl( url, strictMode );
};

$.url = purl;
}
};

purl.jQuery(window.jQuery);

return purl;

});
1 change: 1 addition & 0 deletions koala/templates/instances/instances.pt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
</div>

<div metal:fill-slot="tail_js">
<script src="${request.static_url('koala:static/js/thirdparty/utils/purl.js')}"></script>
<script src="${request.static_url('koala:static/js/pages/landingpage.js')}"></script>
</div>

Expand Down
10 changes: 7 additions & 3 deletions koala/templates/macros.pt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
<h6>Filters</h6>
<form class="custom" method="get" id="properties-filter-form" action="${request.current_route_url()}">
<div class="match-condition">
Match <input type="radio" name="anyall" value="all" checked="checked" /> all
<input type="radio" name="anyall" value="any" /> any
Match
<input type="radio" name="anyall" value="any" checked="checked"
tal:attributes="checked request.params.get('anyall') == 'any'" /> any
<input type="radio" name="anyall" value="all" disabled="disabled"
tal:attributes="checked request.params.get('anyall') == 'all'" /> all
</div>
<div tal:repeat="field filter_fields">
<input type="text" tal:condition="not field.choices" placeholder="${field.name}" />
Expand All @@ -34,7 +37,8 @@
</select>
</div>
<div>
<button type="submit" class="secondary small button">Apply</button>
<button type="submit" class="secondary small button" name="filter" value="apply">Apply</button>
&nbsp;&nbsp;<a href="${request.current_route_url().split('?')[0]}">Clear</a>
</div>
</form>
</metal:properties_filter_form>
Expand Down
20 changes: 20 additions & 0 deletions licenses/purljs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2012 Mark Perkins, http://allmarkedup.com/

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

0 comments on commit b27eaf8

Please sign in to comment.