big refactoring, and more

New routes, new juice flow, the tags on posts
This commit is contained in:
Paul Schneider 2015-10-17 14:45:57 +02:00
commit 1805cb3e17
46 changed files with 1339 additions and 515 deletions

View file

@ -0,0 +1,189 @@
// knockout-jqAutocomplete 0.4.3 | (c) 2015 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
;(function(factory) {
if (typeof define === "function" && define.amd) {
// AMD anonymous module
define(["knockout", "jquery", "jquery-ui/autocomplete"], factory);
} else {
// No module loader - put directly in global namespace
factory(window.ko, jQuery);
}
})(function(ko, $) {
var JqAuto = function() {
var self = this,
unwrap = ko.utils.unwrapObservable; //support older KO versions that did not have ko.unwrap
//binding's init function
this.init = function(element, valueAccessor, allBindings, data, context) {
var existingSelect, existingChange,
options = unwrap(valueAccessor()),
config = {},
filter = typeof options.filter === "function" ? options.filter : self.defaultFilter;
//extend with global options
ko.utils.extend(config, self.options);
//override with options passed in binding
ko.utils.extend(config, options.options);
//get source from a function (can be remote call)
if (typeof options.source === "function" && !ko.isObservable(options.source)) {
config.source = function(request, response) {
//provide a wrapper to the normal response callback
var callback = function(data) {
self.processOptions(valueAccessor, null, data, request, response);
};
//call the provided function for retrieving data
options.source.call(context.$data, request.term, callback);
};
}
else {
//process local data
config.source = self.processOptions.bind(self, valueAccessor, filter, options.source);
}
//save any passed in select/change calls
existingSelect = typeof config.select === "function" && config.select;
existingChange = typeof config.change === "function" && config.change;
//handle updating the actual value
config.select = function(event, ui) {
if (ui.item && ui.item.actual) {
options.value(ui.item.actual);
if (ko.isWriteableObservable(options.dataValue)) {
options.dataValue(ui.item.data);
}
}
if (existingSelect) {
existingSelect.apply(this, arguments);
}
};
//user made a change without selecting a value from the list
config.change = function(event, ui) {
if (!ui.item || !ui.item.actual) {
options.value(event.target && event.target.value);
if (ko.isWriteableObservable(options.dataValue)) {
options.dataValue(null);
}
}
if (existingChange) {
existingChange.apply(this, arguments);
}
};
//initialize the widget
var widget = $(element).autocomplete(config).data("ui-autocomplete");
//render a template for the items
if (options.template) {
widget._renderItem = self.renderItem.bind(self, options.template, context);
}
//destroy the widget if KO removes the element
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
if (widget && typeof widget.destroy === "function") {
widget.destroy();
widget = null;
}
});
};
//the binding's update function. keep value in sync with model
this.update = function(element, valueAccessor) {
var propNames, sources,
options = unwrap(valueAccessor()),
value = unwrap(options && options.value);
if (!value && value !== 0) {
value = "";
}
// find the appropriate value for the input
sources = unwrap(options.source);
propNames = self.getPropertyNames(valueAccessor);
// if there is local data, then try to determine the appropriate value for the input
if ($.isArray(sources) && propNames.value) {
value = ko.utils.arrayFirst(sources, function (opt) {
return opt[propNames.value] == value;
}
) || value;
}
if (propNames.input && value && typeof value === "object") {
element.value = value[propNames.input];
}
else {
element.value = value;
}
};
//if dealing with local data, the default filtering function
this.defaultFilter = function(item, term) {
term = term && term.toLowerCase();
return (item || item === 0) && ko.toJSON(item).toLowerCase().indexOf(term) > -1;
};
//filter/map options to be in a format that autocomplete requires
this.processOptions = function(valueAccessor, filter, data, request, response) {
var item, index, length,
items = unwrap(data) || [],
results = [],
props = this.getPropertyNames(valueAccessor);
//filter/map items
for (index = 0, length = items.length; index < length; index++) {
item = items[index];
if (!filter || filter(item, request.term)) {
results.push({
label: props.label ? item[props.label] : item.toString(),
value: props.input ? item[props.input] : item.toString(),
actual: props.value ? item[props.value] : item,
data: item
});
}
}
//call autocomplete callback to display list
response(results);
};
//if specified, use a template to render an item
this.renderItem = function(templateName, context, ul, item) {
var $li = $("<li></li>").appendTo(ul),
itemContext = context.createChildContext(item.data);
//apply the template binding
ko.applyBindingsToNode($li[0], { template: templateName }, itemContext);
//clean up
$li.one("remove", ko.cleanNode.bind(ko, $li[0]));
return $li;
};
//retrieve the property names to use for the label, input, and value
this.getPropertyNames = function(valueAccessor) {
var options = ko.toJS(valueAccessor());
return {
label: options.labelProp || options.valueProp,
input: options.inputProp || options.labelProp || options.valueProp,
value: options.valueProp
};
};
//default global options passed into autocomplete widget
this.options = {
autoFocus: true,
delay: 50
};
};
ko.bindingHandlers.jqAuto = new JqAuto();
});

View file

@ -0,0 +1,2 @@
// knockout-jqAutocomplete 0.4.3 | (c) 2015 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
!function(a){"function"==typeof define&&define.amd?define(["knockout","jquery","jquery-ui/autocomplete"],a):a(window.ko,jQuery)}(function(a,b){var c=function(){var c=this,d=a.utils.unwrapObservable;this.init=function(e,f,g,h,i){var j,k,l=d(f()),m={},n="function"==typeof l.filter?l.filter:c.defaultFilter;a.utils.extend(m,c.options),a.utils.extend(m,l.options),m.source="function"!=typeof l.source||a.isObservable(l.source)?c.processOptions.bind(c,f,n,l.source):function(a,b){var d=function(d){c.processOptions(f,null,d,a,b)};l.source.call(i.$data,a.term,d)},j="function"==typeof m.select&&m.select,k="function"==typeof m.change&&m.change,m.select=function(b,c){c.item&&c.item.actual&&(l.value(c.item.actual),a.isWriteableObservable(l.dataValue)&&l.dataValue(c.item.data)),j&&j.apply(this,arguments)},m.change=function(b,c){c.item&&c.item.actual||(l.value(b.target&&b.target.value),a.isWriteableObservable(l.dataValue)&&l.dataValue(null)),k&&k.apply(this,arguments)};var o=b(e).autocomplete(m).data("ui-autocomplete");l.template&&(o._renderItem=c.renderItem.bind(c,l.template,i)),a.utils.domNodeDisposal.addDisposeCallback(e,function(){o&&"function"==typeof o.destroy&&(o.destroy(),o=null)})},this.update=function(e,f){var g,h,i=d(f()),j=d(i&&i.value);j||0===j||(j=""),h=d(i.source),g=c.getPropertyNames(f),b.isArray(h)&&g.value&&(j=a.utils.arrayFirst(h,function(a){return a[g.value]==j})||j),e.value=g.input&&j&&"object"==typeof j?j[g.input]:j},this.defaultFilter=function(b,c){return c=c&&c.toLowerCase(),(b||0===b)&&a.toJSON(b).toLowerCase().indexOf(c)>-1},this.processOptions=function(a,b,c,e,f){var g,h,i,j=d(c)||[],k=[],l=this.getPropertyNames(a);for(h=0,i=j.length;i>h;h++)g=j[h],(!b||b(g,e.term))&&k.push({label:l.label?g[l.label]:g.toString(),value:l.input?g[l.input]:g.toString(),actual:l.value?g[l.value]:g,data:g});f(k)},this.renderItem=function(c,d,e,f){var g=b("<li></li>").appendTo(e),h=d.createChildContext(f.data);return a.applyBindingsToNode(g[0],{template:c},h),g.one("remove",a.cleanNode.bind(a,g[0])),g},this.getPropertyNames=function(b){var c=a.toJS(b());return{label:c.labelProp||c.valueProp,input:c.inputProp||c.labelProp||c.valueProp,value:c.valueProp}},this.options={autoFocus:!0,delay:50}};a.bindingHandlers.jqAuto=new c});

View file

@ -1,6 +1,13 @@
var Yavsc = (function(apiBaseUrl){
var self = {};
function dumpprops(obj) {
var str = "";
for(var k in obj)
if (obj.hasOwnProperty(k))
str += k + " = " + obj[k] + "\n";
return (str); }
self.apiBaseUrl = (apiBaseUrl || '/api');
self.showHide = function () {
@ -33,8 +40,11 @@ self.notice = function (msg, msgok) {
self.onAjaxBadInput = function (data)
{
if (!data) { Yavsc.notice('no data'); return; }
if (!data.responseJSON) { Yavsc.notice('no json data:'+data); return; }
if (!Array.isArray(data.responseJSON)) { Yavsc.notice('Bad Input: '+data.responseJSON); return; }
$.each(data.responseJSON, function (key, value) {
var errspanid = "Err_cr_" + value.key.replace("model.","");
var errspanid = "Err_" + value.key;
var errspan = document.getElementById(errspanid);
if (errspan==null)
alert('enoent '+errspanid);
@ -47,9 +57,24 @@ self.notice = function (msg, msgok) {
self.onAjaxError = function (xhr, ajaxOptions, thrownError) {
if (xhr.status!=400)
Yavsc.notice(xhr.status+" : "+xhr.responseText);
else Yavsc.notice(false);
};
return self;
})();
$(document).ready(function(){
var $window = $(window);
$(window).scroll(function() {
var $ns = $('#notifications');
if ($ns.has('*').length>0) {
if ($window.scrollTop()>375) {
$ns.css('position','fixed');
$ns.css('z-index',2);
$ns.css('top',0);
}
else {
$ns.css('position','static');
$ns.css('z-index',1);
}}
});
});

View file

@ -1,37 +0,0 @@
//
// parralax.js
//
// Author:
// Paul Schneider <paul@pschneider.fr>
//
// Copyright (c) 2015 GNU GPL
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
$(document).ready(function(){
var $window = $(window);
$(window).scroll(function() {
var $ns = $('#notifications');
if ($ns.has('*').length>0) {
if ($window.scrollTop()>375) {
$ns.css('position','fixed');
$ns.css('z-index',2);
$ns.css('top',0);
}
else {
$ns.css('position','static');
$ns.css('z-index',1);
}}
});
});