git-svn-id: https://msi/svn/firstRepo/WebClient/trunk@13 0f545695-f87b-41b6-9a03-7f16563b5454
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
define(['jquery','underscore', 'backbone', 'router', 'classes/profile'],function
|
||||
($, _, Backbone,Router, Profile) {
|
||||
'use strict';
|
||||
var init=function(){
|
||||
//create backbone router
|
||||
var router=new Router();
|
||||
Backbone.history.start();
|
||||
Backbone.emulateJSON = true;
|
||||
var origin = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + (location.pathname?location.pathname:'');
|
||||
openFB.init('1466942266882168', origin, window.localStorage);
|
||||
openGPlus.init('319140243944-qk0lfhgmi8shi4go97r83l69f1k0gdf4.apps.googleusercontent.com', origin, window.localStorage);
|
||||
//console.log("Backbone history start");
|
||||
// Trigger 'route' event on router instance.
|
||||
router.on('route', function(name, args) {
|
||||
//alert(name);
|
||||
});
|
||||
|
||||
if( Profile.isConnected()) {
|
||||
Profile.loadProfile();
|
||||
}
|
||||
|
||||
$('body').css('background-color', '');
|
||||
$('#loadingFrm').remove();
|
||||
};
|
||||
|
||||
return {
|
||||
initialize:init
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Created by Denis on 19/06/2014.
|
||||
*/
|
||||
define(['jquery', 'backbone'],
|
||||
function($, Backbone){
|
||||
|
||||
var Profile = {
|
||||
|
||||
_loadme:function(){
|
||||
if(this.isConnected()) {
|
||||
if (this.data.type == null)
|
||||
this.loadProfile();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.data.risRic = window.localStorage.getItem("risRic");
|
||||
this.data.tema = window.localStorage.getItem("tema");
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
dataloaded: false,
|
||||
|
||||
data: {
|
||||
"name": null,
|
||||
"email": null,
|
||||
"gender":null,
|
||||
"tema": 'b',
|
||||
"risRic": '10',
|
||||
"type": null
|
||||
},
|
||||
|
||||
isConnected: function(){
|
||||
return this.getKeySave() != "null" &&
|
||||
this.getKeySave() != null &&
|
||||
this.getKeySave() != "undefined" &&
|
||||
this.getKeySave() != undefined;
|
||||
},
|
||||
|
||||
loadProfile:function(successFn) {
|
||||
this.internalLoadProfile(this.getKeySave(), successFn);
|
||||
},
|
||||
|
||||
internalLoadProfile:function(keyStore, successFn){
|
||||
if(this.dataloaded)
|
||||
return;
|
||||
//var keyStore = this.getKeySave();
|
||||
var self = this;
|
||||
var retBool = false;
|
||||
var resp = $.ajax({
|
||||
url: myManifest.Settings.DefaultURL + "/api/profile/" + keyStore,
|
||||
//dataType: "json",
|
||||
async: false,
|
||||
type: 'GET'
|
||||
}).responseText;
|
||||
|
||||
var response = JSON.parse(resp);
|
||||
if(response.length > 0)
|
||||
{
|
||||
self.dataloaded = true;
|
||||
self.setKeySave(keyStore);
|
||||
self.data.name = response[0].Name;
|
||||
self.data.gender = response[0].Gender;
|
||||
self.data.tema = response[0].TemaUI;
|
||||
self.data.risRic = response[0].RisultatiRicerca;
|
||||
self.data.type = response[0].TipoAccesso;
|
||||
retBool = true;
|
||||
}
|
||||
if(successFn)
|
||||
successFn(retBool);
|
||||
},
|
||||
|
||||
getKeySave: function(){
|
||||
return window.localStorage.getItem("KeySave");
|
||||
},
|
||||
setKeySave: function(val){
|
||||
window.localStorage.setItem("KeySave", val);
|
||||
},
|
||||
|
||||
isGPlusConnected: function(){
|
||||
if(this.data.type == "gplus")
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
isFbConnected: function(){
|
||||
if(this.data.type == "fb")
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
|
||||
addRicettaBloccoNote: function(ricetta_id, successFn) {
|
||||
var sendobj = {
|
||||
"ricetta_id": ricetta_id,
|
||||
"keyStore": this.getKeySave()
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: myManifest.Settings.DefaultURL + "/api/profile/ricetta",
|
||||
//dataType: "json",
|
||||
type: 'POST',
|
||||
data: { dataPair: JSON.stringify(sendobj) },
|
||||
success: function(msg){
|
||||
if(successFn)
|
||||
successFn(msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeRicettaBloccoNote: function(ricetta_id, successFn) {
|
||||
$.ajax({
|
||||
url: myManifest.Settings.DefaultURL + "/api/profile/" + this.getKeySave() + "/ricetta/" + ricetta_id,
|
||||
//dataType: "json",
|
||||
type: 'DELETE',
|
||||
success: function(msg){
|
||||
if(successFn)
|
||||
successFn(msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
existRicettaBloccoNote: function(ricettaID, successFn){
|
||||
$.ajax({
|
||||
url: myManifest.Settings.DefaultURL + "/api/profile/" + this.getKeySave() + "/ricetta/" + ricettaID,
|
||||
//dataType: "json",
|
||||
type: 'GET',
|
||||
success: function(msg){
|
||||
if(successFn)
|
||||
successFn(msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
createProfile: function(keyStore, typeProfile, name, email,gender, successFn) {
|
||||
this.data.type = typeProfile;
|
||||
this.data.name = name;
|
||||
this.data.email = email;
|
||||
this.data.gender = gender;
|
||||
this.setKeySave(keyStore);
|
||||
|
||||
window.localStorage.removeItem("risRic");
|
||||
window.localStorage.removeItem("tema");
|
||||
|
||||
var sendobj = {
|
||||
"keyStore": this.getKeySave(),
|
||||
"name": this.data.name,
|
||||
"email": this.data.email,
|
||||
"gender": this.data.gender,
|
||||
"tema": this.data.tema,
|
||||
"risRic": this.data.risRic,
|
||||
"type": this.data.type
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: myManifest.Settings.DefaultURL + "/api/profile",
|
||||
//dataType: "json",
|
||||
type: 'POST',
|
||||
data: { dataPair: JSON.stringify(sendobj) },
|
||||
success: function(msg){
|
||||
if(successFn)
|
||||
successFn(msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateProfile: function(successFn) {
|
||||
if(this.isConnected()) {
|
||||
var sendobj = {
|
||||
"keyStore": this.getKeySave(),
|
||||
"tema": this.data.tema,
|
||||
"risRic": this.data.risRic,
|
||||
"type": this.data.type
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: myManifest.Settings.DefaultURL + "/api/profile",
|
||||
//dataType: "json",
|
||||
type: 'PUT',
|
||||
data: { dataPair: JSON.stringify(sendobj) },
|
||||
success: function (msg) {
|
||||
if (successFn)
|
||||
successFn(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
window.localStorage.setItem("risRic", this.data.risRic);
|
||||
window.localStorage.setItem("tema", this.data.tema);
|
||||
}
|
||||
}
|
||||
};
|
||||
return Profile._loadme();
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
var pathJquery = "http://ajax.googleapis.com/ajax/libs/jquery/" + myManifest.Settings.JQueryVersion + "/jquery.min";
|
||||
var pathJqueryMobile = "http://ajax.googleapis.com/ajax/libs/jquerymobile/"+ myManifest.Settings.JQueryMobileVersion + "/jquery.mobile.min";
|
||||
|
||||
requirejs.config({
|
||||
baseUrl: 'js',
|
||||
urlArgs: "v" + myManifest.getUrlArg(),
|
||||
paths: {
|
||||
jquery: pathJquery,
|
||||
underscore: 'libs/underscore-min',
|
||||
jQueryPlugins: 'libs/jQueryPlugins',
|
||||
backbone: 'libs/backbone-min',
|
||||
jqm: pathJqueryMobile,
|
||||
text: 'libs/text'
|
||||
},
|
||||
shim: {
|
||||
jqm: {
|
||||
deps: [ 'jquery' ]
|
||||
},
|
||||
jQueryPlugins: {
|
||||
deps: [ 'jquery' ]
|
||||
}
|
||||
},
|
||||
deps:[ "main" ]
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!controls/footer/footerTemplate.html'],
|
||||
function($, _, Backbone, footerTemplate){
|
||||
|
||||
var footer = Backbone.View.extend({
|
||||
//initialize template
|
||||
template:_.template(footerTemplate),
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
this.$el.attr('data-role', 'footer');
|
||||
this.$el.attr('data-position', 'fixed');
|
||||
this.$el.attr('class', 'nav-glyphish-example');
|
||||
this.$el.attr('data-tap-toggle', 'false');
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.template());
|
||||
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return footer;
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<div data-role="navbar" class="nav-glyphish-example">
|
||||
<ul>
|
||||
<li><a href="#noteView" id="noteBtn" data-icon="custom">Blocco note</a></li>
|
||||
<li><a href="#faqView" id="faqBtn" data-icon="custom">Lo sai che?</a></li>
|
||||
<li><a href="#indexView" id="indexBtn" data-icon="custom">Indice</a></li>
|
||||
<li><a href="#searchView" id="searchBtn" data-icon="custom">Cerca</a></li>
|
||||
<li><a href="#moreView" id="moreBtn" data-icon="custom">Altro</a></li>
|
||||
<!--<li><a href="#aboutView" id="infoBtn" data-icon="custom">About</a></li>
|
||||
<li><a href="#toolsView" id="toolsBtn" data-icon="custom">Tools</a></li>-->
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!controls/header/headerTemplate.html'],
|
||||
function($, _, Backbone, headerTemplate){
|
||||
|
||||
var header = Backbone.View.extend({
|
||||
|
||||
title: "",
|
||||
|
||||
initialize : function (options) {
|
||||
this.title = options.title;
|
||||
},
|
||||
|
||||
//initialize template
|
||||
template:_.template(headerTemplate),
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
this.$el.attr('data-role', 'header');
|
||||
this.$el.attr('data-position', 'fixed');
|
||||
this.$el.attr('data-tap-toggle', 'false');
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.template( { "title":this.title } ));
|
||||
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return header;
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
<a href="#homeView" class="nav-glyphish-example ui-btn ui-icon-myHome ui-btn-icon-notext">Home</a>
|
||||
<h4><%= title %></h4>
|
||||
@@ -0,0 +1,16 @@
|
||||
define(['jquery'], function ($){
|
||||
'use strict';
|
||||
$(document).bind("mobileinit", function () {
|
||||
$.mobile.ajaxEnabled = false;
|
||||
$.mobile.linkBindingEnabled = false;
|
||||
$.mobile.hashListeningEnabled = false;
|
||||
$.mobile.pushStateEnabled = false;
|
||||
$.support.cors = true;
|
||||
$.mobile.allowCrossDomainPages = true;
|
||||
//$.mobile.defaultPageTransition = 'slidefade';
|
||||
// Remove page from DOM when it's being replaced
|
||||
$(document).on("pagecontainerhide", function (event, ui) {
|
||||
$("div[data-role='page']:not(.ui-page-active)").remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Created by Denis on 04/03/14.
|
||||
*/
|
||||
function addMetaFunction(name, content)
|
||||
{
|
||||
var meta=document.createElement('meta');
|
||||
meta.name=name;
|
||||
meta.content=content;
|
||||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
}
|
||||
|
||||
function addLinkFunction(rel, href)
|
||||
{
|
||||
var link=document.createElement('link');
|
||||
link.rel=rel;
|
||||
link.href=href;
|
||||
document.getElementsByTagName('head')[0].appendChild(link);
|
||||
}
|
||||
|
||||
function addLinkIconFunction(rel, href, size)
|
||||
{
|
||||
var link=document.createElement('link');
|
||||
link.rel=rel;
|
||||
link.setAttribute('sizes', size);
|
||||
link.href=href;
|
||||
document.getElementsByTagName('head')[0].appendChild(link);
|
||||
}
|
||||
|
||||
function addScriptFunction(scriptFile, version)
|
||||
{
|
||||
var head=document.getElementsByTagName('head')[0];
|
||||
var thisScript = head.getElementsByTagName('script')[1];
|
||||
var sc=document.createElement('script');
|
||||
sc.type='text/javascript';
|
||||
sc.async=true;
|
||||
sc.src= scriptFile
|
||||
if(version!="")
|
||||
sc.src += '?v' + version;
|
||||
thisScript.parentNode.insertBefore(sc,thisScript);
|
||||
}
|
||||
Vendored
+2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,806 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
|
||||
*
|
||||
* @version 1.0.3
|
||||
* @codingstandard ftlabs-jsv2
|
||||
* @copyright The Financial Times Limited [All Rights Reserved]
|
||||
* @license MIT License (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
/*jslint browser:true, node:true*/
|
||||
/*global define, Event, Node*/
|
||||
|
||||
|
||||
/**
|
||||
* Instantiate fast-clicking listeners on the specified layer.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Element} layer The layer to listen on
|
||||
* @param {Object} [options={}] The options to override the defaults
|
||||
*/
|
||||
function FastClick(layer, options) {
|
||||
var oldOnClick;
|
||||
|
||||
options = options || {};
|
||||
|
||||
/**
|
||||
* Whether a click is currently being tracked.
|
||||
*
|
||||
* @type boolean
|
||||
*/
|
||||
this.trackingClick = false;
|
||||
|
||||
|
||||
/**
|
||||
* Timestamp for when click tracking started.
|
||||
*
|
||||
* @type number
|
||||
*/
|
||||
this.trackingClickStart = 0;
|
||||
|
||||
|
||||
/**
|
||||
* The element being tracked for a click.
|
||||
*
|
||||
* @type EventTarget
|
||||
*/
|
||||
this.targetElement = null;
|
||||
|
||||
|
||||
/**
|
||||
* X-coordinate of touch start event.
|
||||
*
|
||||
* @type number
|
||||
*/
|
||||
this.touchStartX = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Y-coordinate of touch start event.
|
||||
*
|
||||
* @type number
|
||||
*/
|
||||
this.touchStartY = 0;
|
||||
|
||||
|
||||
/**
|
||||
* ID of the last touch, retrieved from Touch.identifier.
|
||||
*
|
||||
* @type number
|
||||
*/
|
||||
this.lastTouchIdentifier = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Touchmove boundary, beyond which a click will be cancelled.
|
||||
*
|
||||
* @type number
|
||||
*/
|
||||
this.touchBoundary = options.touchBoundary || 10;
|
||||
|
||||
|
||||
/**
|
||||
* The FastClick layer.
|
||||
*
|
||||
* @type Element
|
||||
*/
|
||||
this.layer = layer;
|
||||
|
||||
/**
|
||||
* The minimum time between tap(touchstart and touchend) events
|
||||
*
|
||||
* @type number
|
||||
*/
|
||||
this.tapDelay = options.tapDelay || 200;
|
||||
|
||||
if (FastClick.notNeeded(layer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Some old versions of Android don't have Function.prototype.bind
|
||||
function bind(method, context) {
|
||||
return function() { return method.apply(context, arguments); };
|
||||
}
|
||||
|
||||
|
||||
var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'];
|
||||
var context = this;
|
||||
for (var i = 0, l = methods.length; i < l; i++) {
|
||||
context[methods[i]] = bind(context[methods[i]], context);
|
||||
}
|
||||
|
||||
// Set up event handlers as required
|
||||
if (deviceIsAndroid) {
|
||||
layer.addEventListener('mouseover', this.onMouse, true);
|
||||
layer.addEventListener('mousedown', this.onMouse, true);
|
||||
layer.addEventListener('mouseup', this.onMouse, true);
|
||||
}
|
||||
|
||||
layer.addEventListener('click', this.onClick, true);
|
||||
layer.addEventListener('touchstart', this.onTouchStart, false);
|
||||
layer.addEventListener('touchmove', this.onTouchMove, false);
|
||||
layer.addEventListener('touchend', this.onTouchEnd, false);
|
||||
layer.addEventListener('touchcancel', this.onTouchCancel, false);
|
||||
|
||||
// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
|
||||
// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
|
||||
// layer when they are cancelled.
|
||||
if (!Event.prototype.stopImmediatePropagation) {
|
||||
layer.removeEventListener = function(type, callback, capture) {
|
||||
var rmv = Node.prototype.removeEventListener;
|
||||
if (type === 'click') {
|
||||
rmv.call(layer, type, callback.hijacked || callback, capture);
|
||||
} else {
|
||||
rmv.call(layer, type, callback, capture);
|
||||
}
|
||||
};
|
||||
|
||||
layer.addEventListener = function(type, callback, capture) {
|
||||
var adv = Node.prototype.addEventListener;
|
||||
if (type === 'click') {
|
||||
adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
|
||||
if (!event.propagationStopped) {
|
||||
callback(event);
|
||||
}
|
||||
}), capture);
|
||||
} else {
|
||||
adv.call(layer, type, callback, capture);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// If a handler is already declared in the element's onclick attribute, it will be fired before
|
||||
// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
|
||||
// adding it as listener.
|
||||
if (typeof layer.onclick === 'function') {
|
||||
|
||||
// Android browser on at least 3.2 requires a new reference to the function in layer.onclick
|
||||
// - the old one won't work if passed to addEventListener directly.
|
||||
oldOnClick = layer.onclick;
|
||||
layer.addEventListener('click', function(event) {
|
||||
oldOnClick(event);
|
||||
}, false);
|
||||
layer.onclick = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Android requires exceptions.
|
||||
*
|
||||
* @type boolean
|
||||
*/
|
||||
var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;
|
||||
|
||||
|
||||
/**
|
||||
* iOS requires exceptions.
|
||||
*
|
||||
* @type boolean
|
||||
*/
|
||||
var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent);
|
||||
|
||||
|
||||
/**
|
||||
* iOS 4 requires an exception for select elements.
|
||||
*
|
||||
* @type boolean
|
||||
*/
|
||||
var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
|
||||
|
||||
|
||||
/**
|
||||
* iOS 6.0(+?) requires the target element to be manually derived
|
||||
*
|
||||
* @type boolean
|
||||
*/
|
||||
var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS ([6-9]|\d{2})_\d/).test(navigator.userAgent);
|
||||
|
||||
/**
|
||||
* BlackBerry requires exceptions.
|
||||
*
|
||||
* @type boolean
|
||||
*/
|
||||
var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;
|
||||
|
||||
/**
|
||||
* Determine whether a given element requires a native click.
|
||||
*
|
||||
* @param {EventTarget|Element} target Target DOM element
|
||||
* @returns {boolean} Returns true if the element needs a native click
|
||||
*/
|
||||
FastClick.prototype.needsClick = function(target) {
|
||||
switch (target.nodeName.toLowerCase()) {
|
||||
|
||||
// Don't send a synthetic click to disabled inputs (issue #62)
|
||||
case 'button':
|
||||
case 'select':
|
||||
case 'textarea':
|
||||
if (target.disabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'input':
|
||||
|
||||
// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
|
||||
if ((deviceIsIOS && target.type === 'file') || target.disabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'label':
|
||||
case 'iframe': // iOS8 homescreen apps can prevent events bubbling into frames
|
||||
case 'video':
|
||||
return true;
|
||||
}
|
||||
|
||||
return (/\bneedsclick\b/).test(target.className);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether a given element requires a call to focus to simulate click into element.
|
||||
*
|
||||
* @param {EventTarget|Element} target Target DOM element
|
||||
* @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
|
||||
*/
|
||||
FastClick.prototype.needsFocus = function(target) {
|
||||
switch (target.nodeName.toLowerCase()) {
|
||||
case 'textarea':
|
||||
return true;
|
||||
case 'select':
|
||||
return !deviceIsAndroid;
|
||||
case 'input':
|
||||
switch (target.type) {
|
||||
case 'button':
|
||||
case 'checkbox':
|
||||
case 'file':
|
||||
case 'image':
|
||||
case 'radio':
|
||||
case 'submit':
|
||||
return false;
|
||||
}
|
||||
|
||||
// No point in attempting to focus disabled inputs
|
||||
return !target.disabled && !target.readOnly;
|
||||
default:
|
||||
return (/\bneedsfocus\b/).test(target.className);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Send a click event to the specified element.
|
||||
*
|
||||
* @param {EventTarget|Element} targetElement
|
||||
* @param {Event} event
|
||||
*/
|
||||
FastClick.prototype.sendClick = function(targetElement, event) {
|
||||
var clickEvent, touch;
|
||||
|
||||
// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
|
||||
if (document.activeElement && document.activeElement !== targetElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
touch = event.changedTouches[0];
|
||||
|
||||
// Synthesise a click event, with an extra attribute so it can be tracked
|
||||
clickEvent = document.createEvent('MouseEvents');
|
||||
clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
|
||||
clickEvent.forwardedTouchEvent = true;
|
||||
targetElement.dispatchEvent(clickEvent);
|
||||
};
|
||||
|
||||
FastClick.prototype.determineEventType = function(targetElement) {
|
||||
|
||||
//Issue #159: Android Chrome Select Box does not open with a synthetic click event
|
||||
if (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
|
||||
return 'mousedown';
|
||||
}
|
||||
|
||||
return 'click';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {EventTarget|Element} targetElement
|
||||
*/
|
||||
FastClick.prototype.focus = function(targetElement) {
|
||||
var length;
|
||||
|
||||
// Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
|
||||
if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month') {
|
||||
length = targetElement.value.length;
|
||||
targetElement.setSelectionRange(length, length);
|
||||
} else {
|
||||
targetElement.focus();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
|
||||
*
|
||||
* @param {EventTarget|Element} targetElement
|
||||
*/
|
||||
FastClick.prototype.updateScrollParent = function(targetElement) {
|
||||
var scrollParent, parentElement;
|
||||
|
||||
scrollParent = targetElement.fastClickScrollParent;
|
||||
|
||||
// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
|
||||
// target element was moved to another parent.
|
||||
if (!scrollParent || !scrollParent.contains(targetElement)) {
|
||||
parentElement = targetElement;
|
||||
do {
|
||||
if (parentElement.scrollHeight > parentElement.offsetHeight) {
|
||||
scrollParent = parentElement;
|
||||
targetElement.fastClickScrollParent = parentElement;
|
||||
break;
|
||||
}
|
||||
|
||||
parentElement = parentElement.parentElement;
|
||||
} while (parentElement);
|
||||
}
|
||||
|
||||
// Always update the scroll top tracker if possible.
|
||||
if (scrollParent) {
|
||||
scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {EventTarget} targetElement
|
||||
* @returns {Element|EventTarget}
|
||||
*/
|
||||
FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
|
||||
|
||||
// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
|
||||
if (eventTarget.nodeType === Node.TEXT_NODE) {
|
||||
return eventTarget.parentNode;
|
||||
}
|
||||
|
||||
return eventTarget;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* On touch start, record the position and scroll offset.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @returns {boolean}
|
||||
*/
|
||||
FastClick.prototype.onTouchStart = function(event) {
|
||||
var targetElement, touch, selection;
|
||||
|
||||
// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
|
||||
if (event.targetTouches.length > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
targetElement = this.getTargetElementFromEventTarget(event.target);
|
||||
touch = event.targetTouches[0];
|
||||
|
||||
if (deviceIsIOS) {
|
||||
|
||||
// Only trusted events will deselect text on iOS (issue #49)
|
||||
selection = window.getSelection();
|
||||
if (selection.rangeCount && !selection.isCollapsed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!deviceIsIOS4) {
|
||||
|
||||
// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
|
||||
// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
|
||||
// with the same identifier as the touch event that previously triggered the click that triggered the alert.
|
||||
// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
|
||||
// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
|
||||
// Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string,
|
||||
// which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long,
|
||||
// random integers, it's safe to to continue if the identifier is 0 here.
|
||||
if (touch.identifier && touch.identifier === this.lastTouchIdentifier) {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
this.lastTouchIdentifier = touch.identifier;
|
||||
|
||||
// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
|
||||
// 1) the user does a fling scroll on the scrollable layer
|
||||
// 2) the user stops the fling scroll with another tap
|
||||
// then the event.target of the last 'touchend' event will be the element that was under the user's finger
|
||||
// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
|
||||
// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
|
||||
this.updateScrollParent(targetElement);
|
||||
}
|
||||
}
|
||||
|
||||
this.trackingClick = true;
|
||||
this.trackingClickStart = event.timeStamp;
|
||||
this.targetElement = targetElement;
|
||||
|
||||
this.touchStartX = touch.pageX;
|
||||
this.touchStartY = touch.pageY;
|
||||
|
||||
// Prevent phantom clicks on fast double-tap (issue #36)
|
||||
if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @returns {boolean}
|
||||
*/
|
||||
FastClick.prototype.touchHasMoved = function(event) {
|
||||
var touch = event.changedTouches[0], boundary = this.touchBoundary;
|
||||
|
||||
if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Update the last position.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @returns {boolean}
|
||||
*/
|
||||
FastClick.prototype.onTouchMove = function(event) {
|
||||
if (!this.trackingClick) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the touch has moved, cancel the click tracking
|
||||
if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
|
||||
this.trackingClick = false;
|
||||
this.targetElement = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to find the labelled control for the given label element.
|
||||
*
|
||||
* @param {EventTarget|HTMLLabelElement} labelElement
|
||||
* @returns {Element|null}
|
||||
*/
|
||||
FastClick.prototype.findControl = function(labelElement) {
|
||||
|
||||
// Fast path for newer browsers supporting the HTML5 control attribute
|
||||
if (labelElement.control !== undefined) {
|
||||
return labelElement.control;
|
||||
}
|
||||
|
||||
// All browsers under test that support touch events also support the HTML5 htmlFor attribute
|
||||
if (labelElement.htmlFor) {
|
||||
return document.getElementById(labelElement.htmlFor);
|
||||
}
|
||||
|
||||
// If no for attribute exists, attempt to retrieve the first labellable descendant element
|
||||
// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
|
||||
return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* On touch end, determine whether to send a click event at once.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @returns {boolean}
|
||||
*/
|
||||
FastClick.prototype.onTouchEnd = function(event) {
|
||||
var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
|
||||
|
||||
if (!this.trackingClick) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Prevent phantom clicks on fast double-tap (issue #36)
|
||||
if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
|
||||
this.cancelNextClick = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reset to prevent wrong click cancel on input (issue #156).
|
||||
this.cancelNextClick = false;
|
||||
|
||||
this.lastClickTime = event.timeStamp;
|
||||
|
||||
trackingClickStart = this.trackingClickStart;
|
||||
this.trackingClick = false;
|
||||
this.trackingClickStart = 0;
|
||||
|
||||
// On some iOS devices, the targetElement supplied with the event is invalid if the layer
|
||||
// is performing a transition or scroll, and has to be re-detected manually. Note that
|
||||
// for this to function correctly, it must be called *after* the event target is checked!
|
||||
// See issue #57; also filed as rdar://13048589 .
|
||||
if (deviceIsIOSWithBadTarget) {
|
||||
touch = event.changedTouches[0];
|
||||
|
||||
// In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
|
||||
targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
|
||||
targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
|
||||
}
|
||||
|
||||
targetTagName = targetElement.tagName.toLowerCase();
|
||||
if (targetTagName === 'label') {
|
||||
forElement = this.findControl(targetElement);
|
||||
if (forElement) {
|
||||
this.focus(targetElement);
|
||||
if (deviceIsAndroid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
targetElement = forElement;
|
||||
}
|
||||
} else if (this.needsFocus(targetElement)) {
|
||||
|
||||
// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
|
||||
// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
|
||||
if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {
|
||||
this.targetElement = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.focus(targetElement);
|
||||
this.sendClick(targetElement, event);
|
||||
|
||||
// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
|
||||
// Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others)
|
||||
if (!deviceIsIOS || targetTagName !== 'select') {
|
||||
this.targetElement = null;
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deviceIsIOS && !deviceIsIOS4) {
|
||||
|
||||
// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
|
||||
// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
|
||||
scrollParent = targetElement.fastClickScrollParent;
|
||||
if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent the actual click from going though - unless the target node is marked as requiring
|
||||
// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
|
||||
if (!this.needsClick(targetElement)) {
|
||||
event.preventDefault();
|
||||
this.sendClick(targetElement, event);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* On touch cancel, stop tracking the click.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
FastClick.prototype.onTouchCancel = function() {
|
||||
this.trackingClick = false;
|
||||
this.targetElement = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determine mouse events which should be permitted.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @returns {boolean}
|
||||
*/
|
||||
FastClick.prototype.onMouse = function(event) {
|
||||
|
||||
// If a target element was never set (because a touch event was never fired) allow the event
|
||||
if (!this.targetElement) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.forwardedTouchEvent) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Programmatically generated events targeting a specific element should be permitted
|
||||
if (!event.cancelable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Derive and check the target element to see whether the mouse event needs to be permitted;
|
||||
// unless explicitly enabled, prevent non-touch click events from triggering actions,
|
||||
// to prevent ghost/doubleclicks.
|
||||
if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
|
||||
|
||||
// Prevent any user-added listeners declared on FastClick element from being fired.
|
||||
if (event.stopImmediatePropagation) {
|
||||
event.stopImmediatePropagation();
|
||||
} else {
|
||||
|
||||
// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
|
||||
event.propagationStopped = true;
|
||||
}
|
||||
|
||||
// Cancel the event
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the mouse event is permitted, return true for the action to go through.
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* On actual clicks, determine whether this is a touch-generated click, a click action occurring
|
||||
* naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
|
||||
* an actual click which should be permitted.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @returns {boolean}
|
||||
*/
|
||||
FastClick.prototype.onClick = function(event) {
|
||||
var permitted;
|
||||
|
||||
// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
|
||||
if (this.trackingClick) {
|
||||
this.targetElement = null;
|
||||
this.trackingClick = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
|
||||
if (event.target.type === 'submit' && event.detail === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
permitted = this.onMouse(event);
|
||||
|
||||
// Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
|
||||
if (!permitted) {
|
||||
this.targetElement = null;
|
||||
}
|
||||
|
||||
// If clicks are permitted, return true for the action to go through.
|
||||
return permitted;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove all FastClick's event listeners.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
FastClick.prototype.destroy = function() {
|
||||
var layer = this.layer;
|
||||
|
||||
if (deviceIsAndroid) {
|
||||
layer.removeEventListener('mouseover', this.onMouse, true);
|
||||
layer.removeEventListener('mousedown', this.onMouse, true);
|
||||
layer.removeEventListener('mouseup', this.onMouse, true);
|
||||
}
|
||||
|
||||
layer.removeEventListener('click', this.onClick, true);
|
||||
layer.removeEventListener('touchstart', this.onTouchStart, false);
|
||||
layer.removeEventListener('touchmove', this.onTouchMove, false);
|
||||
layer.removeEventListener('touchend', this.onTouchEnd, false);
|
||||
layer.removeEventListener('touchcancel', this.onTouchCancel, false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether FastClick is needed.
|
||||
*
|
||||
* @param {Element} layer The layer to listen on
|
||||
*/
|
||||
FastClick.notNeeded = function(layer) {
|
||||
var metaViewport;
|
||||
var chromeVersion;
|
||||
var blackberryVersion;
|
||||
|
||||
// Devices that don't support touch don't need FastClick
|
||||
if (typeof window.ontouchstart === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Chrome version - zero for other browsers
|
||||
chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
|
||||
|
||||
if (chromeVersion) {
|
||||
|
||||
if (deviceIsAndroid) {
|
||||
metaViewport = document.querySelector('meta[name=viewport]');
|
||||
|
||||
if (metaViewport) {
|
||||
// Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
|
||||
if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
|
||||
return true;
|
||||
}
|
||||
// Chrome 32 and above with width=device-width or less don't need FastClick
|
||||
if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Chrome desktop doesn't need FastClick (issue #15)
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceIsBlackBerry10) {
|
||||
blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/);
|
||||
|
||||
// BlackBerry 10.3+ does not require Fastclick library.
|
||||
// https://github.com/ftlabs/fastclick/issues/251
|
||||
if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {
|
||||
metaViewport = document.querySelector('meta[name=viewport]');
|
||||
|
||||
if (metaViewport) {
|
||||
// user-scalable=no eliminates click delay.
|
||||
if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
|
||||
return true;
|
||||
}
|
||||
// width=device-width (or less than device-width) eliminates click delay.
|
||||
if (document.documentElement.scrollWidth <= window.outerWidth) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IE10 with -ms-touch-action: none, which disables double-tap-to-zoom (issue #97)
|
||||
if (layer.style.msTouchAction === 'none') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Factory method for creating a FastClick object
|
||||
*
|
||||
* @param {Element} layer The layer to listen on
|
||||
* @param {Object} [options={}] The options to override the defaults
|
||||
*/
|
||||
FastClick.attach = function(layer, options) {
|
||||
return new FastClick(layer, options);
|
||||
};
|
||||
|
||||
|
||||
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
|
||||
|
||||
// AMD. Register as an anonymous module.
|
||||
define(function() {
|
||||
return FastClick;
|
||||
});
|
||||
} else if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = FastClick.attach;
|
||||
module.exports.FastClick = FastClick;
|
||||
} else {
|
||||
window.FastClick = FastClick;
|
||||
}
|
||||
}());
|
||||
@@ -0,0 +1,6 @@
|
||||
define(['jquery'], function ($) {
|
||||
// Only once jquery has loaded, load the jQuery plugins
|
||||
require(['libs/jQueryPluginsCollection'], function () {
|
||||
// Do nothing
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
define(['plugins/jquery.rating.pack', 'plugins/jquery.mobile.alphascroll.min', 'plugins/jquery.validate.min'], function ($) {
|
||||
// Do nothing
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
define(function() {
|
||||
return $;
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
RequireJS 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/jrburke/requirejs for details
|
||||
*/
|
||||
var requirejs,require,define;
|
||||
(function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function T(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function t(b,c){return fa.call(b,c)}function m(b,c){return t(b,c)&&b[c]}function B(b,c){for(var d in b)if(t(b,d)&&c(b[d],d))break}function U(b,c,d,e){c&&B(c,function(c,g){if(d||!t(b,g))e&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
|
||||
RegExp)?(b[g]||(b[g]={}),U(b[g],c,d,e)):b[g]=c});return b}function u(b,c){return function(){return c.apply(b,arguments)}}function ca(b){throw b;}function da(b){if(!b)return b;var c=ba;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,e){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=e;d&&(c.originalError=d);return c}function ga(b){function c(a,k,b){var f,l,c,d,e,g,i,p,k=k&&k.split("/"),h=j.map,n=h&&h["*"];if(a){a=a.split("/");l=a.length-1;j.nodeIdCompat&&
|
||||
Q.test(a[l])&&(a[l]=a[l].replace(Q,""));"."===a[0].charAt(0)&&k&&(l=k.slice(0,k.length-1),a=l.concat(a));l=a;for(c=0;c<l.length;c++)if(d=l[c],"."===d)l.splice(c,1),c-=1;else if(".."===d&&!(0===c||1==c&&".."===l[2]||".."===l[c-1])&&0<c)l.splice(c-1,2),c-=2;a=a.join("/")}if(b&&h&&(k||n)){l=a.split("/");c=l.length;a:for(;0<c;c-=1){e=l.slice(0,c).join("/");if(k)for(d=k.length;0<d;d-=1)if(b=m(h,k.slice(0,d).join("/")))if(b=m(b,e)){f=b;g=c;break a}!i&&(n&&m(n,e))&&(i=m(n,e),p=c)}!f&&i&&(f=i,g=p);f&&(l.splice(0,
|
||||
g,f),a=l.join("/"))}return(f=m(j.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(k){if(k.getAttribute("data-requiremodule")===a&&k.getAttribute("data-requirecontext")===i.contextName)return k.parentNode.removeChild(k),!0})}function e(a){var k=m(j.paths,a);if(k&&H(k)&&1<k.length)return k.shift(),i.require.undef(a),i.makeRequire(null,{skipMap:!0})([a]),!0}function n(a){var k,c=a?a.indexOf("!"):-1;-1<c&&(k=a.substring(0,c),a=a.substring(c+1,a.length));return[k,a]}function p(a,
|
||||
k,b,f){var l,d,e=null,g=k?k.name:null,j=a,p=!0,h="";a||(p=!1,a="_@r"+(K+=1));a=n(a);e=a[0];a=a[1];e&&(e=c(e,g,f),d=m(r,e));a&&(e?h=d&&d.normalize?d.normalize(a,function(a){return c(a,g,f)}):-1===a.indexOf("!")?c(a,g,f):a:(h=c(a,g,f),a=n(h),e=a[0],h=a[1],b=!0,l=i.nameToUrl(h)));b=e&&!d&&!b?"_unnormalized"+(O+=1):"";return{prefix:e,name:h,parentMap:k,unnormalized:!!b,url:l,originalName:j,isDefine:p,id:(e?e+"!"+h:h)+b}}function s(a){var k=a.id,b=m(h,k);b||(b=h[k]=new i.Module(a));return b}function q(a,
|
||||
k,b){var f=a.id,c=m(h,f);if(t(r,f)&&(!c||c.defineEmitComplete))"defined"===k&&b(r[f]);else if(c=s(a),c.error&&"error"===k)b(c.error);else c.on(k,b)}function w(a,b){var c=a.requireModules,f=!1;if(b)b(a);else if(v(c,function(b){if(b=m(h,b))b.error=a,b.events.error&&(f=!0,b.emit("error",a))}),!f)g.onError(a)}function x(){R.length&&(ha.apply(A,[A.length,0].concat(R)),R=[])}function y(a){delete h[a];delete V[a]}function F(a,b,c){var f=a.map.id;a.error?a.emit("error",a.error):(b[f]=!0,v(a.depMaps,function(f,
|
||||
d){var e=f.id,g=m(h,e);g&&(!a.depMatched[d]&&!c[e])&&(m(b,e)?(a.defineDep(d,r[e]),a.check()):F(g,b,c))}),c[f]=!0)}function D(){var a,b,c=(a=1E3*j.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],l=[],g=!1,h=!0;if(!W){W=!0;B(V,function(a){var i=a.map,j=i.id;if(a.enabled&&(i.isDefine||l.push(a),!a.error))if(!a.inited&&c)e(j)?g=b=!0:(f.push(j),d(j));else if(!a.inited&&(a.fetched&&i.isDefine)&&(g=!0,!i.prefix))return h=!1});if(c&&f.length)return a=C("timeout","Load timeout for modules: "+f,null,
|
||||
f),a.contextName=i.contextName,w(a);h&&v(l,function(a){F(a,{},{})});if((!c||b)&&g)if((z||ea)&&!X)X=setTimeout(function(){X=0;D()},50);W=!1}}function E(a){t(r,a[0])||s(p(a[0],null,!0)).init(a[1],a[2])}function I(a){var a=a.currentTarget||a.srcElement,b=i.onScriptLoad;a.detachEvent&&!Y?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1);b=i.onScriptError;(!a.detachEvent||Y)&&a.removeEventListener("error",b,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function J(){var a;
|
||||
for(x();A.length;){a=A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var W,Z,i,L,X,j={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},h={},V={},$={},A=[],r={},S={},aa={},K=1,O=1;L={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?r[a.map.id]=a.exports:a.exports=r[a.map.id]={}},module:function(a){return a.module?
|
||||
a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){return m(j.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};Z=function(a){this.events=m($,a.id)||{};this.map=a;this.shim=m(j.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Z.prototype={init:function(a,b,c,f){f=f||{};if(!this.inited){this.factory=b;if(c)this.on("error",c);else this.events.error&&(c=u(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=
|
||||
c;this.inited=!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],u(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
|
||||
this.map.url;S[a]||(S[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var f=this.exports,l=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&&
|
||||
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
|
||||
this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f);
|
||||
if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval",
|
||||
"fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b,
|
||||
a);this.check()}));this.errback&&q(a,"error",u(this,this.errback))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b,registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p,
|
||||
nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b,
|
||||
a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n,q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=
|
||||
!0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d,e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!==
|
||||
e&&(!("."===k||".."===k)||1<e))d=b.substring(e,b.length),b=b.substring(0,e);return i.nameToUrl(c(b,a&&a.id,!0),d,!0)},defined:function(b){return t(r,p(b,a,!1,!0).id)},specified:function(b){b=p(b,a,!1,!0).id;return t(r,b)||t(h,b)}});a||(j.undef=function(b){x();var c=p(b,a,!0),e=m(h,b);d(b);delete r[b];delete S[c.url];delete $[b];T(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&($[b]=e.events),y(b))});return j},enable:function(a){m(h,a.id)&&s(a).enable()},completeLoad:function(a){var b,
|
||||
c,d=m(j.shim,a)||{},g=d.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=m(h,a);if(!b&&!t(r,a)&&c&&!c.inited){if(j.enforceDefine&&(!g||!da(g)))return e(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,d.deps||[],d.exportsFn])}D()},nameToUrl:function(a,b,c){var d,e,h;(d=m(j.pkgs,a))&&(a=d);if(d=m(aa,a))return i.nameToUrl(d,b,c);if(g.jsExtRegExp.test(a))d=a+(b||"");else{d=j.paths;a=a.split("/");for(e=a.length;0<e;e-=1)if(h=a.slice(0,
|
||||
e).join("/"),h=m(d,h)){H(h)&&(h=h[0]);a.splice(0,e,h);break}d=a.join("/");d+=b||(/^data\:|\?/.test(d)||c?"":".js");d=("/"===d.charAt(0)||d.match(/^[\w\+\.\-]+:/)?"":j.baseUrl)+d}return j.urlArgs?d+((-1===d.indexOf("?")?"?":"&")+j.urlArgs):d},load:function(a,b){g.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ja.test((a.currentTarget||a.srcElement).readyState))N=null,a=I(a),i.completeLoad(a.id)},onScriptError:function(a){var b=I(a);if(!e(b.id))return w(C("scripterror",
|
||||
"Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var g,x,y,D,I,E,N,J,s,O,ka=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,la=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,Q=/\.js$/,ia=/^\.\//;x=Object.prototype;var K=x.toString,fa=x.hasOwnProperty,ha=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),ea=!z&&"undefined"!==typeof importScripts,ja=z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,
|
||||
Y="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},q={},R=[],M=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;q=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(q=require,require=void 0);g=requirejs=function(b,c,d,e){var n,p="_";!H(b)&&"string"!==typeof b&&(n=b,H(c)?(b=c,c=d,d=e):b=[]);n&&n.context&&(p=n.context);(e=m(F,p))||(e=F[p]=g.s.newContext(p));n&&e.configure(n);return e.require(b,c,d)};g.config=function(b){return g(b)};
|
||||
g.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=g);g.version="2.1.15";g.jsExtRegExp=/^\/|:|\?|\.js$/;g.isBrowser=z;x=g.s={contexts:F,newContext:ga};g({});v(["toUrl","undef","defined","specified"],function(b){g[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=x.head=D.parentNode;g.onError=ca;g.createNode=function(b){var c=
|
||||
b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};g.load=function(b,c,d){var e=b&&b.config||{};if(z)return e=g.createNode(e,c,d),e.setAttribute("data-requirecontext",b.contextName),e.setAttribute("data-requiremodule",c),e.attachEvent&&!(e.attachEvent.toString&&0>e.attachEvent.toString().indexOf("[native code"))&&!Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):
|
||||
(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"),s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl=
|
||||
O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return N=b}),e=N;e&&(b||
|
||||
(b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this);
|
||||
+390
@@ -0,0 +1,390 @@
|
||||
/**
|
||||
* @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
|
||||
* Available via the MIT or new BSD license.
|
||||
* see: http://github.com/requirejs/text for details
|
||||
*/
|
||||
/*jslint regexp: true */
|
||||
/*global require, XMLHttpRequest, ActiveXObject,
|
||||
define, window, process, Packages,
|
||||
java, location, Components, FileUtils */
|
||||
|
||||
define(['module'], function (module) {
|
||||
'use strict';
|
||||
|
||||
var text, fs, Cc, Ci, xpcIsWindows,
|
||||
progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
|
||||
xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
|
||||
bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,
|
||||
hasLocation = typeof location !== 'undefined' && location.href,
|
||||
defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
|
||||
defaultHostName = hasLocation && location.hostname,
|
||||
defaultPort = hasLocation && (location.port || undefined),
|
||||
buildMap = {},
|
||||
masterConfig = (module.config && module.config()) || {};
|
||||
|
||||
text = {
|
||||
version: '2.0.12',
|
||||
|
||||
strip: function (content) {
|
||||
//Strips <?xml ...?> declarations so that external SVG and XML
|
||||
//documents can be added to a document without worry. Also, if the string
|
||||
//is an HTML document, only the part inside the body tag is returned.
|
||||
if (content) {
|
||||
content = content.replace(xmlRegExp, "");
|
||||
var matches = content.match(bodyRegExp);
|
||||
if (matches) {
|
||||
content = matches[1];
|
||||
}
|
||||
} else {
|
||||
content = "";
|
||||
}
|
||||
return content;
|
||||
},
|
||||
|
||||
jsEscape: function (content) {
|
||||
return content.replace(/(['\\])/g, '\\$1')
|
||||
.replace(/[\f]/g, "\\f")
|
||||
.replace(/[\b]/g, "\\b")
|
||||
.replace(/[\n]/g, "\\n")
|
||||
.replace(/[\t]/g, "\\t")
|
||||
.replace(/[\r]/g, "\\r")
|
||||
.replace(/[\u2028]/g, "\\u2028")
|
||||
.replace(/[\u2029]/g, "\\u2029");
|
||||
},
|
||||
|
||||
createXhr: masterConfig.createXhr || function () {
|
||||
//Would love to dump the ActiveX crap in here. Need IE 6 to die first.
|
||||
var xhr, i, progId;
|
||||
if (typeof XMLHttpRequest !== "undefined") {
|
||||
return new XMLHttpRequest();
|
||||
} else if (typeof ActiveXObject !== "undefined") {
|
||||
for (i = 0; i < 3; i += 1) {
|
||||
progId = progIds[i];
|
||||
try {
|
||||
xhr = new ActiveXObject(progId);
|
||||
} catch (e) {}
|
||||
|
||||
if (xhr) {
|
||||
progIds = [progId]; // so faster next time
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xhr;
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses a resource name into its component parts. Resource names
|
||||
* look like: module/name.ext!strip, where the !strip part is
|
||||
* optional.
|
||||
* @param {String} name the resource name
|
||||
* @returns {Object} with properties "moduleName", "ext" and "strip"
|
||||
* where strip is a boolean.
|
||||
*/
|
||||
parseName: function (name) {
|
||||
var modName, ext, temp,
|
||||
strip = false,
|
||||
index = name.indexOf("."),
|
||||
isRelative = name.indexOf('./') === 0 ||
|
||||
name.indexOf('../') === 0;
|
||||
|
||||
if (index !== -1 && (!isRelative || index > 1)) {
|
||||
modName = name.substring(0, index);
|
||||
ext = name.substring(index + 1, name.length);
|
||||
} else {
|
||||
modName = name;
|
||||
}
|
||||
|
||||
temp = ext || modName;
|
||||
index = temp.indexOf("!");
|
||||
if (index !== -1) {
|
||||
//Pull off the strip arg.
|
||||
strip = temp.substring(index + 1) === "strip";
|
||||
temp = temp.substring(0, index);
|
||||
if (ext) {
|
||||
ext = temp;
|
||||
} else {
|
||||
modName = temp;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
moduleName: modName,
|
||||
ext: ext,
|
||||
strip: strip
|
||||
};
|
||||
},
|
||||
|
||||
xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,
|
||||
|
||||
/**
|
||||
* Is an URL on another domain. Only works for browser use, returns
|
||||
* false in non-browser environments. Only used to know if an
|
||||
* optimized .js version of a text resource should be loaded
|
||||
* instead.
|
||||
* @param {String} url
|
||||
* @returns Boolean
|
||||
*/
|
||||
useXhr: function (url, protocol, hostname, port) {
|
||||
var uProtocol, uHostName, uPort,
|
||||
match = text.xdRegExp.exec(url);
|
||||
if (!match) {
|
||||
return true;
|
||||
}
|
||||
uProtocol = match[2];
|
||||
uHostName = match[3];
|
||||
|
||||
uHostName = uHostName.split(':');
|
||||
uPort = uHostName[1];
|
||||
uHostName = uHostName[0];
|
||||
|
||||
return (!uProtocol || uProtocol === protocol) &&
|
||||
(!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&
|
||||
((!uPort && !uHostName) || uPort === port);
|
||||
},
|
||||
|
||||
finishLoad: function (name, strip, content, onLoad) {
|
||||
content = strip ? text.strip(content) : content;
|
||||
if (masterConfig.isBuild) {
|
||||
buildMap[name] = content;
|
||||
}
|
||||
onLoad(content);
|
||||
},
|
||||
|
||||
load: function (name, req, onLoad, config) {
|
||||
//Name has format: some.module.filext!strip
|
||||
//The strip part is optional.
|
||||
//if strip is present, then that means only get the string contents
|
||||
//inside a body tag in an HTML string. For XML/SVG content it means
|
||||
//removing the <?xml ...?> declarations so the content can be inserted
|
||||
//into the current doc without problems.
|
||||
|
||||
// Do not bother with the work if a build and text will
|
||||
// not be inlined.
|
||||
if (config && config.isBuild && !config.inlineText) {
|
||||
onLoad();
|
||||
return;
|
||||
}
|
||||
|
||||
masterConfig.isBuild = config && config.isBuild;
|
||||
|
||||
var parsed = text.parseName(name),
|
||||
nonStripName = parsed.moduleName +
|
||||
(parsed.ext ? '.' + parsed.ext : ''),
|
||||
url = req.toUrl(nonStripName),
|
||||
useXhr = (masterConfig.useXhr) ||
|
||||
text.useXhr;
|
||||
|
||||
// Do not load if it is an empty: url
|
||||
if (url.indexOf('empty:') === 0) {
|
||||
onLoad();
|
||||
return;
|
||||
}
|
||||
|
||||
//Load the text. Use XHR if possible and in a browser.
|
||||
if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
|
||||
text.get(url, function (content) {
|
||||
text.finishLoad(name, parsed.strip, content, onLoad);
|
||||
}, function (err) {
|
||||
if (onLoad.error) {
|
||||
onLoad.error(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//Need to fetch the resource across domains. Assume
|
||||
//the resource has been optimized into a JS module. Fetch
|
||||
//by the module name + extension, but do not include the
|
||||
//!strip part to avoid file system issues.
|
||||
req([nonStripName], function (content) {
|
||||
text.finishLoad(parsed.moduleName + '.' + parsed.ext,
|
||||
parsed.strip, content, onLoad);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
write: function (pluginName, moduleName, write, config) {
|
||||
if (buildMap.hasOwnProperty(moduleName)) {
|
||||
var content = text.jsEscape(buildMap[moduleName]);
|
||||
write.asModule(pluginName + "!" + moduleName,
|
||||
"define(function () { return '" +
|
||||
content +
|
||||
"';});\n");
|
||||
}
|
||||
},
|
||||
|
||||
writeFile: function (pluginName, moduleName, req, write, config) {
|
||||
var parsed = text.parseName(moduleName),
|
||||
extPart = parsed.ext ? '.' + parsed.ext : '',
|
||||
nonStripName = parsed.moduleName + extPart,
|
||||
//Use a '.js' file name so that it indicates it is a
|
||||
//script that can be loaded across domains.
|
||||
fileName = req.toUrl(parsed.moduleName + extPart) + '.js';
|
||||
|
||||
//Leverage own load() method to load plugin value, but only
|
||||
//write out values that do not have the strip argument,
|
||||
//to avoid any potential issues with ! in file names.
|
||||
text.load(nonStripName, req, function (value) {
|
||||
//Use own write() method to construct full module value.
|
||||
//But need to create shell that translates writeFile's
|
||||
//write() to the right interface.
|
||||
var textWrite = function (contents) {
|
||||
return write(fileName, contents);
|
||||
};
|
||||
textWrite.asModule = function (moduleName, contents) {
|
||||
return write.asModule(moduleName, fileName, contents);
|
||||
};
|
||||
|
||||
text.write(pluginName, nonStripName, textWrite, config);
|
||||
}, config);
|
||||
}
|
||||
};
|
||||
|
||||
if (masterConfig.env === 'node' || (!masterConfig.env &&
|
||||
typeof process !== "undefined" &&
|
||||
process.versions &&
|
||||
!!process.versions.node &&
|
||||
!process.versions['node-webkit'])) {
|
||||
//Using special require.nodeRequire, something added by r.js.
|
||||
fs = require.nodeRequire('fs');
|
||||
|
||||
text.get = function (url, callback, errback) {
|
||||
try {
|
||||
var file = fs.readFileSync(url, 'utf8');
|
||||
//Remove BOM (Byte Mark Order) from utf8 files if it is there.
|
||||
if (file.indexOf('\uFEFF') === 0) {
|
||||
file = file.substring(1);
|
||||
}
|
||||
callback(file);
|
||||
} catch (e) {
|
||||
if (errback) {
|
||||
errback(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else if (masterConfig.env === 'xhr' || (!masterConfig.env &&
|
||||
text.createXhr())) {
|
||||
text.get = function (url, callback, errback, headers) {
|
||||
var xhr = text.createXhr(), header;
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
//Allow plugins direct access to xhr headers
|
||||
if (headers) {
|
||||
for (header in headers) {
|
||||
if (headers.hasOwnProperty(header)) {
|
||||
xhr.setRequestHeader(header.toLowerCase(), headers[header]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Allow overrides specified in config
|
||||
if (masterConfig.onXhr) {
|
||||
masterConfig.onXhr(xhr, url);
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = function (evt) {
|
||||
var status, err;
|
||||
//Do not explicitly handle errors, those should be
|
||||
//visible via console output in the browser.
|
||||
if (xhr.readyState === 4) {
|
||||
status = xhr.status || 0;
|
||||
if (status > 399 && status < 600) {
|
||||
//An http 4xx or 5xx error. Signal an error.
|
||||
err = new Error(url + ' HTTP status: ' + status);
|
||||
err.xhr = xhr;
|
||||
if (errback) {
|
||||
errback(err);
|
||||
}
|
||||
} else {
|
||||
callback(xhr.responseText);
|
||||
}
|
||||
|
||||
if (masterConfig.onXhrComplete) {
|
||||
masterConfig.onXhrComplete(xhr, url);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send(null);
|
||||
};
|
||||
} else if (masterConfig.env === 'rhino' || (!masterConfig.env &&
|
||||
typeof Packages !== 'undefined' && typeof java !== 'undefined')) {
|
||||
//Why Java, why is this so awkward?
|
||||
text.get = function (url, callback) {
|
||||
var stringBuffer, line,
|
||||
encoding = "utf-8",
|
||||
file = new java.io.File(url),
|
||||
lineSeparator = java.lang.System.getProperty("line.separator"),
|
||||
input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
|
||||
content = '';
|
||||
try {
|
||||
stringBuffer = new java.lang.StringBuffer();
|
||||
line = input.readLine();
|
||||
|
||||
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
|
||||
// http://www.unicode.org/faq/utf_bom.html
|
||||
|
||||
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
|
||||
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
|
||||
if (line && line.length() && line.charAt(0) === 0xfeff) {
|
||||
// Eat the BOM, since we've already found the encoding on this file,
|
||||
// and we plan to concatenating this buffer with others; the BOM should
|
||||
// only appear at the top of a file.
|
||||
line = line.substring(1);
|
||||
}
|
||||
|
||||
if (line !== null) {
|
||||
stringBuffer.append(line);
|
||||
}
|
||||
|
||||
while ((line = input.readLine()) !== null) {
|
||||
stringBuffer.append(lineSeparator);
|
||||
stringBuffer.append(line);
|
||||
}
|
||||
//Make sure we return a JavaScript string and not a Java string.
|
||||
content = String(stringBuffer.toString()); //String
|
||||
} finally {
|
||||
input.close();
|
||||
}
|
||||
callback(content);
|
||||
};
|
||||
} else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&
|
||||
typeof Components !== 'undefined' && Components.classes &&
|
||||
Components.interfaces)) {
|
||||
//Avert your gaze!
|
||||
Cc = Components.classes;
|
||||
Ci = Components.interfaces;
|
||||
Components.utils['import']('resource://gre/modules/FileUtils.jsm');
|
||||
xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);
|
||||
|
||||
text.get = function (url, callback) {
|
||||
var inStream, convertStream, fileObj,
|
||||
readData = {};
|
||||
|
||||
if (xpcIsWindows) {
|
||||
url = url.replace(/\//g, '\\');
|
||||
}
|
||||
|
||||
fileObj = new FileUtils.File(url);
|
||||
|
||||
//XPCOM, you so crazy
|
||||
try {
|
||||
inStream = Cc['@mozilla.org/network/file-input-stream;1']
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
inStream.init(fileObj, 1, 0, false);
|
||||
|
||||
convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']
|
||||
.createInstance(Ci.nsIConverterInputStream);
|
||||
convertStream.init(inStream, "utf-8", inStream.available(),
|
||||
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
|
||||
convertStream.readString(inStream.available(), readData);
|
||||
convertStream.close();
|
||||
inStream.close();
|
||||
callback(readData.value);
|
||||
} catch (e) {
|
||||
throw new Error((fileObj && fileObj.path || '') + ': ' + e);
|
||||
}
|
||||
};
|
||||
}
|
||||
return text;
|
||||
});
|
||||
Vendored
+9
File diff suppressed because one or more lines are too long
Vendored
+6
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+13
@@ -0,0 +1,13 @@
|
||||
//1. load app.js,
|
||||
//2. configure jquery mobile to prevent default JQM ajax navigation
|
||||
//3. bootstrapping application
|
||||
define(["app", "jqm", "jqm-config", 'jQueryPlugins'], function( app ){
|
||||
if(myManifest.Agent.browser.name == "IE Mobile" && myManifest.Agent.browser.version <= 9 ) {
|
||||
window.location.href = "http://old.gruppolapastamadre.it";
|
||||
}
|
||||
else {
|
||||
$(document).ready(function () {
|
||||
app.initialize();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
var myManifest = {
|
||||
Debug: false,
|
||||
Name: "Il Lievitario",
|
||||
Version: "2.2.3",
|
||||
Author: "Denis Ironi",
|
||||
Settings: {
|
||||
//DefaultURL: "http://localhost:8081/Service",
|
||||
DefaultURL: "http://app.gruppolapastamadre.it/Service",
|
||||
JQueryVersion: "1.11.1",
|
||||
JQueryMobileVersion: "1.4.3",
|
||||
Device:{
|
||||
Width: (window.innerWidth > 0) ? window.innerWidth : screen.width,
|
||||
Height: (window.innerHeight > 0) ? window.innerHeight : screen.height
|
||||
}
|
||||
},
|
||||
Agent: (new UAParser()).getResult(),
|
||||
getUrlArg: function(){
|
||||
return (this.Debug ? this.Version + "." + (Math.random() * 1000) : this.Version);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
define(['app', 'jquery', 'underscore', 'backbone', 'model/category/categoryModel'],
|
||||
function (app, $, _, Backbone, Category){
|
||||
|
||||
var Categories=Backbone.Collection.extend({
|
||||
|
||||
// Book is the model of the collection
|
||||
model:Category,
|
||||
|
||||
url: function() {
|
||||
return myManifest.Settings.DefaultURL + "/api/categories";
|
||||
}
|
||||
});
|
||||
|
||||
return Categories;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
define(['jquery', 'underscore', 'backbone'],
|
||||
function ($, _, Backbone){
|
||||
|
||||
var Category=Backbone.Model.extend({
|
||||
//default attributes
|
||||
defaults:{
|
||||
category_id:"",
|
||||
name:''
|
||||
}
|
||||
});
|
||||
|
||||
return Category;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
define(['app', 'jquery', 'underscore', 'backbone', 'model/categoryItem/categoryItemModel'],
|
||||
function (app, $, _, Backbone, Category){
|
||||
|
||||
var CategoryItems=Backbone.Collection.extend({
|
||||
|
||||
categoryId: null,
|
||||
initialize: function (options) {
|
||||
this.categoryId = options.categoryId;
|
||||
},
|
||||
// Book is the model of the collection
|
||||
model:Category,
|
||||
|
||||
url: function() {
|
||||
return myManifest.Settings.DefaultURL + "/api/categoryitems/" + this.categoryId;
|
||||
}
|
||||
});
|
||||
|
||||
return CategoryItems;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
define(['jquery', 'underscore', 'backbone'],
|
||||
function ($, _, Backbone){
|
||||
|
||||
var CategoryItem = Backbone.Model.extend({
|
||||
//default attributes
|
||||
defaults: {
|
||||
ricetta_id: "",
|
||||
titolo: '',
|
||||
autore: '',
|
||||
valutazione: 0,
|
||||
difficolta: 0,
|
||||
categoria_name: 0
|
||||
}
|
||||
});
|
||||
|
||||
return CategoryItem;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
define(['app', 'jquery', 'underscore', 'backbone', 'model/categoryItem/categoryItemModel'],
|
||||
function (app, $, _, Backbone, Category){
|
||||
|
||||
var FoundItems=Backbone.Collection.extend({
|
||||
dataFilter: null,
|
||||
initialize: function (options) {
|
||||
this.dataFilter = {
|
||||
titolo: options.titolo,
|
||||
difficolta: options.difficolta,
|
||||
categoryId: options.categoryId
|
||||
};
|
||||
this.numItems = options.nResult;
|
||||
},
|
||||
|
||||
|
||||
// Book is the model of the collection
|
||||
model:Category,
|
||||
|
||||
url: function() {
|
||||
var u = myManifest.Settings.DefaultURL + "/api/categoryitems/search/" + this.numItems +
|
||||
"/" + this.dataFilter.categoryId +
|
||||
"/" + this.dataFilter.difficolta;
|
||||
if(this.dataFilter.titolo !== null)
|
||||
u += "/" + this.dataFilter.titolo;
|
||||
|
||||
return u;
|
||||
}
|
||||
});
|
||||
|
||||
return FoundItems;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
define(['app', 'jquery', 'underscore', 'backbone', 'model/item/ingredientiModel'],
|
||||
function (app, $, _, Backbone, Ingrediente){
|
||||
|
||||
var Ingredienti=Backbone.Collection.extend({
|
||||
|
||||
ricettaId: null,
|
||||
initialize: function (options) {
|
||||
this.ricettaId = options.ricettaId;
|
||||
},
|
||||
// Book is the model of the collection
|
||||
model:Ingrediente,
|
||||
|
||||
url: function() {
|
||||
return myManifest.Settings.DefaultURL + "/api/ricetta/ingredienti/" + this.ricettaId;
|
||||
}
|
||||
});
|
||||
|
||||
return Ingredienti;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
define(['jquery', 'underscore', 'backbone'],
|
||||
function ($, _, Backbone){
|
||||
|
||||
var Ingrediente=Backbone.Model.extend({
|
||||
//default attributes
|
||||
defaults:{
|
||||
id_tipo_ingredienti: -1,
|
||||
nome_ingrediente: "",
|
||||
quantita: -1,
|
||||
id_tipo_quantita: -1,
|
||||
unita: '',
|
||||
note: '',
|
||||
posizione: 0
|
||||
}
|
||||
});
|
||||
|
||||
return Ingrediente;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
define(['app', 'jquery', 'underscore', 'backbone', 'model/item/itemModel'],
|
||||
function (app, $, _, Backbone, Item){
|
||||
|
||||
var Items=Backbone.Collection.extend({
|
||||
|
||||
ricettaId: null,
|
||||
initialize: function (options) {
|
||||
this.ricettaId = options.ricettaId;
|
||||
},
|
||||
// Book is the model of the collection
|
||||
model:Item,
|
||||
|
||||
url: function() {
|
||||
return myManifest.Settings.DefaultURL + "/api/ricetta/header/" + this.ricettaId;
|
||||
}
|
||||
});
|
||||
|
||||
return Items;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
define(['jquery', 'underscore', 'backbone'],
|
||||
function ($, _, Backbone){
|
||||
|
||||
var Item=Backbone.Model.extend({
|
||||
//default attributes
|
||||
defaults:{
|
||||
id_categoria: "",
|
||||
categoria_name: '',
|
||||
ricetta_id: -1,
|
||||
titolo: '',
|
||||
procedimento: '',
|
||||
autore: '',
|
||||
link_fonte: '',
|
||||
link_youtube: '',
|
||||
valutazione: 0,
|
||||
ingredienti: []
|
||||
}
|
||||
});
|
||||
|
||||
return Item;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
define(['app', 'jquery', 'underscore', 'backbone', 'model/note/noteModel', 'classes/profile'],
|
||||
function (app, $, _, Backbone, Note, Profile){
|
||||
|
||||
var Notes=Backbone.Collection.extend({
|
||||
|
||||
// Book is the model of the collection
|
||||
model:Note,
|
||||
|
||||
url: function() {
|
||||
return myManifest.Settings.DefaultURL + "/api/profile/" + Profile.getKeySave() + "/ricette";
|
||||
}
|
||||
});
|
||||
|
||||
return Notes;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
define(['jquery', 'underscore', 'backbone'],
|
||||
function ($, _, Backbone){
|
||||
|
||||
var Note=Backbone.Model.extend({
|
||||
//default attributes
|
||||
idAttribute: "ricetta_id",
|
||||
defaults:{
|
||||
ricetta_id: "",
|
||||
titolo: '',
|
||||
autore: '',
|
||||
valutazione: 0,
|
||||
difficolta: 0
|
||||
}
|
||||
});
|
||||
|
||||
return Note;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/about/aboutViewTemplate.html', 'modules/base/baseView'],
|
||||
function($, _, Backbone, aboutViewTemplate, BaseView){
|
||||
|
||||
var AboutView = BaseView.extend({
|
||||
|
||||
//initialize template
|
||||
template:_.template(aboutViewTemplate),
|
||||
|
||||
initialize: function () {
|
||||
AboutView.__super__.initialize.call(this);
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
AboutView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template( { app: myManifest }));
|
||||
this.$el.append(this.footer.$el);
|
||||
this.$el.find("#infoBtn").addClass("ui-btn-active");
|
||||
//$("#homeBtn").addClass("ui-btn-active");
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return AboutView;
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
<div data-role="content">
|
||||
<br>
|
||||
<center>
|
||||
<h1 style='font-size: xx-large;'><%= app.Name %></h1>
|
||||
<br>Applicazione Ricettario del <br><br>'<i><b>Gruppo La Pasta Madre</b></i>'<br><br>
|
||||
<b>Versione:</b> <%= app.Version %><br><br>
|
||||
<b>Sviluppatore:</b> <%= app.Author %><br><br>
|
||||
<br><b>Dettagli Sviluppo: </b><br>S.O.:<%= app.Agent.os.name %><br>Versione: <%= app.Agent.os.version %><br><br>
|
||||
<b>Librerie Usate: </b><br>JQuery:<%= app.Settings.JQueryVersion %><br>JQueryMobile: <%= app.Settings.JQueryMobileVersion %><br>
|
||||
<br><br>
|
||||
<b>Ringraziamenti a</b>
|
||||
<br><br>
|
||||
<i>Per il supporto morale e di coordinamento</i><br><br>
|
||||
Alessia B. (Boss)<br>
|
||||
Francesca M. (ViceBoss)<br><br>
|
||||
<i>Per il codice del convertitore</i><br><br>
|
||||
ringrazio l'autore Giuseppe Burgio <a href="http://www.pastamadre.eu/">PastaMadre</a><br><br>
|
||||
<i>Per l'inserimento di tutte le ricette</i><br><br>
|
||||
Angela P.<br>
|
||||
Carlotta G.<br>
|
||||
Cristina D.<br>
|
||||
Daria M.o<br>
|
||||
Giorgia B.<br>
|
||||
Ire Piu' Pi<br>
|
||||
Lucia A.<br>
|
||||
Malek Ben C.<br>
|
||||
Raffaella G.<br>
|
||||
Rita M.<br>
|
||||
Serenella S.<br>
|
||||
Valentina C.<br>
|
||||
Valentina D'a.<br>
|
||||
Valentina V.<br>
|
||||
Valentina Yaya C.<br>
|
||||
</center>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
define(['jquery', 'underscore', 'backbone', 'controls/footer/footer', 'controls/header/header', 'classes/profile'],
|
||||
function($, _, Backbone, Footer, Header, Profile){
|
||||
|
||||
var BaseView = Backbone.View.extend({
|
||||
|
||||
header: null,
|
||||
footer: null,
|
||||
|
||||
initialize: function () {
|
||||
this.header = new Header({ title: "Il Lievitario"});
|
||||
this.footer = new Footer();
|
||||
},
|
||||
|
||||
render: function(){
|
||||
this.header.render();
|
||||
this.footer.render();
|
||||
//add the attribute 'data-role="page" ' for each view's div
|
||||
this.$el.attr('data-role', 'page');
|
||||
this.$el.attr('data-theme', Profile.data.tema);
|
||||
},
|
||||
onShowed: null
|
||||
});
|
||||
return BaseView;
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/category/categoryViewTemplate.html', 'text!modules/category/categoryItemTemplate.html', 'modules/base/baseView'],
|
||||
function($, _, Backbone, categoryViewTemplate, categoryItemTemplate, BaseView){
|
||||
|
||||
var CategoryView = BaseView.extend({
|
||||
|
||||
collection: null,
|
||||
categoryName: null,
|
||||
//initialize template
|
||||
template:_.template(categoryViewTemplate),
|
||||
itemtemplate:_.template(categoryItemTemplate),
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
CategoryView.__super__.initialize.call(this);
|
||||
this.collection = options.collection;
|
||||
this.categoryName = options.categoryName;
|
||||
this.collection.fetch({
|
||||
success: function(data, textStatus, jqXHR){
|
||||
self.renderItem();
|
||||
}
|
||||
//success: function(){ self.renderItem(); }
|
||||
});
|
||||
},
|
||||
|
||||
renderItem: function(){
|
||||
var $ul = $('#allRicette');
|
||||
|
||||
var items = this.itemtemplate({data:this.collection.toJSON()});
|
||||
|
||||
$ul.html( items );
|
||||
$ul.listview( "refresh" );
|
||||
$ul.trigger( "updatelayout");
|
||||
|
||||
$.mobile.loading( 'hide' );
|
||||
//$( '[data-alpha="true"]' ).alphascroll();
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
CategoryView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template({ categoryName: this.categoryName }));
|
||||
this.$el.append(this.footer.$el);
|
||||
//return to enable chained calls
|
||||
this.$el.find("#indexBtn").addClass("ui-btn-active");
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return CategoryView;
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
<% if(data.length == 0){ %>
|
||||
<h1>Nessuna ricetta trovata</h1>
|
||||
<%} else { for (var i = 0; i < data.length; i++) { %>
|
||||
<% var item = data[i]; %>
|
||||
<li><a href="#ricetta/<%= item.ricetta_id%>" class="ui-btn ui-btn-icon-right ui-icon-carat-r"><div class='ricettaTitolo'><%= unescape(item.titolo) %></div><div class='ricettaAutore'><%= unescape(item.autore) %></div></a></li>
|
||||
<% }} %>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div id="categoryListContent" data-role="content">
|
||||
<h1>Indice Ricette<br><%= categoryName %></h1>
|
||||
<ul id="allRicette" data-role="listview" data-autodividers="true" data-alpha="true" data-inset="true">
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,498 @@
|
||||
define(['jquery', 'underscore', 'backbone',
|
||||
'text!modules/converter/converterViewTemplate.html',
|
||||
'modules/base/baseView'],
|
||||
function($, _, Backbone, converterViewTemplate, BaseView){
|
||||
|
||||
var ConverterView = BaseView.extend({
|
||||
|
||||
collection: null,
|
||||
//initialize template
|
||||
template:_.template(converterViewTemplate),
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
ConverterView.__super__.initialize.call(this);
|
||||
//this.header.title = "pippo";
|
||||
},
|
||||
|
||||
events: {
|
||||
"click #calculate": "performCalcBtn",
|
||||
"change #typeLvStart": "typeLvStartChanged"
|
||||
},
|
||||
|
||||
performCalcBtn: function (e) {
|
||||
e.preventDefault();
|
||||
//this.calculateConvert();
|
||||
this.$el.find("#inputForm").submit();
|
||||
},
|
||||
|
||||
typeLvStartChanged: function(e){
|
||||
e.preventDefault();
|
||||
|
||||
if(this.$el.find("#typeLvStart").val() == "ldbf" ||
|
||||
this.$el.find("#typeLvStart").val() == "ldbs"){
|
||||
}
|
||||
else{
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
calculateConvert: function(){
|
||||
var ret ="";
|
||||
if(this.$el.find("#typeLvStart").val() == "ldbf" ||
|
||||
this.$el.find("#typeLvStart").val() == "ldbs"){
|
||||
this.$el.find("#qtaLvlAlt").val(this.impostaPmConsigliata());
|
||||
ret += this.convertiLDB();
|
||||
}
|
||||
else{
|
||||
this.$el.find("#qtaLvlAlt").val(this.impostaPmConsigliata());
|
||||
ret += this.convertiPM();
|
||||
}
|
||||
|
||||
this.$el.find('#result')[0].innerHTML = ret.replace(/<br>/g, "<br><br>");
|
||||
|
||||
this.$el.find('#popupConvertResult').popup("open");
|
||||
},
|
||||
|
||||
convertiPM: function(){
|
||||
|
||||
// dichiaro e inizializzo la variabile che conterrà il risultato dell'elaborazione
|
||||
var risultato = "";
|
||||
|
||||
// imposto come fissa al 50% l'idratazione della PM solida
|
||||
var VidratazionePmSolida = 50;
|
||||
|
||||
// ottengo i valori scelti dall'utente
|
||||
var vTipoPmPartenza = this.$el.find("#typeLvStart").val();
|
||||
var vTipoPmFinale = "";
|
||||
var vIdratazionePmFinale = 0;
|
||||
var vIdratazionePmPartenza = 50; //parseInt(this.$el.find("#qtaLiquidi").val());
|
||||
if(this.$el.find("#typeLvStart").val() == "lic100" )
|
||||
vIdratazionePmPartenza = 100;
|
||||
else if(this.$el.find("#typeLvStart").val() == "lic130" )
|
||||
vIdratazionePmPartenza = 130;
|
||||
|
||||
var vQuantitaPmPartenza = parseInt(this.$el.find("#qtaLvStart").val());
|
||||
var vQuantitaFarinaPartenza = parseInt(this.$el.find("#qtaFarina").val());
|
||||
var vQuantitaAcquaPartenza = parseInt(this.$el.find("#qtaLiquidi").val());
|
||||
var vQuantitaPmFinale = parseInt(this.$el.find("#qtaLvlAlt").val());
|
||||
|
||||
// Imposto di il tipo di PM finale in funzione di quello scelto come partenza
|
||||
// e visualizzo o nascondo di conseguenza la select per l'idratazione
|
||||
switch (this.$el.find("#typeLvDest").val()){
|
||||
case "pm":
|
||||
vTipoPmFinale = "SOLIDA";
|
||||
vIdratazionePmFinale = 50;
|
||||
break;
|
||||
case "lic100":
|
||||
vTipoPmFinale = "LIQUIDA";
|
||||
vIdratazionePmFinale = 100;
|
||||
break;
|
||||
case "lic130":
|
||||
vTipoPmFinale = "LIQUIDA";
|
||||
vIdratazionePmFinale = 130;
|
||||
break;
|
||||
default:
|
||||
vTipoPmFinale = "";
|
||||
}
|
||||
|
||||
// elaborazione per PM finale SOLIDA
|
||||
if (vTipoPmFinale == "SOLIDA") {
|
||||
|
||||
// quanta acqua c'è nella PM liquida di partenza?
|
||||
var qAcquaPmPartenza = (vQuantitaPmPartenza / (100 + vIdratazionePmPartenza)) * vIdratazionePmPartenza;
|
||||
qAcquaPmPartenza = qAcquaPmPartenza.toFixed(0);
|
||||
|
||||
// quanta farina c'è nella PM liquida di partenza?
|
||||
var qFarinaPmPartenza = vQuantitaPmPartenza - qAcquaPmPartenza;
|
||||
|
||||
// quanta acqua c'è nella PM finale?
|
||||
var qAcquaPmFinale = (vQuantitaPmFinale / (100 + VidratazionePmSolida)) * VidratazionePmSolida
|
||||
qAcquaPmFinale = qAcquaPmFinale.toFixed(0);
|
||||
|
||||
// quanta farina c'è nella PM finale?
|
||||
var qFarinaPmFinale = vQuantitaPmFinale - qAcquaPmFinale;
|
||||
|
||||
// come devo modificare l'acqua prevista dalla ricetta originale?
|
||||
// devo aggiungere/togliere la differenza tra l'acqua della PM di partenza e quella finale
|
||||
// quindi calcolo tale differenza...
|
||||
var deltaAcquaPM = qAcquaPmPartenza - qAcquaPmFinale;
|
||||
|
||||
// ...e la aggiungo/tolgo all'acqua dell'impasto della ricetta originale
|
||||
var qAcquaImpastoFinale = vQuantitaAcquaPartenza;
|
||||
|
||||
// se il delta acqua è negativo lo tolgo
|
||||
// altrimenti lo aggiungo
|
||||
if (deltaAcquaPM < 0) {
|
||||
qAcquaImpastoFinale -= deltaAcquaPM;
|
||||
}
|
||||
else {
|
||||
qAcquaImpastoFinale += deltaAcquaPM;
|
||||
}
|
||||
|
||||
// come devo modificare la farina prevista dalla ricetta originale?
|
||||
// devo aggiungere/togliere la differenza tra la farina della PM di partenza e quella finale
|
||||
// quindi calcolo tale differenza...
|
||||
var deltaFarinaPM = qFarinaPmPartenza - qFarinaPmFinale;
|
||||
|
||||
// ...e la aggiungo/tolgo alla farina dell'impasto della ricetta originale
|
||||
var qFarinaImpastoFinale = vQuantitaFarinaPartenza;
|
||||
|
||||
// se il delta farina è negativo lo aggiungo
|
||||
// altrimenti lo tolgo
|
||||
if (deltaFarinaPM < 0) {
|
||||
qFarinaImpastoFinale += deltaFarinaPM;
|
||||
}
|
||||
else {
|
||||
qFarinaImpastoFinale -= deltaFarinaPM;
|
||||
}
|
||||
|
||||
risultato += "PM solida gr " + vQuantitaPmFinale.toString();
|
||||
risultato += "<br>";
|
||||
risultato += "Farina gr " + qFarinaImpastoFinale.toString();
|
||||
risultato += "<br>";
|
||||
risultato += "Acqua gr " + qAcquaImpastoFinale.toString();
|
||||
|
||||
|
||||
}
|
||||
|
||||
// elaborazione per PM finale LIQUIDA
|
||||
if (vTipoPmFinale == "LIQUIDA"){
|
||||
|
||||
// CASO PM LIQUIDA FINALE AL 100%
|
||||
|
||||
// quanta acqua c'è nella PM solida iniziale?
|
||||
var qAcquaPmPartenza = (vQuantitaPmPartenza / (100 + VidratazionePmSolida)) * VidratazionePmSolida
|
||||
qAcquaPmPartenza = qAcquaPmPartenza.toFixed(0);
|
||||
|
||||
// quanta farina c'è nella PM solida iniziale?
|
||||
var qFarinaPmPartenza = vQuantitaPmPartenza - qAcquaPmPartenza;
|
||||
|
||||
// quanta acqua c'è nella PM finale?
|
||||
var qAcquaPmFinale = (vQuantitaPmFinale / (100 + 100)) * 100;
|
||||
qAcquaPmFinale = qAcquaPmFinale.toFixed(0);
|
||||
|
||||
// quanta farina c'è nella PM finale?
|
||||
var qFarinaPmFinale = vQuantitaPmFinale - qAcquaPmFinale;
|
||||
|
||||
// come devo modificare l'acqua prevista dalla ricetta originale?
|
||||
// devo aggiungere/togliere la differenza tra l'acqua della PM di partenza e quella finale
|
||||
// quindi calcolo tale differenza...
|
||||
var deltaAcquaPM = qAcquaPmPartenza - qAcquaPmFinale;
|
||||
|
||||
// ...e la aggiungo/tolgo all'acqua dell'impasto della ricetta originale
|
||||
var qAcquaImpastoFinale = vQuantitaAcquaPartenza;
|
||||
|
||||
// se il delta acqua è negativo lo aggiungo
|
||||
// altrimenti lo tolgo
|
||||
if (deltaAcquaPM < 0){
|
||||
qAcquaImpastoFinale += deltaAcquaPM;
|
||||
}
|
||||
else{
|
||||
qAcquaImpastoFinale -= deltaAcquaPM;
|
||||
}
|
||||
|
||||
// come devo modificare la farina prevista dalla ricetta originale?
|
||||
// devo aggiungere/togliere la differenza tra la farina della PM di partenza e quella finale
|
||||
// quindi calcolo tale differenza...
|
||||
var deltaFarinaPM = qFarinaPmPartenza - qFarinaPmFinale;
|
||||
|
||||
// ...e la aggiungo/tolgo alla farina dell'impasto della ricetta originale
|
||||
var qFarinaImpastoFinale = vQuantitaFarinaPartenza;
|
||||
|
||||
// se il delta farina è negativo lo aggiungo
|
||||
// altrimenti lo tolgo
|
||||
if (deltaFarinaPM < 0){
|
||||
qFarinaImpastoFinale -= deltaFarinaPM;
|
||||
}
|
||||
else{
|
||||
qFarinaImpastoFinale += deltaFarinaPM;
|
||||
}
|
||||
|
||||
if(vIdratazionePmFinale == 100) {
|
||||
risultato += "PM liquida 100% gr " + vQuantitaPmFinale.toString();
|
||||
risultato += "<br>";
|
||||
risultato += "Farina gr " + qFarinaImpastoFinale.toString();
|
||||
risultato += "<br>";
|
||||
risultato += "Acqua gr " + qAcquaImpastoFinale.toString();
|
||||
}
|
||||
else {
|
||||
|
||||
// CASO PM LIQUIDA FINALE AL 130%
|
||||
|
||||
// quanta acqua c'è nella PM solida iniziale?
|
||||
var qAcquaPmPartenza = (vQuantitaPmPartenza / (100 + VidratazionePmSolida)) * VidratazionePmSolida
|
||||
qAcquaPmPartenza = qAcquaPmPartenza.toFixed(0);
|
||||
|
||||
// quanta farina c'è nella PM solida iniziale?
|
||||
var qFarinaPmPartenza = vQuantitaPmPartenza - qAcquaPmPartenza;
|
||||
|
||||
// quanta acqua c'è nella PM finale?
|
||||
var qAcquaPmFinale = (vQuantitaPmFinale / (100 + 130)) * 130;
|
||||
qAcquaPmFinale = qAcquaPmFinale.toFixed(0);
|
||||
|
||||
// quanta farina c'è nella PM finale?
|
||||
var qFarinaPmFinale = vQuantitaPmFinale - qAcquaPmFinale;
|
||||
|
||||
// come devo modificare l'acqua prevista dalla ricetta originale?
|
||||
// devo aggiungere/togliere la differenza tra l'acqua della PM di partenza e quella finale
|
||||
// quindi calcolo tale differenza...
|
||||
var deltaAcquaPM = qAcquaPmPartenza - qAcquaPmFinale;
|
||||
|
||||
// ...e la aggiungo/tolgo all'acqua dell'impasto della ricetta originale
|
||||
var qAcquaImpastoFinale = vQuantitaAcquaPartenza;
|
||||
|
||||
// se il delta acqua è negativo lo aggiungo
|
||||
// altrimenti lo tolgo
|
||||
if (deltaAcquaPM < 0) {
|
||||
qAcquaImpastoFinale += deltaAcquaPM;
|
||||
}
|
||||
else {
|
||||
qAcquaImpastoFinale -= deltaAcquaPM;
|
||||
}
|
||||
|
||||
// come devo modificare la farina prevista dalla ricetta originale?
|
||||
// devo aggiungere/togliere la differenza tra la farina della PM di partenza e quella finale
|
||||
// quindi calcolo tale differenza...
|
||||
var deltaFarinaPM = qFarinaPmPartenza - qFarinaPmFinale;
|
||||
|
||||
// ...e la aggiungo/tolgo alla farina dell'impasto della ricetta originale
|
||||
var qFarinaImpastoFinale = vQuantitaFarinaPartenza;
|
||||
|
||||
// se il delta farina è negativo lo aggiungo
|
||||
// altrimenti lo tolgo
|
||||
if (deltaFarinaPM < 0) {
|
||||
qFarinaImpastoFinale -= deltaFarinaPM;
|
||||
}
|
||||
else {
|
||||
qFarinaImpastoFinale += deltaFarinaPM;
|
||||
}
|
||||
|
||||
risultato += "PM liquida 130% gr " + vQuantitaPmFinale.toString();
|
||||
risultato += "<br>";
|
||||
risultato += "Farina gr " + qFarinaImpastoFinale.toString();
|
||||
risultato += "<br>";
|
||||
risultato += "Acqua gr " + qAcquaImpastoFinale.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return risultato;
|
||||
},
|
||||
|
||||
convertiLDB: function(){
|
||||
// dichiaro e inizializzo la variabile che conterrà il risultato dell'elaborazione
|
||||
var risultato = "";
|
||||
|
||||
// dichiaro e inizializzo la variabile che conterrà la quantità di farina da usare
|
||||
var vQuantitaFarinaDaUsare = 0;
|
||||
|
||||
// dichiaro e inizializzo la variabile che conterrà la quantità di acqua da usare
|
||||
var vQuantitaAcquaDaUsare = 0;
|
||||
|
||||
// dichiaro e inizializzo la variabile per la quantità di farina presente nella PM da usare
|
||||
var qFarinaPmDaUsare = 0;
|
||||
|
||||
// dichiaro e inizializzo la variabile per la quantità di acqua presente nella PM da usare
|
||||
var qAcquaPmDaUsare = 0;
|
||||
|
||||
// ricavo la quantità di LDB della ricetta originale
|
||||
var vQuantitaLdbPartenza = parseInt(this.$el.find("#qtaLvStart").val());
|
||||
|
||||
// ricavo l'idratazione della PM da usare
|
||||
var vIdratazionePmFinale = 50;
|
||||
if(this.$el.find("#typeLvDest").val() == "lic100" )
|
||||
vIdratazionePmFinale = 100;
|
||||
else if(this.$el.find("#typeLvDest").val() == "lic130" )
|
||||
vIdratazionePmFinale = 130;
|
||||
|
||||
// ricavo la quantità di farina della ricetta originale
|
||||
var vQuantitaFarinaPartenza = parseInt(this.$el.find("#qtaFarina").val());
|
||||
|
||||
// ricavo la quantità di acqua della ricetta originale
|
||||
var vQuantitaAcquaPartenza = parseInt(this.$el.find("#qtaLiquidi").val());
|
||||
|
||||
// ricavo la quantità di PM da usare
|
||||
var vQuantitaPmDaUsare = parseInt(this.$el.find("#qtaLvlAlt").val());
|
||||
|
||||
// quanta acqua c'è nella PM da usare?
|
||||
var qAcquaPmDaUsare = (vQuantitaPmDaUsare / (100 + vIdratazionePmFinale)) * vIdratazionePmFinale;
|
||||
qAcquaPmDaUsare = qAcquaPmDaUsare.toFixed(0);
|
||||
|
||||
// ricavo la quantità di farina presente nella PM da usare
|
||||
qFarinaPmDaUsare = vQuantitaPmDaUsare - qAcquaPmDaUsare;
|
||||
|
||||
// diminuisco la farina della ricetta originale di una quantità pari a quella presente nella PM da usare
|
||||
vQuantitaFarinaDaUsare = vQuantitaFarinaPartenza - qFarinaPmDaUsare;
|
||||
|
||||
// diminuisco l'acqua della ricetta originale di una quantità pari a quella presente nella PM da usare
|
||||
vQuantitaAcquaDaUsare = vQuantitaAcquaPartenza - qAcquaPmDaUsare;
|
||||
|
||||
// costruisco la stringa del risultato
|
||||
risultato += "PM gr " + vQuantitaPmDaUsare.toString();
|
||||
risultato += "<br>";
|
||||
risultato += "Farina gr " + vQuantitaFarinaDaUsare.toString();
|
||||
risultato += "<br>";
|
||||
risultato += "Acqua gr " + vQuantitaAcquaDaUsare.toString();
|
||||
|
||||
|
||||
return risultato;
|
||||
},
|
||||
|
||||
impostaPmConsigliata: function(){
|
||||
|
||||
var dummy = "";
|
||||
|
||||
|
||||
// dichiaro e inizializzo la variabile per la quantità consigliata di pasta madre
|
||||
var vQuantitaPmConsigliata = 0;
|
||||
|
||||
if(this.$el.find("#typeLvStart").val() == "pm")
|
||||
{
|
||||
vQuantitaPmConsigliata = ((parseInt(this.$el.find("#qtaLvStart").val()) / 3) * 2);
|
||||
}
|
||||
else if(this.$el.find("#typeLvStart").val() == "lic100" ||
|
||||
this.$el.find("#typeLvStart").val() == "lic130")
|
||||
{
|
||||
vQuantitaPmConsigliata = ((parseInt(this.$el.find("#qtaLvStart").val()) / 2) * 3);
|
||||
}
|
||||
else {
|
||||
// dichiaro e inizializzo la variabile per la quantità di lievito di birra
|
||||
var vQuantitaLdbPartenza = 0;
|
||||
|
||||
// dichiaro e inizializzo la variabile per il tipo di lievito di birra
|
||||
var vTipoLdbPartenza = "";
|
||||
|
||||
// dichiaro e inizializzo la variabile per la quantità consigliata di pasta madre massima ammessa
|
||||
var vQuantitaPmConsigliataMax = 0;
|
||||
|
||||
// imposto il rapporto percentuale di default PM solida/Farina... ma è solo orientativo
|
||||
var rapportoPmSolidaFarina = 25;
|
||||
|
||||
// imposto il rapporto percentuale di default PM liquida 100%/Farina... ma è solo orientativo
|
||||
var rapportoPm100Farina = 16.5;
|
||||
|
||||
// imposto il rapporto percentuale di default PM liquida 100%/Farina... ma è solo orientativo
|
||||
var rapportoPm130Farina = 16.5;
|
||||
|
||||
// ricavo la quantità di farina della ricetta originale
|
||||
var vQuantitaFarinaPartenza = parseInt(this.$el.find('#qtaFarina').val());
|
||||
|
||||
// ricavo l'idratazione della PM da usare
|
||||
var vIdratazionePmFinale = 0;
|
||||
|
||||
switch (this.$el.find("#typeLvDest").val()) {
|
||||
case "pm":
|
||||
vTipoPmFinale = "SOLIDA";
|
||||
vIdratazionePmFinale = 50;
|
||||
break;
|
||||
case "lic100":
|
||||
vTipoPmFinale = "LIQUIDA";
|
||||
vIdratazionePmFinale = 100;
|
||||
break;
|
||||
case "lic130":
|
||||
vTipoPmFinale = "LIQUIDA";
|
||||
vIdratazionePmFinale = 130;
|
||||
break;
|
||||
default:
|
||||
vTipoPmFinale = "";
|
||||
}
|
||||
// altrimenti faccio il rapporto partendo dalla quantità del lievito di birra
|
||||
|
||||
// ricavo la quantità di lievito di birra
|
||||
vQuantitaLdbPartenza = parseInt(this.$el.find('#qtaLvStart').val());
|
||||
|
||||
// ricavo il tipo di lievito di birra
|
||||
vTipoLdbPartenza = this.$el.find("#typeLvStart").val();
|
||||
|
||||
if (!isNaN(vQuantitaLdbPartenza)) {
|
||||
if (vQuantitaLdbPartenza > 0) {
|
||||
if (vTipoLdbPartenza == "ldbs") {
|
||||
// 6 ldb = 240 PM
|
||||
vQuantitaPmConsigliata = (240 / 6) * vQuantitaLdbPartenza;
|
||||
}
|
||||
else {
|
||||
// 15 ldb = 240 PM
|
||||
vQuantitaPmConsigliata = (240 / 15) * vQuantitaLdbPartenza;
|
||||
}
|
||||
|
||||
// SE IL RISULTATO OTTENUTO E' IRRAGIONEVOLE LO CORREGGO
|
||||
switch (this.$el.find('#typeLvDest').val()) {
|
||||
case "pm":
|
||||
vQuantitaPmConsigliataMax = (vQuantitaFarinaPartenza / 100) * rapportoPmSolidaFarina;
|
||||
break;
|
||||
case "lic100":
|
||||
vQuantitaPmConsigliataMax = (vQuantitaFarinaPartenza / 100) * rapportoPm100Farina;
|
||||
break;
|
||||
case "lic130":
|
||||
vQuantitaPmConsigliataMax = (vQuantitaFarinaPartenza / 100) * rapportoPm130Farina;
|
||||
break;
|
||||
default:
|
||||
vQuantitaPmConsigliataMax = 0;
|
||||
}
|
||||
if (vQuantitaPmConsigliata > vQuantitaPmConsigliataMax) {
|
||||
vQuantitaPmConsigliata = vQuantitaPmConsigliataMax;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
vQuantitaPmConsigliata = 0;
|
||||
alert("Impossibile calcolare\nAccertati di aver scritto bene la quantita'\ndi lievito di birra nella ricetta originale.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
vQuantitaPmConsigliata = 0;
|
||||
alert("Impossibile calcolare\nAccertati di aver scritto bene la quantita'\ndi lievito di birra nella ricetta originale.");
|
||||
}
|
||||
}
|
||||
return vQuantitaPmConsigliata;
|
||||
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
ConverterView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
var self = this;
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template({ deviceWidth: myManifest.Settings.Device.Width }));
|
||||
this.$el.append(this.footer.$el);
|
||||
|
||||
//this.$el.find("#popupConvertResult").css("max-width", myManifest.Settings.Device.Width + "px" );
|
||||
|
||||
jQuery.validator.addMethod("cRequired", $.validator.methods.required,
|
||||
"Il campo è richiesto, si prega di completarlo");
|
||||
|
||||
jQuery.validator.addMethod("requireIf", function(value, element, params) {
|
||||
if(self.$el.find('#typeLvStart').val() != "ldbf" &&
|
||||
self.$el.find('#typeLvStart').val() != "ldbs")
|
||||
{
|
||||
return value!="";
|
||||
}
|
||||
return true;
|
||||
}, jQuery.validator.format("Il campo è richiesto, si prega di completarlo"));
|
||||
|
||||
jQuery.validator.addClassRules("cRequireIf", {
|
||||
requireIf: true
|
||||
});
|
||||
|
||||
jQuery.validator.addClassRules("cRequired", {
|
||||
cRequired: true
|
||||
});
|
||||
|
||||
this.$el.find("#inputForm").validate({
|
||||
submitHandler: function() {
|
||||
self.calculateConvert();
|
||||
}
|
||||
});
|
||||
this.$el.find("#moreBtn").addClass("ui-btn-active");
|
||||
//$("#homeBtn").addClass("ui-btn-active");
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return ConverterView;
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
<div data-role="content">
|
||||
<h1>Convertitore</h1>
|
||||
<form id="inputForm">
|
||||
<label for="typeLvStart">Tipo lievito della ricetta originale:</label>
|
||||
<select name="typeLvStart" id="typeLvStart" data-theme="a" class="cRequired">
|
||||
<option value="">Selezionare il tipo di lievito</option>
|
||||
<option value="ldbf">Lievito di Birra Fresco</option>
|
||||
<option value="ldbs">Lievito di Birra Secco</option>
|
||||
<option value="pm">PM Solida</option>
|
||||
<option value="lic100">PM Liquida 100% (Li.Co.Li.)</option>
|
||||
<option value="lic130">PM Liquida 130% (Li.Co.Li.)</option>
|
||||
</select>
|
||||
<br>
|
||||
<label for="qtaLvStart">Lievito nella ricetta originale:</label>
|
||||
<input type="number" data-clear-btn="false" name="qtaLvStart" id="qtaLvStart" value="" placeholder="Specificare quantità in grammi" data-theme="a" class="cRequired">
|
||||
<br>
|
||||
<label for="typeLvDest">Tipo lievito che si vuole utilizzare:</label>
|
||||
<select name="typeLvDest" id="typeLvDest" data-theme="a" class="cRequired">
|
||||
<option value="">Selezionare il tipo di lievito</option>
|
||||
<option value="pm">PM Solida</option>
|
||||
<option value="lic100">PM Liquida 100% (Li.Co.Li.)</option>
|
||||
<option value="lic130">PM Liquida 130% (Li.Co.Li.)</option>
|
||||
</select>
|
||||
<br>
|
||||
<label for="qtaFarina">Farina per l'impasto nella ricetta originale:</label>
|
||||
<input type="number" data-clear-btn="false" name="qtaFarina" id="qtaFarina" value="" placeholder="Specificare quantità in grammi" data-theme="a" class="cRequired">
|
||||
<br>
|
||||
<label for="qtaLiquidi">Liquidi (acqua, latte...) per l'impasto nella ricetta originale:</label>
|
||||
<input type="number" data-clear-btn="false" name="qtaLiquidi" id="qtaLiquidi" value="" placeholder="Specificare quantità in grammi" data-theme="a" class="cRequired">
|
||||
<br>
|
||||
<!-- <label for="qtaLvlAlt">Lievito alternativo rispetto alla ricetta originale che intendi usare:</label>-->
|
||||
<input type="hidden" data-clear-btn="false" name="qtaLvlAlt" id="qtaLvlAlt" value="" placeholder="Specificare quantità in grammi" data-theme="a" disabled="disabled">
|
||||
<br>
|
||||
<button type="submit" id="calculate" class="ui-shadow ui-btn ui-corner-all" data-theme="a">Calcola</button>
|
||||
</form>
|
||||
<div data-role="popup" id="popupConvertResult" data-dismissible="false" style="width: 300px;max-width: <%= deviceWidth%>px">
|
||||
<div data-role="header">
|
||||
<h1>Conversione</h1>
|
||||
</div>
|
||||
<div role="main" class="ui-content">
|
||||
<h3 class="ui-title" id="result" style="text-align: center;"></h3>
|
||||
<p style="text-align: center;font-style: italic;"><br><br>IMPORTANTE<br><br>
|
||||
La quantità consigliata è da ritenersi
|
||||
<br>
|
||||
assolutamente indicativa in quanto la scelta
|
||||
<br>
|
||||
dovrebbe essere fatta sulla base
|
||||
<br>
|
||||
dell'esperienza, del particolare impasto
|
||||
<br>
|
||||
e delle condizioni ambientali di temperatura
|
||||
<br>
|
||||
e umidità</p>
|
||||
<a href="" class="ui-btn ui-corner-all ui-shadow ui-btn-b ui-icon-check" data-rel="back">Ok</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/donation/donationViewTemplate.html', 'modules/base/baseView'],
|
||||
function($, _, Backbone, homeViewTemplate, BaseView){
|
||||
|
||||
var DonationView = BaseView.extend({
|
||||
|
||||
//initialize template
|
||||
template:_.template(homeViewTemplate),
|
||||
|
||||
initialize: function () {
|
||||
DonationView.__super__.initialize.call(this);
|
||||
//this.header.title = "pippo";
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
DonationView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template());
|
||||
this.$el.append(this.footer.$el);
|
||||
this.$el.find("#moreBtn").addClass("ui-btn-active");
|
||||
//$("#homeBtn").addClass("ui-btn-active");
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return DonationView;
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
<div data-role="content">
|
||||
<h1>Donazione</h1>
|
||||
<div style="text-align: center;">
|
||||
<h3>NOI stiamo facendo tutto per la passione.<br><br>Ma se vuoi darci una mano per continuare a migliorare questo sito/app <br><br>Puoi darci un piccolo contributo donando quanto vuoi e puoi, NOI ti ringraziamo.</h3>
|
||||
</div><br><br>
|
||||
<div style="text-align: center;"><form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="J8X4NCWYUCN2Q">
|
||||
<input type="image" src="https://www.paypalobjects.com/it_IT/IT/i/btn/btn_donate_SM.gif" border="0" name="submit" alt="PayPal - Il metodo rapido, affidabile e innovativo per pagare e farsi pagare.">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/it_IT/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,30 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/faq/faqViewTemplate.html', 'modules/base/baseView'],
|
||||
function($, _, Backbone, faqViewTemplate, BaseView){
|
||||
|
||||
var FaqView = BaseView.extend({
|
||||
|
||||
//initialize template
|
||||
template:_.template(faqViewTemplate),
|
||||
|
||||
initialize: function () {
|
||||
FaqView.__super__.initialize.call(this);
|
||||
//this.header.title = "pippo";
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
FaqView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template());
|
||||
this.$el.append(this.footer.$el);
|
||||
this.$el.find("#faqBtn").addClass("ui-btn-active");
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return FaqView;
|
||||
});
|
||||
@@ -0,0 +1,125 @@
|
||||
<div data-role="content">
|
||||
<h1>Lo sai che?</h1>
|
||||
<ul data-role="listview" id="faqList">
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>PM. Iniziare</h2> <div data-role="collapsible"><h4>Come ottenere il Lievito Madre</h4><p>Il modo più semplice ed immediato è trovare uno spacciatore che ci doni gratuitamente un pezzetto del suo Lievito Madre.
|
||||
Al link seguente trovi la mappa degli spacciatori del gruppo e quella generale della comunità del cibo.<br>
|
||||
<a href="https://www.facebook.com/notes/gruppo-la-pasta-madre/la-mappa-spacciatori-del-gruppo/733005206786758">Link Gruppo FB</a><br>
|
||||
<a href="http://pastamadre.blogspot.it/p/spacciatori-di-pasta-madre.html">Mappa Spacciatori</a></p></div>
|
||||
<div data-role="collapsible"><h4>Partire da zero</h4><p>Creare la propria Pasta Madre non è difficile, anche se è necessario attendere il raggiungimento dell'equilibrio tra batteri e lactobacilli.<br>
|
||||
Ti serviranno Farina, Acqua un eventuale Starter e molta pazienza.<br>
|
||||
Alcuni metodi sono elencati al link: <a href="https://www.facebook.com/notes/gruppo-la-pasta-madre/come-partire-ricette-e-consigli-per-autoprodursi-pasta-madre-o-licoli/733307843423161">Link Gruppo FB</a></p></div>
|
||||
<div data-role="collapsible"><h4>Posso Creare PM Senza Glutine</h4><p>Certamente si! Trovi le indicazioni al link:
|
||||
<a href="https://www.facebook.com/notes/gruppo-la-pasta-madre/pasta-madre-e-ricette-glutenfree/733308193423126">Link Gruppo FB</a></p></div>
|
||||
<div data-role="collapsible"><h4>Lievito Madre essicato al supermercato</h4><p> Ho visto in commercio confezioni di lievito madre essiccato. E' pasta madre Posso cominciare così la mia PM? No. Il lievito madre essiccato in commercio contiene lievito di birra, che è l'unico responsabile della lievitazione degli impasti a cui viene aggiunto; la pasta madre presente è inattiva ed ha solo la funzione aromatica. Per approfondimenti vedere al <a href="http://pastamadre.blogspot.it/2012/03/lievitazione-ingannevole.html">link</a></p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>PM. Autoprodotta</h2> <div data-role="collapsible"><h4>Dove è consigliato generare e conservare la PM in formazione?</h4><p> In un barattolo di vetro alto e stretto, coperto, tenuto a Temperatura Ambiente (preferibilmente al calduccio 25/28°) e lontano da correnti e sbalzi di temperatura. </p></div>
|
||||
<div data-role="collapsible"><h4>Puntini neri/odore di acido/non si è mossa.</h4><p>La mia PM a 48 ore dalla nascita è coperta di puntini neri/odora di acido/non si è mossa. Butto tutto? No. E' normale che una Pm alla nascita presenti queste caratteristiche poiche deve stabilizzarsi il PH al suo interno e l'equiibrio tra lactobaccili e lieviti.<br>
|
||||
Prendi il cuore del panetto e continua coi rinfreschi.</p></div>
|
||||
<div data-role="collapsible"><h4>Raddoppio incostante dopo 10 giorni</h4><p> Una PM appena nata non ha ancora raggiunto la stabilità tra fermenti e lievti, perciò potrebbe aumentare in modo diverso da un giorno all'altro. Se presenta bollicine è perchè la fermentazione è partita quindi devi avere pazienza e continuare coi rinfreschi. </p></div>
|
||||
<div data-role="collapsible"><h4>Quando posso iniziare ad usare la PM autodrodotta? Quando posso mettere in frigorifero?</h4><p> La tua Pm sarà pronta all'utilizzo quando raddoppierà costantemente in 4 ore, ovvero avrà raggiunto un equilibrio accettabile tra lieviti e lactobacilli. Da questo momento potrai conservarla in frigorifero e rinfrescarla meno frequentemente. </p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>PM. Il Mantenimento (Rinfresco, fermentazione, collasso...) </h2> <div data-role="collapsible"><h4>Cos'è il rinfresco (o rigenero)?</h4><p>La Pasta Madre è un organismo vivo e per questo necessita di nutrimento:<br>
|
||||
aggiungendo acqua e farina alla tua pm, le dai ""da mangiare"". I lieviti nutrendosi fanno partire la fermentazione e gonfiano la pm creando bolle d'aria.</p></div>
|
||||
<div data-role="collapsible"><h4>L'esubero di pasta madre</h4><p>"Esubero... chi era costui???"<br>
|
||||
E' in assoluto la domanda più ricorrente qua dentro, la FAQ delle FAQ insomma, fiumi di discussioni in merito: chi lo definisce in un modo, chi in un altro, chi ne ha il frigo pieno, chi non lo conosce, chi lo butta, chi panifica solo con quello... ma in sintesi: <b>cosa sarebbe l'esubero?</b><br><br>
|
||||
Secondo il dizionario l'esubero è un'eccedenza, un avanzo, ma nel nostro ambito specifico, che è quello della panificazione con lievito madre, direi che possiamo trovarci in accordo nel definirlo <b>pasta madre di avanzo</b> (ebbene sì anche l'esubero è pasta madre!) <b>che non abbia subito un rinfresco recente.</b><br><br>
|
||||
La pasta madre come ben sappiamo è <u>un impasto di acqua e farina colonizzato da particolari microrganismi (lieviti e lactobacilli) che le fanno avere potere fermentante, essi sono un qualcosa di vivo e per continuare a fare il proprio lavoro devono essere nutriti con quantitativi prestabiliti di acqua e farina. Una volta nutrita attraverso il rinfresco, la nostra pasta madre aumenta di volume raggiungendo un apice di crescita, dopo il quale (ed è fisiologico), raggiunge il collasso e tende ad inacidirsi.<br><br>
|
||||
I tempi di questo ciclo vitale cambiano a seconda delle temperature, del quantitativo di farina aggiunta e della sua forza (diciamo che spesso si ha un raddoppio di volume in tre/quattro ore ma la vera e propria fase decrescente è successiva).</u><br><br>
|
||||
Normalmente (ovvero se non è specificato altrimenti in ricetta) <b>per panificare si utilizza pasta madre che ha subito un rinfresco ed ha dunque microrganismi ben attivi</b>: si prende il nostro lievito dal frigorifero, lo lasciamo ambientare, lo rinfreschiamo, una parte la teniamo come madre per le panificazioni successive riponendola in frigo (c'è chi lo fa dopo un'oretta dal rinfresco, chi invece lascia raddoppiare e la ripone dopo averla sgonfiata - sono gli stessi maestri a fornire consigli differenti in merito...) e una parte la lasciamo lievitare e la utilizziamo nel nostro impasto.<br>
|
||||
In questo modo NON si producono avanzi e l'equilibrio è perfetto.<br>
|
||||
<b>La pasta madre solida (anche la liquida, ma con tempi di resistenza senza rinfresco più lunghi rispetto alla solida) dovrebbe subire un rinfresco almeno una volta a settimana per rimanere ben vitale, può però capitare che non si abbia voglia di panificare in occasione del rinfresco... allora cosa si fa?</b> In questo caso si rinfresca solo il lievito che abbiamo intenzione di conservare come madre lasciando il resto senza rinfresco (ed eccolo qua il nostro ESUBERO) oppure lo si rinfresca tutto e la parte che non lasciamo come madre e che rimane comunque inutilizzata (perché per l'appunto non abbiamo voglia di panificare) verrà riposta in frigo e con il trascorrere del tempo (non subito perché inizialmente è per l'appunto normale e vitalissima pm rinfrescata) inizierà la propria fase decrescente in cui perderà di attività e si inacidirà (ed ecco che di nuovo, abbiamo un ESUBERO).<br><br>
|
||||
<b>Insomma l'esubero non è una entità astratta, è semplicemente pasta madre non rinfrescata di avanzo.</b><br><br>
|
||||
<b>Cosa si fa con l'esubero se lo si ha?</b> (e sottolineo che se panifichiamo almeno una volta a settimana e teniamo da parte quantitativi piuttosto ristretti di pasta madre è pure possibile NON avere alcun esubero)<br><br>
|
||||
Le alternative sono due: lo si butta (ma in tanti si rifiutano categoricamente di di farlo) o lo si utilizza in <b>ricette cosiddette per esubero</b> (è una categoria apposita all'interno del nostro Lievitario <a href="http://app.gruppolapastamadre.it/#category/Esuberi/6">Categoria Esuberi</a>).<br>
|
||||
Queste ricette possono non prevedere alcuna lievitazione (cracker, grissini, taralli, piade o similari -in questo caso la pasta madre è trattata alla stregua di acqua e farina e ha al massimo un potere aromatizzante, non di certo lievitante) oppure possono essere ricette classiche con pm e lievitazione (in questo caso i tempi di lievitazione e il quantitativo di pm di esubero utilizzato dovrebbe tener conto del fatto che esso abbia un minor potere lievitante rispetto alla pm rinfrescata).<br><br>
|
||||
Detto questo vorrei fare alcune considerazioni: <br><br>
|
||||
1. Come accennavo sopra <b>non è che gli esuberi siano d'obbligo</b> (né con pm solida né tanto meno con licoli), io ad esempio utilizzo licoli e non ne ho perché tengo pochissimo lievito da parte (anche soli 30 g) e se ho bisogno di quantitativi maggiori rinfresco più volte, cosa che lo rende pure più attivo, così come se proprio voglio realizzare una ricetta per esubero (a casa mia piacciono un sacco le similpiade ad esempio)<br><br>
|
||||
2. non considero comunque 'esubero' una pasta madre rinfrescata da un lasso di tempo superiore anche alle canoniche 3/4 ore che mostra comunque segnali di gran attività (se il mio licolì rinfrescato il giorno prima è ancora pieno di bolle lo utilizzo in ricette normalissime e non mi pongo il problema, infatti tutto lievita alla perfezione)<br><br>
|
||||
3. dall'altra parte vedo però che nel gruppo ci sono (tante) persone che molto fieramente postano quasi soltanto foto di panificati fatti con esubero e mi chiedo cosa facciano della pm rinfrescata, arrivando a ipotizzare che preferiscano lasciarla diventare un esubero (e a me pare un paradosso)<br><br>
|
||||
4. mi viene poi da sorridere quando (è capitato più volte) alcune persone parlano di una ricetta con esubero e sottolineano che per realizzarla... lo hanno rinfrescato!!!! A queste vorrei ricordare che un esubero rinfrescato altro non è... che normalissima pasta madre!!!<br></p></div>
|
||||
<div data-role="collapsible"><h4>Perchè dopo un po' il mio lievito smette di gonfiarsi e collassa su se stesso?</h4><p>Quando i microrganismi del lievito hanno finito di ""digerire"" la farina, inizia il processo inverso e la pm si sgonfia. Basterà un nuovo rinfresco per far ripartire il processo.<br>
|
||||
Se il tempo che intercorre tra i rinfreschi è molto lungo il lievito inizia ad inacidire e per recuperarlo saranno necessari più rinfreschi ripetuti.</p></div>
|
||||
<div data-role="collapsible"><h4>La pm va tenuta in frigo o a temperatura ambiente?</h4><p>Dipende da quanto spesso la rinfreschi e da quando devi panificare. In linea di massima, il freddo rallenta il processo di fermentazione, quindi se a 20° la tua pm raddoppia in 4 ore, in frigo ci potrà mettere il doppio del tempo o anche bloccarsi completamente. Se dopo il rinfresco vuoi impastare, aspetta che sia raddoppiata, prelevi quella che ti serve per impastare e riponi il resto in frigo fino al prossimo rinfresco.<br>
|
||||
Si consiglia di aspettare un'oretta prima di riporla in frigorifero per far partire meglio la fermentazione; lo stesso è consigliabile in uscita dal frigo prima del rinfresco per farla acclimatare.</p></div>
|
||||
<div data-role="collapsible"><h4>Come capisco se il mio lievito va bene e se non va bene come correggo?</h4><p>Osservando Annusando Assaggiando
|
||||
Lievito in forma: pasta Bianca ,Soffice, con alveoli allungati, odora di farina e si percepisce l'acidità, all'assaggio rivela un sapore aciduloo e pungente. (PH = 5)<br>
|
||||
<br>
|
||||
Lievito troppo forte: ha un colore Grigiastro con alveoli tondi, ha un odore amarognolo ed il sapore è acido-amaro (PH < 5)<br>
|
||||
rimedio: Bagnetto: formare un salsicciotto di lievito e Tagliarlo a fette di circa 1cm di spessore. Immergerlo in acqua (20-22°C) zuccherata (2 g di zucchero per ogni litro d'acqua) e lasciarlo a bagno per 15-30 minuti; strizzarlo e rinfrescare con farina doppia (50g PM + 100g farina + 50g acqua). Proseguire con normali rinfreschi.<br>
|
||||
<br>
|
||||
Lievito Troppo Debole: Pasta di colore Bianco pochi alveoli, odore dolciastro tipo latte, sapore dolciastro, (PH > 5)<br>
|
||||
rimedio: Rinfrescare aggiungendo 1 cucchiaio di zucchero o miele, rinfrescare con minore quantità di farina (100g PM + 75g farina + 40g acqua). Proseguire con normali rinfreschi. proseguire con normali rinfreschi finchè il lievito non raddoppierà in 4 ore<br>
|
||||
<br>
|
||||
Lievito Inacidito: Si presenta di colore Grigio e la pasta è vischiosa, l'odore ricorda il formaggio, il sapore è acetico. (PH molto basso 1-2).<br>
|
||||
rimedio: rinfresco con una quantità doppia di farina e acqua aggiungere 1 tuorlo d'uovo e un pizzico di zucchero (50g PM + 100g farina + 50g acqua+1 tuorlo+2g zucchero)</p></div>
|
||||
<div data-role="collapsible"><h4>Nella mia PM possono prodursi batteri patogeni (botulino)?</h4><p> La pasta madre è una coltura stabile simbiotica di batteri lattici (LAB) e lievito in una miscela di farina ed acqua. Quello che si viene a creare ad avvenuta maturazione dell'LM è un equilibrio biologico di specie di microrganismi che non concorrono per il nutrimento ma che si cibano dei prodotti della fermentazione altrui (i Lab fermentano gli zuccheri che i lieviti non possono fermentare e i lieviti fermentano i prodotti della fermentazione dei primi) un vero e proprio equilibrio biochimico sancito da un pH stabile e da un rapporto tra acido lattico e acido acetico di 3:1. In questa maniera si creano i presupposti perchè determinate specie patogene non attecchiscano e soprattutto quando un lievito è maturo e di annata è difficile sconvolgerne gli equilibri. Ogni volta che aggiungiamo farina e acqua, forniamo il nutrimento ed aggiungiamo microbi alla pasta. i microbi patogeni avranno la peggio mentre i microbi compatibili con le specie che sono già nella pasta si aggiungeranno a quelli preesistenti. (cit. Paolo Sanguedolce) </p></div>
|
||||
<div data-role="collapsible"><h4>Ho trovato la mia pm liquida con uno strato di acqua grigia sopra, cosa faccio?</h4><p> E' tutto regolare, semplicemente la farina e l'acqua si sono separate: mischia tutto e rinfresca normalmente. </p></div>
|
||||
<div data-role="collapsible"><h4>Per sbaglio ho rinfrescato la mia pm solida con uguale acqua e farina e ora ho un blob informe, come faccio?</h4><p> Non è un grosso problema. Se te ne accorgi subito puoi aggiungere un'altra dose di farina in modo che sia il doppio dell'acqua. La pm tornerà della giusta consistenza e ci vorrà un po' di più perchè raddoppi (ha più "cibo"). Se invece te ne accorgi a raddoppio avvenuto, metti più farina nei prossimi rinfreschi fino a quando non sarà tornata della giusta consistenza. </p></div>
|
||||
<div data-role="collapsible"><h4>Ho poca pm come faccio ad averne di più? Come faccio a calcolare quuanta PM rinfrescare per averne abbastanza per la ricetta?</h4><p> Rinfreschi più volte senza utilizzarla. </p></div>
|
||||
<div data-role="collapsible"><h4>Come faccio a calcolare quanta PM rinfrescare per averne abbastanza per la ricetta?</h4><p>Ricorda che nulla si crea e nulla si distrugge perciò il peso del tuo lievito sarà dato dal peso degli ingredienti del rinfresco:<br>
|
||||
-Con la solida otterrai 2 volte e mezzo il peso iniziale (100g di PM+ 100 farina + 50 acqua= 250g PM)<br>
|
||||
-Con lLicoli otterrai il triplo del perso iniziale ( 100g di Licoli+ 100 farina + 100 acqua= 300g Licoli)</p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>Impastare con PM</h2> <div data-role="collapsible"><h4>Bisogna sempre rinfrescare la pm per panificare?</h4><p> Sì. perchè il rinfresco ATTIVA i lieviti. </p></div>
|
||||
<div data-role="collapsible"><h4>Quanto devo aspettare prima di impastare?</h4><p>Dopo aver rinfrescato la PM si attende il raddoppio (3/4 orea temperatura ottimale, di più se fa freddo).<br>
|
||||
La PM non rinfrescata viene chiamata ESUBERO ed è utilizzabile in ricette che non prevedono particolare spinta di lievitazione</p></div>
|
||||
<div data-role="collapsible"><h4>Perchè il mio impasto non lievita?</h4><p>Possono esserci diversi motivi tra i più comuni:<br>
|
||||
- La pm non era in forma o l'hai usata a troppo tempodal rinfresco<br>
|
||||
- La temperatura è troppo bassa , l'ideale è da 25° a 28°, se è più bassa la lievitazione richiede più tempo. Puoi aiutarti con una fonte di calore non troppo forte (lucina nel forno, decoder, vicinanze stufa, sole)<br>
|
||||
La temperatura è troppo alta, sopra i 30°, l'impasto rischia di inacidire e passare la lievitazione sgonfiandosi e collassando<br>
|
||||
- l'impasto è molto pesante (con uova o grassi) e ha bisogno di più tempo.</p></div>
|
||||
<div data-role="collapsible"><h4>Perchè il mio pane è acido?</h4><p>Alcuni motivi:<br>
|
||||
Problema nella PM:<br>
|
||||
E' acida la PM, hai impastato senza rinfrescare.<br>
|
||||
Problema di lievitazione:<br>
|
||||
hai lasciato l'impasto a lievitare per troppe ore o al troppo caldo.</p></div>
|
||||
<div data-role="collapsible"><h4>L'impasto per il pane è lievitato troppo e ora sa di acido. Butto tutto?</h4><p>Se il tuo impasto sa di acido anche il prodotto finale potrebbe avere lo stesso problema.<br>
|
||||
Puoi fare un tentativo cuocendo un pezzetto piccolo di impasto e vedere se la cottura toglie abbastanza acidità.<br>
|
||||
Oppure puoi reuperarlo aggiungendo acqua e farina nelle stesse proporzioni della ricetta lasciare lievitare anchora un po' e infornare.<br>
|
||||
Oppure puoi aggiungere farina, semola, olio e sale e fare crakers o taralli.<br>
|
||||
Insomma fanne qualcosa, ma non gettare il cibo senza averci almeno provato ;)</p></div>
|
||||
<div data-role="collapsible"><h4>Come fare il un pane semplice?</h4><p> Dopo aver tirato fuori la pm dal frigo aspetta circa un'ora per farla acclimatare poi la rinfreschi. Al raddoppio (circa 3-4 ore) puoi impastare seguendo la ricetta. Metti a lievitare il tempo necessario (6-8 ore) in un luogo tiepido e privo di correnti (ad esempio il forno spento, un credenzino o una cella di lievitazione) dai la forma al pane lo lasci riposare ancora una o 2 ore e poi lo cuoci. Nelle ricette trovi anche il livello di difficoltà. </p></div>
|
||||
<div data-role="collapsible"><h4>Cosa significa che un impasto è idratato al 50, 60, 70%?</h4><p> ci si riferisce alla percentuale di liquidi rispetto alla farina. Una idratazione al 50 significa che l'acqua è la metà della farina (ad esempio 500g di acqua su un chilo di farina), chiaramente in questa percentuale c'è anche da considerare i quantitativi di acqua e farina introdotti in ricetta attraverso la pasta madre (con le dovute differenze tra pasta madre solida, idratata al 50 per cento - l'acqua è la metà della farina - e la pasta madre liquida, idratata al 100 - pari peso di acqua e farina). Idratazioni maggiori danno dolitamente alveolature più pronunciate </p></div>
|
||||
<div data-role="collapsible"><h4>Qual è la funzione della lievitazione in frigo che qui nel gruppo in tanti usano?</h4><p> Il frigo ha un doppio uso: da una parte aiuta ad organizzarci meglio coi tempi (in frigo la lievitazione non è che si blocca ma rallenta un sacco - così alle volte per non rischiare infornate notturne si impasta, mette in frigo, magari dopo un'oretta, per concedere alla lievitazione di partire per bene, e poi si continua il giorno successivo a temperatura ambiente) dall'altra parte ha anche vantaggi in termini di leggerezza e (maggiore) digeribilità degl impasti (vedi anche <a href="http://www.profumidalforno.it/forum/viewtopic.php?f=4&t=98">qui</a>). Insomma si può usare il frigo per allungare i tempi di lievitazione di una ricetta che non lo prevede (in questo caso la sosta non sarà lunghissima) oppure fare lunghe lievitazioni (o meglio fermentazioni) e nel file abbiamo un sacco di ricette. </p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>Sostituire il lievito con PM</h2> <div data-role="collapsible"><h4>Come sostituisco il Lievito di birra con PM?</h4><p> Nella sezione Altro trovi un comodo convertitore automatico. Indicativamente il rapporto LdB:PM è di 1:10, tuttavia anche i quantitativi di farina e acqua vanno ricalibrati. </p></div>
|
||||
<div data-role="collapsible"><h4>Come sostituisco Pm solida con Licoli?</h4><p> Da solida a liquida: (quantità di PMsolida :3) x2, il risultato corrisponde al Licoli da usare in ricetta. La differenza tra la quantità di Pm e Licoli sarà da aggiungere in farina. (esempio: PM 150g :3= 50g x2= 100g di licoli da usare in ricetta; 150-100=50g di farina da aggiungere alla ricetta) </p></div>
|
||||
<div data-role="collapsible"><h4>Come sostituisco Licoli con Pm solida?</h4><p> Da liquida a solida: (quantità di Licoli :2) x3, il risultato corrisponde alla PM da usare in ricetta. La differenza tra la quantità di Licoli e Pm sarà da togliere in farina. (esempio: Licoli 100g :2= 50g x3= 150g di PM da usare in ricetta; 150-100=50g di farina da togliere alla ricetta) </p></div>
|
||||
<div data-role="collapsible"><h4>come sostituisco il lievito per dolci? o il lievito istantaneo?</h4><p> La pm non sostituisce il lievito chimico (paneangeli, bertolini....). I dolci che usano lievito chimico prevedono una lievitazione istantanea in cottura. I dolci lievitati con PM invece lievitano prima della cottura. </p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>Conservare i prodotti con PM</h2> <div data-role="collapsible"><h4>Vorrei fare un impasto, ma usarlo successivamente Posso congelare? Quando è meglio farlo?</h4><p> Si può congelare un impasto dopo la messa in forma e prima della lievitazione finale; in tal caso si mette poi fuori freezer la sera e si cuoce al mattino affinchè l'impasto scongeli e lieviti. Oppure si può congelare dopo la cottura, in questo caso è consigliabile sostituire 50 g di farina con un amido (farina di riso, maizena, fecola...) </p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>Ingredienti particolari</h2> <div data-role="collapsible"><h4>Dove si trova il malto? E con cosa sostituirlo?</h4><p> Il malto (vedi file apposito <a href="https://www.facebook.com/notes/gruppo-la-pasta-madre/malto/733786720041940">qui</a>) si trova nei negozio di alimentazione naturale e biologica e può essere sostituito da miele o zucchero anche se non è proprio la medesima cosa. </p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>Impastatrici</h2> <div data-role="collapsible"><h4>E' possibile panificare senza impastatrice?</h4><p> Assolutamente sì, anche se per alcune ricette, in particolare i grandi lievitati è vivamente consigliata. </p></div>
|
||||
<div data-role="collapsible"><h4>Che impastatrice compro? cosa devo valutare?</h4><p> Il budget: ci sono in commercio impastarici di ogni prezzo. La capienza della ciotola, in una ciotola da 4,6 litri potrai impastare circa 1,5/2 kg di farina; Il tipo di motore: le impastatrici più diffuse hanno motore indiretto, saranno necessari circa 1000W per avere una buona macchina; alcune impastatrici hanno motore in testa a presa diretta, in tal caso sarà sufficiente meno potenza. </p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>Glossario</h2> <div data-role="collapsible"><h4>Non capisco i termini usati nelle ricette</h4><p><b>Autolisi o idrolisi:</b> processo in cui si mescolano grossolanamente acqua e farina prima dell'impasto, favorisce la formazione di alveoli nel prodotto finale.<br><br>
|
||||
<b>Bagnetto:</b> immersione del lievito in una soluzione di acqua e zucchero (o acqua e bicarbonato)<br><br>
|
||||
<b>Biga:</b> è un preimpasto ottenuto miscelando acqua, farina e lievito in proporzioni tali che risulti piuttosto asciutto; alle volte può essere inteso anche come pasta madre (solida) rinfrescata, ad esempio nel libro di Annalisa De Luca<br><br>
|
||||
<b>Buratto:</b> è un setaccio e per estensione un tipo di farina di frumento setacciata appunto nel Buratto<br><br>
|
||||
<b>Burro a Pomata:</b> burro morbido, consistenza di una pomata/dentifricio/cremoso<br><br>
|
||||
<b>Campana (lievitazione a):</b> far lievitare l'impasto sul piano di lavoro con ciotola rovesciata sopra a mo' di copertura<br><br>
|
||||
<b>Esubero:</b> lievito madre non rinfescato e che avanza dopo la scorta standard e il rinfresco (vedere anche PM. Il Mantenimento (Rinfresco, fermentazione, collasso...) -> L'esubero di pasta madre)<br><br>
|
||||
<b>Olio EVO:</b> Extra Vergine Oil (olio extravergine di Oliva)<br><br>
|
||||
<b>Cottura a fessura:</b> cottura con un oggetto - cucchiaio, mestolo piatto- che impedisca allo sportello del forno di chiudersi perfettamente (serve a far uscire l'umidità)<br><br>
|
||||
<b>Forno STATICO/VENTILATO:</b> il forno con la ventola spenta/accesa<br><br>
|
||||
<b>Folding:</b> pieghe<br><br>
|
||||
<b>Gommasio:</b> sesamo e sale integrale<br><br>
|
||||
<b>Idrolisi:</b> vedi autolisi<br><br>
|
||||
<b>Incordatura:</b> un impasto è incordato quando appare elastico e non appiccicoso; nella planetaria si riconosce perchè si ""arrampica sul gancio"" staccandosi perfettamente dalle pareti.<br><br>
|
||||
<b>LiCoLi:</b> acronimo di LievitoColturaLiquida e sinonimo di pasta madre liquida e rappresenta un lievito idratato al 100%<br><br>
|
||||
<b>Lievito compresso:</b> il lievito birra fresco a cubetti.<br><br>
|
||||
<b>Leccarda:</b> teglia da forno<br><br>
|
||||
<b>LdB:</b> lievito di Birra<br><br>
|
||||
<b>Maglia glutinica:</b> si intende il legame tra le proteine presenti nella farina di grano (il ""glutine"") che si costituisce in seguito alle sollecitazioni meccaniche proprie di una impastatura energica e prolungata. (da Pastamadre.altervista.org)<br><br>
|
||||
<b>Netiquette:</b> l'insieme delle regole di un gruppo, una lista o un forum internet, per le nostre vedi<br><br>
|
||||
<b>OT:</b> off topic, termine usato nelle discussioni internet per indicare i fuori tema<br><br>
|
||||
<b>Pieghe:</b> sono un modo per favorire la lievitazione dell'impasto del nostro pane in quanto fanno in modo che l'impasto inglobi aria e si riempia di quelle bolle che dopo la cottura si traducono negli alveoli della fetta, in secondo luogo servono pure per dare all'impasto una forma determinata; Vedi <a href="http://www.facebook.com/notes/la-pasta-madre/pieghe-e-forme-di-pane/183861355052098">qui</a> per dettagli<br><br>
|
||||
<b>Pirlatura:</b> processo tramite il quale si ""Muove"" l'impasto per fargli incamerare aria donandogli una forma arrotondata.<br><br>
|
||||
<b>PM:</b> pasta madre<br><br>
|
||||
<b>PML:</b> pasta madre liquida. Indica una pasta madre con alta idratazione. Tra le più comuni vi sono la PML al 100% (es: 100g PM, 100 gr farina e 100 gr acqua) e PML al 130% (es.100g PM, 100 gr farina e 130 gr. acqua)<br><br>
|
||||
<b>PMS:</b> pasta madre solida. Indica una pasta madre con idratazione medio-bassa. La più comune è la PMS al 50% (100 gr farina e 50 gr acqua).<br><br>
|
||||
<b>Planetaria:</b> impastatrice con movimento planetario (le comuni impastatrici domestiche che impastano con un gancio che gira su se stesso e attorno alla ciotola)<br><br>
|
||||
<b>Poolish:</b> è un lievito liquido ad idratazione altissima,in proporzione di 1:1 acqua e farina non necessariamente di lievito madre (nasce con il LdB) Nella pasta madre il poolish si fa rinfrescando in modo ravvicinato con acqua e farina 1:1 per 2 volte<br><br>
|
||||
<b>Prefermento:</b> Termine in uso nel gruppo per indicare un preimpasto con acqua, farina e lievito. Simile a una biga, un poolish o un lievitino.<br><br>
|
||||
<b>Puntatura:</b> Tempo di riposo dell'impasto appena impastato.<br><br>
|
||||
<b>Scarpatura:</b> incisione praticata alla sommità del panettone con la funzione di facilitare lo sviluppo verticale dell'impasto.<br><br>
|
||||
<b>TA:</b> temperatura ambiente<br><br>
|
||||
<b>Tarocco:</b> spatola di metallo (o plastica) per staccare l'impasto dalla spianatoia<br><br>
|
||||
<b>Water roux:</b> tecnica orientale di gelatinizzazione degli amidi. permette di ottenere lievitati dolci o salati morbidi e leggeri,con alveoli fitti, che durano più a lungo senza aggiunta di conservanti ma usando uno starter fatto con 1 dose di farina e 5 dosi d'acqua, portandoli alla temperatura di 65°C e poi raffreddati prima di incorporarli all'impasto.</p></div></li>
|
||||
<li data-role="collapsible" data-iconpos="left" data-inset="false"><h2>Condividere Ricette</h2> <div data-role="collapsible"><h4>Ho una ricetta con la Pasta Madre come posso inserirla nel Lievitario?</h4><p> Compila il Form al <a href="https://docs.google.com/forms/d/13uc0n9FIUNoraGErx-mBmqDKRMpOg3Lw_NvHEZXqbUA/viewform">Link</a></p></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,47 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/home/homeViewTemplate.html', 'modules/base/baseView', 'classes/profile'],
|
||||
function($, _, Backbone, homeViewTemplate, BaseView, Profile){
|
||||
|
||||
var HomeView = BaseView.extend({
|
||||
|
||||
//initialize template
|
||||
template:_.template(homeViewTemplate),
|
||||
|
||||
initialize: function () {
|
||||
HomeView.__super__.initialize.call(this);
|
||||
//this.header.title = "pippo";
|
||||
},
|
||||
|
||||
events: {
|
||||
"click #goFbGroup": "goFbGroup"
|
||||
},
|
||||
|
||||
goFbGroup: function(){
|
||||
window.localStorage.setItem("goFbGroup", 1);
|
||||
window.location.href = "https://www.facebook.com/groups/732844273469518/";
|
||||
},
|
||||
|
||||
onShowed: function()
|
||||
{
|
||||
if(window.localStorage.getItem("goFbGroup") !== "1")
|
||||
this.$el.find("#nuovoGruppo").popup("open");
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
HomeView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template({ profile: Profile}));
|
||||
this.$el.append(this.footer.$el);
|
||||
this.$el.find("#homeBtn").addClass("ui-btn-active");
|
||||
|
||||
//$("#homeBtn").addClass("ui-btn-active");
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return HomeView;
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
<div data-role="content">
|
||||
<div style="text-align: center;">
|
||||
<% if(profile.data.name){ %>
|
||||
<h2 id="benvenuto">Bentornat<% if(profile.data.gender=="male"){%>o<%}else{%>a<%}%>
|
||||
<br><%=profile.data.name %></h2>
|
||||
<% } %>
|
||||
<img id="sfondo" src="https://dl.dropboxusercontent.com/s/6qrdp9mbi1rb92k/sfondo.png">
|
||||
</div>
|
||||
</div>
|
||||
<div data-role="popup" id="nuovoGruppo" data-history="false" data-dismissible="false">
|
||||
<div data-role="header"><h1>IMPORTANTE</h1></div>
|
||||
<div role="main" class="ui-content">
|
||||
<p style="text-align: center;font-style: italic;">
|
||||
<img src="https://dl.dropboxusercontent.com/s/xnbrbbe7eejkfv2/festa.png"><br><br>
|
||||
Le admin <br><br><b>Alessia, Elena e Francesca</b><br><br>hanno RIFONDATO IL GRUPPO!!<br>
|
||||
<br>"<b>Gruppo La Pasta Madre</b>"<br>
|
||||
<br>vuoi chiedere di diventare membro?
|
||||
</p>
|
||||
<p style="text-align: center;">
|
||||
<a id="goFbGroup" href="#" class="ui-btn ui-corner-all ui-shadow ui-btn-inline ui-btn-b" data-rel="back">Si</a>
|
||||
<a href="#" class="ui-btn ui-corner-all ui-shadow ui-btn-inline ui-btn-b" data-rel="back" data-transition="flow">No</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,38 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/index/indexViewTemplate.html', 'modules/base/baseView'],
|
||||
function($, _, Backbone, indexViewTemplate, BaseView){
|
||||
|
||||
var IndexView = BaseView.extend({
|
||||
|
||||
collection: null,
|
||||
//initialize template
|
||||
template:_.template(indexViewTemplate),
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
IndexView.__super__.initialize.call(this);
|
||||
this.collection = options.collection;
|
||||
this.collection.fetch({
|
||||
success: function(data, textStatus, jqXHR){
|
||||
self.render();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
IndexView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template({data:this.collection.toJSON()}));
|
||||
this.$el.append(this.footer.$el);
|
||||
this.trigger("renderCompleted:Categories",this);
|
||||
//return to enable chained calls
|
||||
this.$el.find("#indexBtn").addClass("ui-btn-active");
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return IndexView;
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<div id="categoryListContent" data-role="content">
|
||||
<h1>Indice Ricette</h1>
|
||||
<ul id="categoryList" data-role="listview" data-inset="true">
|
||||
<% for (var i = 0; i < data.length; i++) { %>
|
||||
<% var item = data[i]; %>
|
||||
<li><a href="#category/<%=item.name%>/<%= item.category_id%>" class="ui-btn ui-btn-icon-right ui-icon-carat-r"><%= item.name %></a></li>
|
||||
<% } %>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,129 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/item/itemViewTemplate.html', 'modules/base/baseView', 'classes/profile'],
|
||||
function($, _, Backbone, itemViewTemplate, BaseView, Profile){
|
||||
|
||||
var ItemView = BaseView.extend({
|
||||
|
||||
collRicetta: null,
|
||||
collIngredienti: null,
|
||||
|
||||
fetchedRicetta: false,
|
||||
fetchedIngredienti: false,
|
||||
//initialize template
|
||||
template:_.template(itemViewTemplate),
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
ItemView.__super__.initialize.call(this);
|
||||
this.collRicetta = options.collRicetta;
|
||||
this.collIngredienti = options.collIngredienti;
|
||||
|
||||
this.collRicetta.fetch({success: function() {
|
||||
self.fetchedRicetta = true;
|
||||
self.render();
|
||||
}});
|
||||
this.collIngredienti.fetch({success: function() {
|
||||
self.fetchedIngredienti = true;
|
||||
self.render();
|
||||
}});
|
||||
},
|
||||
|
||||
events: {
|
||||
"click #favoriteBtn": "favBtn",
|
||||
"click #backBtn": "backBtn"
|
||||
},
|
||||
|
||||
backBtn:function(e){
|
||||
e.preventDefault();
|
||||
window.history.back();
|
||||
},
|
||||
|
||||
favBtn:function(e){
|
||||
e.preventDefault();
|
||||
var self = this;
|
||||
var ric = this.collRicetta.toJSON()[0];
|
||||
|
||||
if(!Profile.isConnected())
|
||||
{
|
||||
self.$el.find('#popupDialog').popup("open");
|
||||
return;
|
||||
}
|
||||
|
||||
Profile.addRicettaBloccoNote(ric.ricetta_id,
|
||||
function(msg) {
|
||||
var favBtn = self.$el.find('#favoriteBtn');
|
||||
favBtn.addClass('ui-disabled');
|
||||
}
|
||||
);
|
||||
},
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
if(this.fetchedIngredienti && this.fetchedRicetta )
|
||||
{
|
||||
ItemView.__super__.render.call(this);
|
||||
var self = this;
|
||||
|
||||
var ric = self.collRicetta.toJSON()[0];
|
||||
|
||||
Profile.existRicettaBloccoNote(ric.ricetta_id,
|
||||
function(exist) {
|
||||
self.$el.append(self.template({
|
||||
ricetta: self.collRicetta.toJSON()[0],
|
||||
ingredienti: self.collIngredienti.toJSON()
|
||||
}));
|
||||
|
||||
self.$arrayContent = self.$el.find('div[data-role="content"]');
|
||||
self.$arrayNavBar = self.$el.find('div[data-role="navbar"] a');
|
||||
|
||||
var favBtn = self.$el.find('#favoriteBtn');
|
||||
if(exist > 0)
|
||||
favBtn.addClass('ui-disabled');
|
||||
|
||||
self.$arrayNavBar.on("click", function(e){
|
||||
e.preventDefault();
|
||||
var index = jQuery.inArray( this , self.$arrayNavBar);
|
||||
self.goToContent(index);
|
||||
});
|
||||
|
||||
self.$arrayContent.on("swipeleft", function(e) {
|
||||
var index = jQuery.inArray(this, self.$arrayContent);
|
||||
self.goToContent(index + 1 );
|
||||
});
|
||||
self.$arrayContent.on("swiperight", function(e) {
|
||||
var index = jQuery.inArray(this, self.$arrayContent);
|
||||
self.goToContent(index - 1 );
|
||||
});
|
||||
self.trigger("renderCompleted:Item",self);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
},
|
||||
|
||||
goToContent:function(newIndex)
|
||||
{
|
||||
if(this.$arrayContent.length > newIndex && newIndex >= 0)
|
||||
{
|
||||
this.indexContent = newIndex;
|
||||
this.switchContent();
|
||||
}
|
||||
},
|
||||
|
||||
switchContent: function(){
|
||||
this.$arrayContent.hide();
|
||||
this.$arrayNavBar.removeClass('ui-btn-active');
|
||||
this.$arrayNavBar.removeClass('ui-state-persist');
|
||||
$(this.$arrayContent[this.indexContent]).show();
|
||||
$(this.$arrayNavBar[this.indexContent]).addClass('ui-btn-active');
|
||||
$(this.$arrayNavBar[this.indexContent]).addClass('ui-state-persist');
|
||||
}
|
||||
});
|
||||
return ItemView;
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
<div data-role="header" data-position="fixed" data-tap-toggle="false">
|
||||
<a id="favoriteBtn" href="" data-role="button" class="ui-btn-left" data-icon="custom" style="font-size: x-small;">Agg. al Blocco</a>
|
||||
<h3 id='titoloRicetta'><%= unescape(ricetta.titolo)%></h3>
|
||||
<a id="backBtn" href="" data-role="button" class="ui-btn-right" data-icon="custom">Indietro</a>
|
||||
</div>
|
||||
<div id="contentIngredienti" data-role="content">
|
||||
<h1>Ingredienti</h1>
|
||||
<center><p id='ingredienti'>
|
||||
<% _.each(ingredienti, function(ingrediente) {
|
||||
var liStyle = "";
|
||||
var qty = ": " + ingrediente.quantita;
|
||||
var nome_ingr = ingrediente.nome_ingrediente;
|
||||
if(ingrediente.id_tipo_ingredienti == 22)
|
||||
{
|
||||
liStyle="list-style-type: none;";
|
||||
qty = "";
|
||||
nome_ingr = "";
|
||||
} %> <li style="<%= liStyle %>"><b><%= nome_ingr %></b><%= qty %> <%= ingrediente.unita %> <%= ingrediente.note %></li><br> <% }); %>
|
||||
</p></center>
|
||||
</div>
|
||||
<div id="contentProcedimento" data-role="content" style="display: none;">
|
||||
<h1>Procedimento</h1>
|
||||
<p id='procedimento'><%= ricetta.procedimento%></p>
|
||||
</div>
|
||||
<!--<div id="contentFoto" data-role="content" data-theme="d" style="display: none;" data-iscroll>
|
||||
<h1>Foto</h1>
|
||||
<ul id="Gallery" class="gallery">
|
||||
</ul>
|
||||
</div>
|
||||
<div id="contentVideo" data-role="content" data-theme="d" style="display: none;" data-iscroll>
|
||||
<h1>Video</h1>
|
||||
<p id='video'></p>
|
||||
</div>-->
|
||||
<div data-role="footer" data-position="fixed" data-tap-toggle="false">
|
||||
<div data-role="navbar">
|
||||
<ul>
|
||||
<li><a href="" class="ui-btn-active ui-state-persist">Ingredienti</a></li>
|
||||
<li><a href="">Procedimento</a></li>
|
||||
<!--<li><a href="">Foto</a></li>
|
||||
<li><a href="">Video</a></li>-->
|
||||
</ul>
|
||||
</div><!-- /navbar -->
|
||||
<% if(ricetta.autore.length > 0){ %>
|
||||
<h1 id="autore" style="padding: 0px;">Autore: <%= unescape(ricetta.autore)%></h1>
|
||||
<% }if(ricetta.link_fonte.length > 0){ %>
|
||||
<h1 id="linkFonte" style="padding: 0px;"><a target="_blank" href="<%= ricetta.link_fonte%>">Link Fonte</a></h1>
|
||||
<% }%>
|
||||
</div>
|
||||
<div data-role="popup" id="popupDialog">
|
||||
<div data-role="header">
|
||||
<h1>Informazione</h1>
|
||||
</div>
|
||||
<div role="main" class="ui-content">
|
||||
<p style="text-align: center;font-style: italic;">IMPORTANTE<br><br>
|
||||
Questa funzionalità è disponibile solo se si è abilitata la Sincronizzazione tramite Facebook o Google.
|
||||
</p>
|
||||
<p style="text-align: center;">
|
||||
<a id="syncBtn" href="#syncView" class="ui-btn ui-corner-all ui-btn-inline ui-shadow ui-icon-custom ui-btn-icon-left">Sincronizza</a>
|
||||
<a href="" class="ui-btn ui-corner-all ui-shadow ui-btn-inline ui-icon-check" data-rel="back">Cancel</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/more/moreViewTemplate.html', 'modules/base/baseView'],
|
||||
function($, _, Backbone, moreViewTemplate, BaseView){
|
||||
|
||||
var MoreView = BaseView.extend({
|
||||
|
||||
collection: null,
|
||||
//initialize template
|
||||
template:_.template(moreViewTemplate),
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
MoreView.__super__.initialize.call(this);
|
||||
//this.header.title = "pippo";
|
||||
},
|
||||
|
||||
events:{
|
||||
"click #converterLnk": "converterLnkClick"
|
||||
},
|
||||
|
||||
converterLnkClick:function()
|
||||
{
|
||||
window.location.href = "http://www.pastamadre.eu/webapps/conversione_lieviti/index.php";
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
MoreView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template());
|
||||
this.$el.append(this.footer.$el);
|
||||
|
||||
this.$el.find("#moreBtn").addClass("ui-btn-active");
|
||||
//$("#homeBtn").addClass("ui-btn-active");
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return MoreView;
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<div data-role="content">
|
||||
<ul data-role="listview" data-inset="true">
|
||||
<li data-role="list-divider">Altre opzioni</li>
|
||||
<li><a id="converterLnk" href="#"><img src="Resources/img/converter.png" alt="Convertitore" class="ui-li-icon ui-corner-none">Convertitore</a></li>
|
||||
|
||||
<li><a href="#settingsView"><img src="Resources/img/settings.png" alt="Impostazioni" class="ui-li-icon ui-corner-none">Impostazioni</a></li>
|
||||
|
||||
<li><a href="#aboutView"><img src="Resources/img/info.png" alt="Informazioni su..." class="ui-li-icon ui-corner-none">Informazioni su...</a></li>
|
||||
<li><a href="#donationView"><img src="Resources/img/donation.png" alt="Donazione" class="ui-li-icon ui-corner-none">Donazione</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,82 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/note/noteViewTemplate.html', 'text!modules/note/noteItemTemplate.html', 'modules/base/baseView', 'classes/profile'],
|
||||
function($, _, Backbone, noteViewTemplate, noteItemTemplate, BaseView, Profile){
|
||||
|
||||
var NoteView = BaseView.extend({
|
||||
|
||||
collection: null,
|
||||
//initialize template
|
||||
template:_.template(noteViewTemplate),
|
||||
itemtemplate:_.template(noteItemTemplate),
|
||||
current_ricetta_id: null,
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
NoteView.__super__.initialize.call(this);
|
||||
this.collection = options.collection;
|
||||
this.collection.fetch({ success: function(){ self.renderItem(); } });
|
||||
},
|
||||
|
||||
events: {
|
||||
"click #deleteItem": "deleteItemClick",
|
||||
"popupafterclose #popupMenu": "popupMenuPopupafterclose"
|
||||
},
|
||||
|
||||
updateList: function(){
|
||||
var $ul = this.$el.find('#allNote');
|
||||
|
||||
var items = this.itemtemplate({data:this.collection.toJSON()});
|
||||
|
||||
$ul.html( items );
|
||||
$ul.listview( "refresh" );
|
||||
$ul.trigger( "updatelayout");
|
||||
},
|
||||
|
||||
renderItem: function(){
|
||||
this.updateList();
|
||||
|
||||
$.mobile.loading( 'hide' );
|
||||
var self = this;
|
||||
this.$el.find('.optionLink').on("click", function(e){
|
||||
e.preventDefault();
|
||||
self.current_ricetta_id = $(e.target.parentElement).find('#itemID').text();
|
||||
self.$el.find('#popupMenu').popup("open");
|
||||
});
|
||||
},
|
||||
|
||||
deleteItemClick: function(e){
|
||||
e.preventDefault();
|
||||
var self = this;
|
||||
Profile.removeRicettaBloccoNote(this.current_ricetta_id, function(msg) {
|
||||
var item = self.collection.get(self.current_ricetta_id);
|
||||
|
||||
self.$el.find('#popupMenu').popup("close");
|
||||
|
||||
self.collection.remove(item);
|
||||
self.updateList();
|
||||
});
|
||||
},
|
||||
|
||||
popupMenuPopupafterclose: function( event, ui ) {
|
||||
this.current_ricetta_id = null;
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
NoteView.__super__.render.call(this);
|
||||
|
||||
var self = this;
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template());
|
||||
this.$el.append(this.footer.$el);
|
||||
|
||||
//return to enable chained calls
|
||||
this.$el.find("#noteBtn").addClass("ui-btn-active");
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return NoteView;
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
<% if(data.length == 0){ %>
|
||||
<h1>Nessuna ricetta trovata</h1>
|
||||
<%} else { for (var i = 0; i < data.length; i++) { %>
|
||||
<% var item = data[i]; %>
|
||||
<li>
|
||||
<a href="#ricetta/<%= item.ricetta_id%>">
|
||||
<div id="itemID" style="display: none;"><%= item.ricetta_id%></div>
|
||||
<div class='ricettaTitolo'><%= unescape(item.titolo) %></div>
|
||||
<div class='ricettaAutore'><%= unescape(item.autore) %></div>
|
||||
</a>
|
||||
<a href="" class="optionLink" data-rel="popup" data-position-to="window" data-transition="pop">Opzioni</a>
|
||||
</li>
|
||||
<% }} %>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div id="noteListContent" data-role="content">
|
||||
<h1>Blocco note</h1>
|
||||
<ul id="allNote" data-role="listview" data-inset="true" data-split-icon="gear">
|
||||
</ul>
|
||||
<div data-role="popup" id="popupMenu" data-theme="b">
|
||||
<ul data-role="listview" data-inset="true" style="min-width:210px;">
|
||||
<li data-role="list-divider">Scegliere l'azione</li>
|
||||
<li><a href="" id="deleteItem">Elimina dal Blocco</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,48 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/search/foundViewTemplate.html','text!modules/search/foundItemTemplate.html', 'modules/base/baseView'],
|
||||
function($, _, Backbone, foundViewTemplate, foundItemTemplate, BaseView){
|
||||
|
||||
var FoundView = BaseView.extend({
|
||||
|
||||
collection: null,
|
||||
//initialize template
|
||||
template:_.template(foundViewTemplate),
|
||||
itemTemplate:_.template(foundItemTemplate),
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
FoundView.__super__.initialize.call(this);
|
||||
this.collection = options.collection;
|
||||
this.collection.fetch({
|
||||
success: function(){ self.renderItem(); } });
|
||||
},
|
||||
|
||||
renderItem: function(){
|
||||
var $ul = $('#foundRicette');
|
||||
|
||||
var items = this.itemTemplate({data:this.collection.toJSON()});
|
||||
|
||||
$ul.html( items );
|
||||
$ul.listview( "refresh" );
|
||||
$ul.trigger( "updatelayout");
|
||||
|
||||
$.mobile.loading( 'hide' );
|
||||
//$( '[data-alpha="true"]' ).alphascroll();
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
//this.header.title = "pippo";
|
||||
FoundView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template());
|
||||
this.$el.append(this.footer.$el);
|
||||
//return to enable chained calls
|
||||
this.$el.find("#searchBtn").addClass("ui-btn-active");
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return FoundView;
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
<% if(data.length == 0){ %>
|
||||
<h1>Nessuna ricetta trovata</h1>
|
||||
<%} else { for (var i = 0; i < data.length; i++) { %>
|
||||
<% var item = data[i]; %>
|
||||
<li><a href="#ricetta/<%= item.ricetta_id%>" class="ui-btn ui-btn-icon-right ui-icon-carat-r">
|
||||
<div class='ricettaTitolo'><%= unescape(item.titolo) %> - <%= unescape(item.categoria_name) %></div><div class='ricettaAutore'><%= unescape(item.autore) %></div>
|
||||
</a></li>
|
||||
<% }} %>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div id="categoryListContent" data-role="content">
|
||||
<h1>Ricerca Ricette...</h1>
|
||||
<ul id="foundRicette" data-role="listview" data-autodividers="true" data-inset="true">
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,57 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/search/searchViewTemplate.html', 'modules/base/baseView', 'classes/profile', 'jQueryPlugins'],
|
||||
function($, _, Backbone, searchViewTemplate, BaseView, Profile) {
|
||||
var SearchView = BaseView.extend({
|
||||
collection: null,
|
||||
//initialize template
|
||||
template:_.template(searchViewTemplate),
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
SearchView.__super__.initialize.call(this);
|
||||
this.collection = options.collection;
|
||||
this.collection.fetch({ success: function () { self.render(); } });
|
||||
//this.header.title = "pippo";
|
||||
},
|
||||
|
||||
events: {
|
||||
"click [button='true']": "performSearch"
|
||||
},
|
||||
|
||||
performSearch: function (e) {
|
||||
e.preventDefault();
|
||||
var titolo = $('#titolo').val();
|
||||
var categoria = $('#categoria').val();
|
||||
var nResult = $('#nResult').val();
|
||||
var diffi = $('#difficoltaFrm').serialize();
|
||||
diffi = diffi.replace("difficolta=", "");
|
||||
if (diffi === "") {
|
||||
diffi = "0";
|
||||
}
|
||||
Backbone.history.navigate('search/' + nResult + "/"+ categoria + "/" + diffi + "/" + titolo, { trigger: true });
|
||||
},
|
||||
//render the content into div of view
|
||||
render: function () {
|
||||
//this.header.title = "pippo";
|
||||
SearchView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template({data:this.collection.toJSON()}));
|
||||
this.$el.append(this.footer.$el);
|
||||
|
||||
this.$el.find('#nResult').val(Profile.data.risRic);
|
||||
// this.$el.find('#search').on("click", function(e){
|
||||
// e.preventDefault();
|
||||
//
|
||||
// });
|
||||
this.trigger("renderCompleted:Search", this);
|
||||
|
||||
this.$el.find("#searchBtn").addClass("ui-btn-active");
|
||||
//$("#homeBtn").addClass("ui-btn-active");
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return SearchView;
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
<div data-role="content">
|
||||
<h1>Ricerca ricetta</h1>
|
||||
<label for="titolo">Titolo:</label>
|
||||
<input type="text" name="titolo" id="titolo" placeholder="Titolo..." value="" data-clear-btn="true" ><br>
|
||||
<label for="categoria">Categoria:</label>
|
||||
<select name="categoria" id="categoria" data-native-menu="true" >
|
||||
<option value="0" selected="true">Selezionare Categoria...</option>
|
||||
<% for (var i = 0; i < data.length; i++) { %>
|
||||
<% var item = data[i]; %>
|
||||
<option value="<%=item.category_id%>"><%=item.name%></option>
|
||||
<% } %>
|
||||
</select><br>
|
||||
<label for="difficoltaFrm">Livello Difficoltà:</label>
|
||||
<form id="difficoltaFrm" data-role="none">
|
||||
<input name="difficolta" type="radio" data-role="none" value="1" title="Molto Semplice" class="star"/>
|
||||
<input name="difficolta" type="radio" data-role="none" value="2" title="Semplice" class="star"/>
|
||||
<input name="difficolta" type="radio" data-role="none" value="3" title="Normale" class="star"/>
|
||||
<input name="difficolta" type="radio" data-role="none" value="4" title="Difficile" class="star"/>
|
||||
<input name="difficolta" type="radio" data-role="none" value="5" title="Molto Difficile" class="star"/>
|
||||
<span id="hover-test" style="margin:0 0 0 20px;">Nessuna</span></form><br>
|
||||
<label for="nResult">Numero Risultati:</label>
|
||||
<select name="nResult" id="nResult" >
|
||||
<option value="10" selected="true">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="30">30</option>
|
||||
</select>
|
||||
<br><br>
|
||||
<center><a href="" id="search" button="true" class="ui-btn ui-corner-all">Cerca</a></center>
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/settings/settingsViewTemplate.html', 'modules/base/baseView', 'classes/profile'],
|
||||
function($, _, Backbone, settingsViewTemplate, BaseView, Profile){
|
||||
|
||||
var SettingsView = BaseView.extend({
|
||||
|
||||
//initialize template
|
||||
template:_.template(settingsViewTemplate),
|
||||
|
||||
initialize: function () {
|
||||
SettingsView.__super__.initialize.call(this);
|
||||
},
|
||||
|
||||
events: {
|
||||
"click #saveBtn": "saveBtn"
|
||||
},
|
||||
|
||||
saveBtn:function(e){
|
||||
e.preventDefault();
|
||||
Profile.data.risRic = this.$el.find('#nResult').val();
|
||||
Profile.data.tema = this.$el.find('#theme').val();
|
||||
Profile.updateProfile(function(){
|
||||
Backbone.history.loadUrl();
|
||||
});
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
SettingsView.__super__.render.call(this);
|
||||
//this.el is the root element of Backbone.View. By default, it is a div.
|
||||
//$el is cached jQuery object for the view's element.
|
||||
//append the compiled template into view div container
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template());
|
||||
this.$el.append(this.footer.$el);
|
||||
|
||||
this.$el.find('#nResult').val(Profile.data.risRic);
|
||||
this.$el.find('#theme').val(Profile.data.tema);
|
||||
|
||||
this.$el.find("#moreBtn").addClass("ui-btn-active");
|
||||
//$("#homeBtn").addClass("ui-btn-active");
|
||||
//return to enable chained calls
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return SettingsView;
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
<div data-role="content">
|
||||
<h1>Impostazioni</h1>
|
||||
<div>
|
||||
<label for="nResult">Numero Risultati Ricerca:</label>
|
||||
<select name="nResult" id="nResult">
|
||||
<option value="10" selected="true">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="30">30</option>
|
||||
</select>
|
||||
<label for="theme">Tema Grafico:</label>
|
||||
<select name="theme" id="theme">
|
||||
<option value="a">Blu</option>
|
||||
<option value="b" selected="true">Nero</option>
|
||||
<option value="c" selected="true">Chiaro</option>
|
||||
</select>
|
||||
<a id="saveBtn" href="" button="true" class="ui-link ui-btn ui-icon-custom ui-btn-icon-left">Save</a>
|
||||
<br><br>
|
||||
Impostazione di sincronizzazione
|
||||
<a id="syncBtn" href="#syncView" button="true" class="ui-link ui-btn ui-icon-custom ui-btn-icon-left">Sincronizzazione</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,164 @@
|
||||
define(['jquery', 'underscore', 'backbone','text!modules/sync/syncViewTemplate.html', 'modules/base/baseView', 'classes/profile'],
|
||||
function($, _, Backbone, syncViewTemplate, BaseView, Profile){
|
||||
|
||||
var SyncView = BaseView.extend({
|
||||
|
||||
//initialize template
|
||||
template:_.template(syncViewTemplate),
|
||||
|
||||
initialize: function (options) {
|
||||
SyncView.__super__.initialize.call(this);
|
||||
if(options &&
|
||||
options.tokenFound == 1)
|
||||
{
|
||||
if(window.localStorage.getItem("tryLogin")=="fb")
|
||||
{
|
||||
this.fbAfterLogin();
|
||||
}
|
||||
else if(window.localStorage.getItem("tryLogin")=="gplus")
|
||||
{
|
||||
this.gPlusAfterLogin();
|
||||
}
|
||||
}
|
||||
window.localStorage.setItem("tryLogin", null);
|
||||
},
|
||||
|
||||
events: {
|
||||
"click #backBtn": "backBtn",
|
||||
"click #fblogin": "fbLogin",
|
||||
"click #gpluslogin": "gplusLogin",
|
||||
"click #resetBtn": "resetBtn"
|
||||
},
|
||||
|
||||
resetBtn:function(e){
|
||||
e.preventDefault();
|
||||
Profile.setKeySave(null);
|
||||
Backbone.history.loadUrl();
|
||||
},
|
||||
|
||||
backBtn:function(e){
|
||||
e.preventDefault();
|
||||
window.history.back();
|
||||
},
|
||||
|
||||
fbLogin: function(e){
|
||||
var self = this;
|
||||
e.preventDefault();
|
||||
|
||||
if(!Profile.isConnected()) {
|
||||
window.localStorage.setItem("tryLogin", "fb");
|
||||
openFB.login('email');
|
||||
}
|
||||
else if(Profile.isConnected() && Profile.isFbConnected())
|
||||
openFB.revokePermissions(function(){
|
||||
Profile.setKeySave(null);
|
||||
self.updateLoginBtn();
|
||||
});
|
||||
},
|
||||
|
||||
fbAfterLogin: function()
|
||||
{
|
||||
var self = this;
|
||||
openFB.api({
|
||||
path: '/me',
|
||||
success: function (data) {
|
||||
Profile.internalLoadProfile(data.id, function(retVal){
|
||||
if(retVal == false)
|
||||
Profile.createProfile(
|
||||
data.id,
|
||||
"fb",
|
||||
data.name,
|
||||
data.email,
|
||||
data.gender,
|
||||
function(){
|
||||
//Backbone.history.loadUrl();
|
||||
});
|
||||
self.updateLoginBtn();
|
||||
});
|
||||
}});
|
||||
},
|
||||
|
||||
gplusLogin: function(e){
|
||||
var self = this;
|
||||
e.preventDefault();
|
||||
|
||||
if(!Profile.isConnected()) {
|
||||
window.localStorage.setItem("tryLogin", "gplus");
|
||||
openGPlus.login('email');
|
||||
}
|
||||
else if(Profile.isConnected() && Profile.isGPlusConnected())
|
||||
openGPlus.revokePermissions(function(){
|
||||
Profile.setKeySave(null);
|
||||
self.updateLoginBtn();
|
||||
});
|
||||
},
|
||||
|
||||
gPlusAfterLogin: function()
|
||||
{
|
||||
var self = this;
|
||||
openGPlus.api({
|
||||
path: 'people/me',
|
||||
success: function (data) {
|
||||
Profile.internalLoadProfile(data.id, function(retVal){
|
||||
if(retVal == false)
|
||||
Profile.createProfile(
|
||||
data.id,
|
||||
"gplus",
|
||||
data.displayName,
|
||||
data.emails[0].value,
|
||||
data.gender,
|
||||
function(){
|
||||
//Backbone.history.loadUrl();
|
||||
}
|
||||
);
|
||||
self.updateLoginBtn();
|
||||
});
|
||||
}});
|
||||
},
|
||||
|
||||
updateLoginBtn: function()
|
||||
{
|
||||
if(Profile.isConnected()) {
|
||||
if (Profile.isFbConnected()) {
|
||||
this.$el.find("#fblogin").show();
|
||||
this.$el.find("#gpluslogin").hide();
|
||||
this.$el.find("#loginFbImg").removeClass("loginfb");
|
||||
this.$el.find("#loginFbImg").addClass("logoutfb");
|
||||
}
|
||||
|
||||
if (Profile.isGPlusConnected()) {
|
||||
this.$el.find("#gpluslogin").show();
|
||||
this.$el.find("#fblogin").hide();
|
||||
this.$el.find("#loginGPlusImg").removeClass("logingplus");
|
||||
this.$el.find("#loginGPlusImg").addClass("logoutgplus");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.$el.find("#loginFbImg").removeClass("logoutfb");
|
||||
this.$el.find("#loginFbImg").addClass("loginfb");
|
||||
this.$el.find("#loginGPlusImg").removeClass("logoutgplus");
|
||||
this.$el.find("#loginGPlusImg").addClass("logingplus");
|
||||
}
|
||||
},
|
||||
|
||||
//render the content into div of view
|
||||
render: function(){
|
||||
var self = this;
|
||||
//this.header.title = "pippo";
|
||||
SyncView.__super__.render.call(this);
|
||||
|
||||
this.header.$el.append("<a id=\"backBtn\" href=\"\" data-role=\"button\" class=\"ui-btn-right\" data-icon=\"custom\">Indietro</a>");
|
||||
|
||||
this.$el.append(this.header.$el);
|
||||
this.$el.append(this.template( { app: myManifest }));
|
||||
this.$el.append(this.footer.$el);
|
||||
this.$el.find("#moreBtn").addClass("ui-btn-active");
|
||||
|
||||
this.updateLoginBtn();
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
return SyncView;
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
<div data-role="content">
|
||||
<h1>Sincronizzazione Dati</h1>
|
||||
<div style="text-align: center;">
|
||||
Qui puoi collegarti con l'account che preferisci<br>per avere la sincronizzazione dei tuoi dati su qualsiasi dispositivo che userai<br>
|
||||
Scegli il tipo di account e premi il tasto qui sotto per effettuare il login<br><br>
|
||||
<a id="fblogin" href=""><img id="loginFbImg" class="loginfb"/><br></a>
|
||||
<a id="gpluslogin" href=""><img id="loginGPlusImg" class="logingplus"/></a>
|
||||
<div data-role="popup" id="popupLogin" data-overlay-theme="a" data-theme="a" data-corners="false" data-tolerance="15,15">
|
||||
<a href="#" data-rel="back" class="ui-btn ui-btn-b ui-corner-all ui-shadow ui-btn-a ui-icon-delete ui-btn-icon-notext ui-btn-right">Close</a>
|
||||
<iframe id="urlLogin" src="" width="497" height="298" seamless=""></iframe>
|
||||
</div>
|
||||
<a id="resetBtn" href="" class="ui-btn ui-corner-all ui-shadow">Reset Account</a>
|
||||
</div>
|
||||
</div>
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* OpenFB is a micro-library that lets you integrate your JavaScript application with Facebook.
|
||||
* OpenFB works for both BROWSER-BASED apps and CORDOVA/PHONEGAP apps.
|
||||
* This library has no dependency: You don't need (and shouldn't use) the Facebook SDK with this library. Whe running in
|
||||
* Cordova, you also don't need the Facebook Cordova plugin. There is also no dependency on jQuery.
|
||||
* OpenFB allows you to login to Facebook and execute any Facebook Graph API request.
|
||||
* @author Christophe Coenraets @ccoenraets
|
||||
* @version 0.3
|
||||
*/
|
||||
var openFB = (function () {
|
||||
|
||||
var FB_LOGIN_URL = 'https://www.facebook.com/dialog/oauth',
|
||||
|
||||
// By default we store fbtoken in sessionStorage. This can be overridden in init()
|
||||
tokenStore = window.sessionStorage,
|
||||
|
||||
fbAppId,
|
||||
oauthRedirectURL,
|
||||
|
||||
// Because the OAuth login spans multiple processes, we need to keep the success/error handlers as variables
|
||||
// inside the module instead of keeping them local within the login function.
|
||||
loginSuccessHandler,
|
||||
loginErrorHandler,
|
||||
|
||||
// Indicates if the app is running inside Cordova
|
||||
runningInCordova,
|
||||
|
||||
// Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function)
|
||||
loginProcessed;
|
||||
|
||||
document.addEventListener("deviceready", function () {
|
||||
runningInCordova = true;
|
||||
}, false);
|
||||
|
||||
/**
|
||||
* Initialize the OpenFB module. You must use this function and initialize the module with an appId before you can
|
||||
* use any other function.
|
||||
* @param appId - The id of the Facebook app
|
||||
* @param redirectURL - The OAuth redirect URL. Optional. If not provided, we use sensible defaults.
|
||||
* @param store - The store used to save the Facebook token. Optional. If not provided, we use sessionStorage.
|
||||
*/
|
||||
function init(appId, redirectURL, store) {
|
||||
fbAppId = appId;
|
||||
if (redirectURL) oauthRedirectURL = redirectURL;
|
||||
if (store) tokenStore = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login to Facebook using OAuth. If running in a Browser, the OAuth workflow happens in a a popup window.
|
||||
* If running in Cordova container, it happens using the In-App Browser. Don't forget to install the In-App Browser
|
||||
* plugin in your Cordova project: cordova plugins add org.apache.cordova.inappbrowser.
|
||||
* @param scope - The set of Facebook permissions requested
|
||||
* @param success - Callback function to invoke when the login process succeeds
|
||||
* @param error - Callback function to invoke when the login process fails
|
||||
* @returns {*}
|
||||
*/
|
||||
function login(scope, success, error) {
|
||||
|
||||
var loginWindow,
|
||||
startTime;
|
||||
|
||||
function loginWindowLoadStart(event) {
|
||||
var url = event.url;
|
||||
if (url.indexOf("access_token=") > 0 || url.indexOf("error=") > 0) {
|
||||
// When we get the access token fast, the login window (inappbrowser) is still opening with animation
|
||||
// in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little...
|
||||
var timeout = 600 - (new Date().getTime() - startTime);
|
||||
setTimeout(function () {
|
||||
loginWindow.close();
|
||||
}, timeout > 0 ? timeout : 0);
|
||||
oauthCallback(url);
|
||||
}
|
||||
}
|
||||
|
||||
function loginWindowExit() {
|
||||
console.log('exit and remove listeners');
|
||||
// Handle the situation where the user closes the login window manually before completing the login process
|
||||
deferredLogin.reject({error: 'user_cancelled', error_description: 'User cancelled login process', error_reason: "user_cancelled"});
|
||||
loginWindow.removeEventListener('loadstop', loginWindowLoadStart);
|
||||
loginWindow.removeEventListener('exit', loginWindowExit);
|
||||
loginWindow = null;
|
||||
console.log('done removing listeners');
|
||||
}
|
||||
|
||||
|
||||
if (!fbAppId) {
|
||||
return error({error: 'Facebook App Id not set.'});
|
||||
}
|
||||
|
||||
scope = scope || '';
|
||||
|
||||
loginSuccessHandler = success;
|
||||
loginErrorHandler = error;
|
||||
|
||||
loginProcessed = false;
|
||||
logout();
|
||||
|
||||
// Check if an explicit oauthRedirectURL has been provided in init(). If not, infer the appropriate value
|
||||
if (!oauthRedirectURL) {
|
||||
if (runningInCordova) {
|
||||
oauthRedirectURL = 'https://www.facebook.com/connect/login_success.html';
|
||||
} else {
|
||||
var origin = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');
|
||||
// could also use 'var origin = window.location.origin' when enough browsers support it
|
||||
oauthRedirectURL = origin + '/oauthcallback.html';
|
||||
}
|
||||
}
|
||||
|
||||
startTime = new Date().getTime();
|
||||
|
||||
var url = FB_LOGIN_URL + '?client_id=' + fbAppId + '&redirect_uri=' + oauthRedirectURL +
|
||||
'&response_type=token&display=popup&scope=' + scope;
|
||||
|
||||
window.location.href = url;
|
||||
//loginWindow = window.open(url, '_blank', 'location=no');
|
||||
// If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error
|
||||
if (runningInCordova) {
|
||||
loginWindow.addEventListener('loadstart', loginWindowLoadStart);
|
||||
loginWindow.addEventListener('exit', loginWindowExit);
|
||||
}
|
||||
// Note: if the app is running in the browser the loginWindow dialog will call back by invoking the
|
||||
// oauthCallback() function. See oauthcallback.html for details.
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called either by oauthcallback.html (when the app is running the browser) or by the loginWindow loadstart event
|
||||
* handler defined in the login() function (when the app is running in the Cordova/PhoneGap container).
|
||||
* @param url - The oautchRedictURL called by Facebook with the access_token in the querystring at the ned of the
|
||||
* OAuth workflow.
|
||||
*/
|
||||
function oauthCallback(url) {
|
||||
// Parse the OAuth data received from Facebook
|
||||
var queryString,
|
||||
obj;
|
||||
|
||||
loginProcessed = true;
|
||||
if (url.indexOf("access_token=") > 0) {
|
||||
queryString = url.substr(url.indexOf('#') + 1);
|
||||
obj = parseQueryString(queryString);
|
||||
tokenStore['fbtoken'] = obj['access_token'];
|
||||
if (loginSuccessHandler) loginSuccessHandler();
|
||||
} else if (url.indexOf("error=") > 0) {
|
||||
queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#'));
|
||||
obj = parseQueryString(queryString);
|
||||
if (loginErrorHandler) loginErrorHandler(obj);
|
||||
} else {
|
||||
if (loginErrorHandler) loginErrorHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Application-level logout: we simply discard the token.
|
||||
*/
|
||||
function logout() {
|
||||
tokenStore['fbtoken'] = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you make any Facebook Graph API request.
|
||||
* @param obj - Request configuration object. Can include:
|
||||
* method: HTTP method: GET, POST, etc. Optional - Default is 'GET'
|
||||
* path: path in the Facebook graph: /me, /me.friends, etc. - Required
|
||||
* params: queryString parameters as a map - Optional
|
||||
* success: callback function when operation succeeds - Optional
|
||||
* error: callback function when operation fails - Optional
|
||||
*/
|
||||
function api(obj) {
|
||||
|
||||
var method = obj.method || 'GET',
|
||||
params = obj.params || {},
|
||||
xhr = new XMLHttpRequest(),
|
||||
url;
|
||||
|
||||
params['access_token'] = tokenStore['fbtoken'];
|
||||
|
||||
url = 'https://graph.facebook.com' + obj.path + '?' + toQueryString(params);
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
if (obj.success) obj.success(JSON.parse(xhr.responseText));
|
||||
} else {
|
||||
var error = xhr.responseText ? JSON.parse(xhr.responseText).error : {message: 'An error has occurred'};
|
||||
if (obj.error) obj.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open(method, url, true);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to de-authorize the app
|
||||
* @param success
|
||||
* @param error
|
||||
* @returns {*}
|
||||
*/
|
||||
function revokePermissions(success, error) {
|
||||
return api({method: 'DELETE',
|
||||
path: '/me/permissions',
|
||||
success: function () {
|
||||
tokenStore['fbtoken'] = undefined;
|
||||
success();
|
||||
},
|
||||
error: error});
|
||||
}
|
||||
|
||||
function parseQueryString(queryString) {
|
||||
var qs = decodeURIComponent(queryString),
|
||||
obj = {},
|
||||
params = qs.split('&');
|
||||
params.forEach(function (param) {
|
||||
var splitter = param.split('=');
|
||||
obj[splitter[0]] = splitter[1];
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
function toQueryString(obj) {
|
||||
var parts = [];
|
||||
for (var i in obj) {
|
||||
if (obj.hasOwnProperty(i)) {
|
||||
parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
|
||||
}
|
||||
}
|
||||
return parts.join("&");
|
||||
}
|
||||
|
||||
// The public API
|
||||
return {
|
||||
init: init,
|
||||
login: login,
|
||||
logout: logout,
|
||||
revokePermissions: revokePermissions,
|
||||
api: api,
|
||||
oauthCallback: oauthCallback
|
||||
}
|
||||
|
||||
}());
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* openGPlus is a micro-library that lets you integrate your JavaScript application with GooglePlus.
|
||||
* openGPlus works for both BROWSER-BASED apps and CORDOVA/PHONEGAP apps.
|
||||
* This library has no dependency: You don't need (and shouldn't use) the Facebook SDK with this library. Whe running in
|
||||
* Cordova, you also don't need the Facebook Cordova plugin. There is also no dependency on jQuery.
|
||||
* openGPlus allows you to login to Facebook and execute any Facebook Graph API request.
|
||||
* @author Denis Ironi @hexstudy
|
||||
* @version 0.1
|
||||
*/
|
||||
var openGPlus = (function () {
|
||||
|
||||
var GPLUS_LOGIN_URL = 'https://accounts.google.com/o/oauth2/auth',
|
||||
|
||||
// By default we store fbtoken in sessionStorage. This can be overridden in init()
|
||||
tokenStore = window.sessionStorage,
|
||||
|
||||
clientId,
|
||||
oauthRedirectURL,
|
||||
|
||||
// Because the OAuth login spans multiple processes, we need to keep the success/error handlers as variables
|
||||
// inside the module instead of keeping them local within the login function.
|
||||
loginSuccessHandler,
|
||||
loginErrorHandler,
|
||||
|
||||
// Indicates if the app is running inside Cordova
|
||||
runningInCordova,
|
||||
|
||||
// Used in the exit event handler to identify if the login has already been processed elsewhere (in the oauthCallback function)
|
||||
loginProcessed;
|
||||
|
||||
document.addEventListener("deviceready", function () {
|
||||
runningInCordova = true;
|
||||
}, false);
|
||||
|
||||
/**
|
||||
* Initialize the openGPlus module. You must use this function and initialize the module with an appId before you can
|
||||
* use any other function.
|
||||
* @param appId - The id of the Facebook app
|
||||
* @param redirectURL - The OAuth redirect URL. Optional. If not provided, we use sensible defaults.
|
||||
* @param store - The store used to save the Facebook token. Optional. If not provided, we use sessionStorage.
|
||||
*/
|
||||
function init(appId, redirectURL, store) {
|
||||
clientId = appId;
|
||||
if (redirectURL) oauthRedirectURL = redirectURL;
|
||||
if (store) tokenStore = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login to Facebook using OAuth. If running in a Browser, the OAuth workflow happens in a a popup window.
|
||||
* If running in Cordova container, it happens using the In-App Browser. Don't forget to install the In-App Browser
|
||||
* plugin in your Cordova project: cordova plugins add org.apache.cordova.inappbrowser.
|
||||
* @param scope - The set of Facebook permissions requested
|
||||
* @param success - Callback function to invoke when the login process succeeds
|
||||
* @param error - Callback function to invoke when the login process fails
|
||||
* @returns {*}
|
||||
*/
|
||||
function login(scope, success, error) {
|
||||
|
||||
var loginWindow,
|
||||
startTime;
|
||||
|
||||
function loginWindowLoadStart(event) {
|
||||
var url = event.url;
|
||||
if (url.indexOf("access_token=") > 0 || url.indexOf("error=") > 0) {
|
||||
// When we get the access token fast, the login window (inappbrowser) is still opening with animation
|
||||
// in the Cordova app, and trying to close it while it's animating generates an exception. Wait a little...
|
||||
var timeout = 600 - (new Date().getTime() - startTime);
|
||||
setTimeout(function () {
|
||||
loginWindow.close();
|
||||
}, timeout > 0 ? timeout : 0);
|
||||
oauthCallback(url);
|
||||
}
|
||||
}
|
||||
|
||||
function loginWindowExit() {
|
||||
console.log('exit and remove listeners');
|
||||
// Handle the situation where the user closes the login window manually before completing the login process
|
||||
deferredLogin.reject({error: 'user_cancelled', error_description: 'User cancelled login process', error_reason: "user_cancelled"});
|
||||
loginWindow.removeEventListener('loadstop', loginWindowLoadStart);
|
||||
loginWindow.removeEventListener('exit', loginWindowExit);
|
||||
loginWindow = null;
|
||||
console.log('done removing listeners');
|
||||
}
|
||||
|
||||
|
||||
if (!clientId) {
|
||||
return error({error: 'Google Client Id not set.'});
|
||||
}
|
||||
|
||||
scope = scope || '';
|
||||
|
||||
loginSuccessHandler = success;
|
||||
loginErrorHandler = error;
|
||||
|
||||
loginProcessed = false;
|
||||
logout();
|
||||
|
||||
// Check if an explicit oauthRedirectURL has been provided in init(). If not, infer the appropriate value
|
||||
if (!oauthRedirectURL) {
|
||||
if (runningInCordova) {
|
||||
//oauthRedirectURL = 'https://www.facebook.com/connect/login_success.html';
|
||||
} else {
|
||||
var origin = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');
|
||||
// could also use 'var origin = window.location.origin' when enough browsers support it
|
||||
oauthRedirectURL = origin + '/oauthcallbackgplus.html';
|
||||
}
|
||||
}
|
||||
|
||||
startTime = new Date().getTime();
|
||||
var url = GPLUS_LOGIN_URL + '?client_id=' + clientId + '&redirect_uri=' + oauthRedirectURL +
|
||||
'&response_type=token&display=popup&scope=' + scope;
|
||||
|
||||
window.location.href = url;
|
||||
/*
|
||||
// If the app is running in Cordova, listen to URL changes in the InAppBrowser until we get a URL with an access_token or an error
|
||||
if (runningInCordova) {
|
||||
loginWindow.addEventListener('loadstart', loginWindowLoadStart);
|
||||
loginWindow.addEventListener('exit', loginWindowExit);
|
||||
}
|
||||
|
||||
*/
|
||||
// Note: if the app is running in the browser the loginWindow dialog will call back by invoking the
|
||||
// oauthCallback() function. See oauthcallback.html for details.
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called either by oauthcallback.html (when the app is running the browser) or by the loginWindow loadstart event
|
||||
* handler defined in the login() function (when the app is running in the Cordova/PhoneGap container).
|
||||
* @param url - The oautchRedictURL called by Facebook with the access_token in the querystring at the ned of the
|
||||
* OAuth workflow.
|
||||
*/
|
||||
function oauthCallback(url) {
|
||||
// Parse the OAuth data received from Facebook
|
||||
var queryString,
|
||||
obj;
|
||||
|
||||
loginProcessed = true;
|
||||
if (url.indexOf("access_token=") > 0) {
|
||||
queryString = url.substr(url.indexOf('#') + 1);
|
||||
obj = parseQueryString(queryString);
|
||||
tokenStore['gplustoken'] = obj['access_token'];
|
||||
if (loginSuccessHandler) loginSuccessHandler();
|
||||
} else if (url.indexOf("error=") > 0) {
|
||||
queryString = url.substring(url.indexOf('?') + 1, url.indexOf('#'));
|
||||
obj = parseQueryString(queryString);
|
||||
if (loginErrorHandler) loginErrorHandler(obj);
|
||||
} else {
|
||||
if (loginErrorHandler) loginErrorHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Application-level logout: we simply discard the token.
|
||||
*/
|
||||
function logout() {
|
||||
tokenStore['gplustoken'] = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets you make any Facebook Graph API request.
|
||||
* @param obj - Request configuration object. Can include:
|
||||
* method: HTTP method: GET, POST, etc. Optional - Default is 'GET'
|
||||
* path: path in the Facebook graph: /me, /me.friends, etc. - Required
|
||||
* params: queryString parameters as a map - Optional
|
||||
* success: callback function when operation succeeds - Optional
|
||||
* error: callback function when operation fails - Optional
|
||||
*/
|
||||
function api(obj) {
|
||||
|
||||
var method = obj.method || 'GET',
|
||||
baseUrl = obj.baseUrl || 'https://www.googleapis.com/plus/v1/',
|
||||
params = obj.params || {},
|
||||
xhr = new XMLHttpRequest(),
|
||||
url;
|
||||
|
||||
params['access_token'] = tokenStore['gplustoken'];
|
||||
|
||||
url = baseUrl + obj.path + '?' + toQueryString(params);
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
if (obj.success) obj.success(JSON.parse(xhr.responseText));
|
||||
} else {
|
||||
var error = xhr.responseText ? JSON.parse(xhr.responseText).error : {message: 'An error has occurred'};
|
||||
if (obj.error) obj.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open(method, url, true);
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to de-authorize the app
|
||||
* @param success
|
||||
* @param error
|
||||
* @returns {*}
|
||||
*/
|
||||
function revokePermissions(success, error) {
|
||||
return api({
|
||||
baseUrl: 'https://accounts.google.com/o/oauth2',
|
||||
path: '/revoke',
|
||||
params: { 'token': tokenStore['gplustoken'] },
|
||||
success: function () {
|
||||
tokenStore['gplustoken'] = undefined;
|
||||
success();
|
||||
},
|
||||
error: error});
|
||||
}
|
||||
|
||||
function parseQueryString(queryString) {
|
||||
var qs = decodeURIComponent(queryString),
|
||||
obj = {},
|
||||
params = qs.split('&');
|
||||
params.forEach(function (param) {
|
||||
var splitter = param.split('=');
|
||||
obj[splitter[0]] = splitter[1];
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
function toQueryString(obj) {
|
||||
var parts = [];
|
||||
for (var i in obj) {
|
||||
if (obj.hasOwnProperty(i)) {
|
||||
parts.push(encodeURIComponent(i) + "=" + encodeURIComponent(obj[i]));
|
||||
}
|
||||
}
|
||||
return parts.join("&");
|
||||
}
|
||||
|
||||
// The public API
|
||||
return {
|
||||
init: init,
|
||||
login: login,
|
||||
logout: logout,
|
||||
revokePermissions: revokePermissions,
|
||||
api: api,
|
||||
oauthCallback: oauthCallback
|
||||
}
|
||||
|
||||
}());
|
||||
File diff suppressed because it is too large
Load Diff
+1
@@ -0,0 +1 @@
|
||||
(function($){$.fn.extend({alphascroll:function(){return this.each(function(){var content=$(this),alphabet=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'],shortAlphabet=['a','d','g','j','m','p','s','w','z'],dividers=[],dividerClass,scrollbar='';$(content).find('.ui-li-divider').each(function(){dividerClass=$(this).html().toLowerCase();dividers.push(dividerClass);$(this).addClass(dividerClass);});function createScrollbar(){$(alphabet).each(function(index,value){if($.inArray(value,dividers)>-1){scrollbar+='<li id="alphascroll-'+value+'" class="alphascroll-item" unselectable="on">'+value.toUpperCase()+'</li>';}else{scrollbar+='<li id="alphascroll-'+value+'" unselectable="on">'+value.toUpperCase()+'</li>';}});$(content).wrap('<div />');var wrapper=$(content).parent();$(wrapper).prepend('<ul class="alphascroll">'+scrollbar+'</ul>');var alphascroll=$(content).closest('div').children('.alphascroll');$(alphascroll).bind('touchmove',function(event){event.preventDefault();var touch=event.originalEvent.touches[0]||event.originalEvent.changedTouches[0];alphaScroll(touch.pageY);});$(alphascroll).bind('mousedown',function(){$('.ui-page-active').bind('mousemove',function(event){$(this).css({"-webkit-user-select":"none","-moz-user-select":"none","-ms-user-select":"none","user-select":"none"});alphaScroll(event.pageY);});$('.ui-page-active').bind('mouseup',function(){$('.ui-page-active').unbind('mousemove');$(this).css({"-webkit-user-select":"text","-moz-user-select":"text","-ms-user-select":"text","user-select":"text"});});});if($(window).height()<=320){truncateScrollbar();}}$(window).bind('orientationchange',function(){$('.alphascroll').unwrap().remove();scrollbar='';createScrollbar();});function truncateScrollbar(){$('.alphascroll li').each(function(index,value){if($.inArray($(this).html().toLowerCase(),shortAlphabet)<0){$(this).html('·').addClass('truncated');}});}function alphaScroll(y){$('.alphascroll-item').each(function(){if(!(y<=$(this).offset().top||y>=$(this).offset().top+$(this).outerHeight())){var scroll_id=$(this).attr('id'),letter=scroll_id.split('-'),target=$('.'+letter[1]),position=target.position(),header_height;if($('.ui-page-active [data-role="header"]').hasClass('ui-fixed-hidden')){header_height=0;}else{header_height=$('.ui-page-active [data-role="header"]').height();}$.mobile.silentScroll(position.top-header_height);}});}createScrollbar();});}});})(jQuery);
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
### jQuery Star Rating Plugin v4.11 - 2013-03-14 ###
|
||||
* Home: http://www.fyneworks.com/jquery/star-rating/
|
||||
* Code: http://code.google.com/p/jquery-star-rating-plugin/
|
||||
*
|
||||
* Licensed under http://en.wikipedia.org/wiki/MIT_License
|
||||
###
|
||||
*/
|
||||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';5(1W.1C)(8($){5((!$.1s.1V&&!$.1s.1U))2d{1j.1X("1T",C,s)}1R(e){};$.o.4=8(j){5(3.u==0)9 3;5(M V[0]==\'1m\'){5(3.u>1){7 k=V;9 3.18(8(){$.o.4.K($(3),k)})};$.o.4[V[0]].K(3,$.27(V).26(1)||[]);9 3};7 j=$.1b({},$.o.4.1w,j||{});$.o.4.P++;3.1y(\'.l-4-1g\').p(\'l-4-1g\').18(8(){7 b,m=$(3);7 c=(3.2g||\'28-4\').1f(/\\[|\\]/g,\'Y\').1f(/^\\Y+|\\Y+$/g,\'\');7 d=$(3.2h||1j.1H);7 e=d.6(\'4\');5(!e||e.1o!=$.o.4.P)e={E:0,1o:$.o.4.P};7 f=e[c]||d.6(\'4\'+c);5(f)b=f.6(\'4\');5(f&&b)b.E++;R{b=$.1b({},j||{},($.1d?m.1d():($.25?m.6():w))||{},{E:0,L:[],v:[]});b.z=e.E++;f=$(\'<1G 13="l-4-1I"/>\');m.1J(f);f.p(\'4-12-11-10\');5(m.Z(\'G\')||m.14(\'G\'))b.n=s;5(m.14(\'1c\'))b.1c=s;f.1r(b.D=$(\'<W 13="4-D"><a U="\'+b.D+\'">\'+b.1B+\'</a></W>\').q(\'1e\',8(){$(3).4(\'N\');$(3).p(\'l-4-T\')}).q(\'1h\',8(){$(3).4(\'x\');$(3).I(\'l-4-T\')}).q(\'1i\',8(){$(3).4(\'y\')}).6(\'4\',b))};7 g=$(\'<W 20="21" 22-24="\'+3.U+\'" 13="l-4 t-\'+b.z+\'"><a U="\'+(3.U||3.1k)+\'">\'+3.1k+\'</a></W>\');f.1r(g);5(3.X)g.Z(\'X\',3.X);5(3.1x)g.p(3.1x);5(b.29)b.B=2;5(M b.B==\'1l\'&&b.B>0){7 h=($.o.15?g.15():0)||b.1n;7 i=(b.E%b.B),17=1K.1L(h/b.B);g.15(17).1M(\'a\').1N({\'1O-1P\':\'-\'+(i*17)+\'1Q\'})};5(b.n)g.p(\'l-4-1p\');R g.p(\'l-4-1S\').q(\'1e\',8(){$(3).4(\'1q\');$(3).4(\'J\')}).q(\'1h\',8(){$(3).4(\'x\');$(3).4(\'H\')}).q(\'1i\',8(){$(3).4(\'y\')});5(3.S)b.r=g;5(3.1Y=="A"){5($(3).14(\'1Z\'))b.r=g};m.1t();m.q(\'1u.4\',8(a){5(a.1v)9 C;$(3).4(\'y\')});g.6(\'4.m\',m.6(\'4.l\',g));b.L[b.L.u]=g[0];b.v[b.v.u]=m[0];b.t=e[c]=f;b.23=d;m.6(\'4\',b);f.6(\'4\',b);g.6(\'4\',b);d.6(\'4\',e);d.6(\'4\'+c,f)});$(\'.4-12-11-10\').4(\'x\').I(\'4-12-11-10\');9 3};$.1b($.o.4,{P:0,J:8(){7 a=3.6(\'4\');5(!a)9 3;5(!a.J)9 3;7 b=$(3).6(\'4.m\')||$(3.19==\'1a\'?3:w);5(a.J)a.J.K(b[0],[b.Q(),$(\'a\',b.6(\'4.l\'))[0]])},H:8(){7 a=3.6(\'4\');5(!a)9 3;5(!a.H)9 3;7 b=$(3).6(\'4.m\')||$(3.19==\'1a\'?3:w);5(a.H)a.H.K(b[0],[b.Q(),$(\'a\',b.6(\'4.l\'))[0]])},1q:8(){7 a=3.6(\'4\');5(!a)9 3;5(a.n)9;3.4(\'N\');3.1z().1A().O(\'.t-\'+a.z).p(\'l-4-T\')},N:8(){7 a=3.6(\'4\');5(!a)9 3;5(a.n)9;a.t.2a().O(\'.t-\'+a.z).I(\'l-4-q\').I(\'l-4-T\')},x:8(){7 a=3.6(\'4\');5(!a)9 3;3.4(\'N\');7 b=$(a.r);7 c=b.u?b.1z().1A().O(\'.t-\'+a.z):w;5(c)c.p(\'l-4-q\');a.D[a.n||a.1c?\'1t\':\'2b\']();3.2c()[a.n?\'p\':\'I\'](\'l-4-1p\')},y:8(a,b){7 c=3.6(\'4\');5(!c)9 3;5(c.n)9;c.r=w;5(M a!=\'F\'||3.u>1){5(M a==\'1l\')9 $(c.L[a]).4(\'y\',F,b);5(M a==\'1m\'){$.18(c.L,8(){5($(3).6(\'4.m\').Q()==a)$(3).4(\'y\',F,b)});9 3}}R{c.r=3[0].19==\'1a\'?3.6(\'4.l\'):(3.2e(\'.t-\'+c.z)?3:w)};3.6(\'4\',c);3.4(\'x\');7 d=$(c.r?c.r.6(\'4.m\'):w);7 e=$(c.v).O(\':S\');7 f=$(c.v).1y(d);f.1D(\'S\',C);d.1D(\'S\',s);$(d.u?d:e).2f({1E:\'1u\',1v:s});5((b||b==F)&&c.1F)c.1F.K(d[0],[d.Q(),$(\'a\',c.r)[0]]);9 3},n:8(a,b){7 c=3.6(\'4\');5(!c)9 3;c.n=a||a==F?s:C;5(b)$(c.v).Z("G","G");R $(c.v).2i("G");3.6(\'4\',c);3.4(\'x\')},2j:8(){3.4(\'n\',s,s)},2k:8(){3.4(\'n\',C,C)}});$.o.4.1w={D:\'2l 2m\',1B:\'\',B:0,1n:16};$(8(){$(\'m[1E=2n].l\').4()})})(1C);',62,148,'|||this|rating|if|data|var|function|return||||||||||||star|input|readOnly|fn|addClass|on|current|true|rater|length|inputs|null|draw|select|serial||split|false|cancel|count|undefined|disabled|blur|removeClass|focus|apply|stars|typeof|drain|filter|calls|val|else|checked|hover|title|arguments|div|id|_|attr|drawn|be|to|class|hasClass|width||spw|each|tagName|INPUT|extend|required|metadata|mouseover|replace|applied|mouseout|click|document|value|number|string|starWidth|call|readonly|fill|append|support|hide|change|selfTriggered|options|className|not|prevAll|addBack|cancelValue|jQuery|prop|type|callback|span|body|control|before|Math|floor|find|css|margin|left|px|catch|live|BackgroundImageCache|style|opacity|window|execCommand|nodeName|selected|role|text|aria|context|label|meta|slice|makeArray|unnamed|half|children|show|siblings|try|is|trigger|name|form|removeAttr|disable|enable|Cancel|Rating|radio'.split('|'),0,{}))
|
||||
Vendored
+4
File diff suppressed because one or more lines are too long
+203
@@ -0,0 +1,203 @@
|
||||
define(['jquery', 'underscore', 'backbone',
|
||||
'modules/home/home', 'modules/faq/faq', 'modules/index/index', 'modules/category/category', 'modules/item/item',
|
||||
'modules/about/about', 'modules/search/search', 'modules/search/found', 'modules/more/more', 'modules/note/note',
|
||||
'modules/sync/sync', 'modules/converter/converter', 'modules/donation/donation', 'modules/settings/settings',
|
||||
'model/note/noteCollection', 'model/category/categoryCollection', 'model/categoryItem/categoryItemCollection',
|
||||
'model/item/itemCollection', 'model/item/ingredientiCollection', 'model/categoryItem/foundItemCollection',
|
||||
'libs/fastclick', 'jqm', 'jQueryPlugins'],
|
||||
function ($, _, Backbone,
|
||||
HomeView, FaqView, IndexView, CategoryView, ItemView,
|
||||
AboutView, SearchView, FoundView, MoreView, NoteView,
|
||||
SyncView, ConverterView, DonationView, SettingsView,
|
||||
NoteCollection, CategoryCollection, CategoryItemCollection,
|
||||
ItemCollection, IngredientiCollection, FoundItemCollection,
|
||||
FastClick) {
|
||||
|
||||
'use strict';
|
||||
var Router = Backbone.Router.extend({
|
||||
//define routes and mapping route to the function
|
||||
routes: {
|
||||
'': 'showHome', //home view
|
||||
'homeView': 'showHome', //home view as well
|
||||
'faqView': 'showFaq', //home view as well
|
||||
'indexView': 'showIndex', //home view as well
|
||||
'category/:categoryName/:categoryId': 'showCategory',
|
||||
'ricetta/:itemId': 'showItem',
|
||||
'aboutView': 'showAbout',
|
||||
'syncView(/)*founded': 'showSync',
|
||||
'noteView': 'showNote',
|
||||
'searchView': 'showSearch',
|
||||
'settingsView': 'showSettings',
|
||||
'donationView': 'showDonation',
|
||||
'search/:nresult/:categoria/:difficolta/*titolo': 'searchFn',
|
||||
'converterView': 'showConverter',
|
||||
'moreView': 'showMore',
|
||||
'*actions': 'defaultAction' //default action
|
||||
},
|
||||
defaultAction: function (actions) {
|
||||
this.showHome(actions);
|
||||
},
|
||||
showHome: function (actions) {
|
||||
// will render home view and navigate to homeView
|
||||
var homeView = new HomeView();
|
||||
homeView.render();
|
||||
this.changePage(homeView);
|
||||
},
|
||||
showSettings: function (actions) {
|
||||
var settingsView = new SettingsView();
|
||||
settingsView.render();
|
||||
this.changePage(settingsView);
|
||||
},
|
||||
showDonation: function (actions) {
|
||||
var donationView = new DonationView();
|
||||
donationView.render();
|
||||
this.changePage(donationView);
|
||||
},
|
||||
showAbout: function (actions) {
|
||||
// will render home view and navigate to homeView
|
||||
var aboutView = new AboutView();
|
||||
aboutView.render();
|
||||
this.changePage(aboutView);
|
||||
},
|
||||
showSync: function (actions) {
|
||||
var option = {};
|
||||
if (actions)
|
||||
{
|
||||
option = {tokenFound: 1};
|
||||
}
|
||||
// will render home view and navigate to homeView
|
||||
var syncView = new SyncView(option);
|
||||
syncView.render();
|
||||
this.changePage(syncView);
|
||||
},
|
||||
showNote: function (actions) {
|
||||
var notes = new NoteCollection();
|
||||
// will render home view and navigate to homeView
|
||||
var noteView = new NoteView({collection: notes});
|
||||
noteView.render();
|
||||
this.changePage(noteView);
|
||||
},
|
||||
showFaq: function (actions) {
|
||||
// will render home view and navigate to homeView
|
||||
var faqView = new FaqView();
|
||||
faqView.render();
|
||||
this.changePage(faqView);
|
||||
},
|
||||
showIndex: function (actions) {
|
||||
var categories = new CategoryCollection();
|
||||
// will render home view and navigate to homeView
|
||||
var indexView = new IndexView({collection: categories});
|
||||
//indexView.render();
|
||||
indexView.bind('renderCompleted:Categories', this.changePage, this);
|
||||
},
|
||||
showCategory: function (categoryName, categoryId) {
|
||||
var categories = new CategoryItemCollection({categoryId: categoryId});
|
||||
// will render home view and navigate to homeView
|
||||
var categoryView = new CategoryView({categoryName: categoryName, collection: categories});
|
||||
|
||||
categoryView.render();
|
||||
this.changePage(categoryView);
|
||||
|
||||
$.mobile.loading('show', {
|
||||
text: 'Caricamento categoria ' + categoryName + '...',
|
||||
textVisible: true,
|
||||
//theme: 'z',
|
||||
html: ""
|
||||
});
|
||||
//categoryView.bind('renderCompleted:Category',this.changePage,this);
|
||||
},
|
||||
showItem: function (itemId) {
|
||||
var item = new ItemCollection({ricettaId: itemId});
|
||||
var ingr = new IngredientiCollection({ricettaId: itemId});
|
||||
// will render home view and navigate to homeView
|
||||
var itemView = new ItemView({
|
||||
collRicetta: item,
|
||||
collIngredienti: ingr
|
||||
});
|
||||
//indexView.render();
|
||||
itemView.bind('renderCompleted:Item', this.changePage, this);
|
||||
},
|
||||
showConverter: function () {
|
||||
var converterView = new ConverterView();
|
||||
converterView.render();
|
||||
this.changePage(converterView);
|
||||
},
|
||||
showMore: function () {
|
||||
var moreView = new MoreView();
|
||||
moreView.render();
|
||||
this.changePage(moreView);
|
||||
},
|
||||
showSearch: function () {
|
||||
var categories = new CategoryCollection();
|
||||
// will render home view and navigate to homeView
|
||||
var searchView = new SearchView({collection: categories});
|
||||
//indexView.render();
|
||||
searchView.bind('renderCompleted:Search', this.changePage, this);
|
||||
},
|
||||
searchFn: function (nresult, categoria, difficolta, titolo) {
|
||||
|
||||
//console.log("Search by Titolo: " + titolo + ", Categoria: " + categoria + ", Difficoltà: " + difficolta);
|
||||
var foundedItems = new FoundItemCollection({categoryId: categoria, difficolta: difficolta, titolo: titolo, nResult: nresult});
|
||||
var foundView = new FoundView({collection: foundedItems});
|
||||
|
||||
foundView.render();
|
||||
this.changePage(foundView);
|
||||
|
||||
$.mobile.loading('show', {
|
||||
text: 'Caricamento ricerca ricette...',
|
||||
textVisible: true,
|
||||
//theme: 'z',
|
||||
html: ""
|
||||
});
|
||||
},
|
||||
init: true,
|
||||
//1. changePage will insert view into DOM and then call changePage to enhance and transition
|
||||
//2. for the first page, jQuery mobile will present and enhance automatically
|
||||
//3. for the other page, we will call $.mobile.changePage() to enhance page and make transition
|
||||
//4. argument 'view' is passed from event trigger
|
||||
changePage: function (view) {
|
||||
|
||||
//append to dom
|
||||
$('body').append(view.$el);
|
||||
|
||||
$.mobile.pageContainer.pagecontainer("change", $(view.el), {changeHash: false});
|
||||
|
||||
FastClick.attach(document.body);
|
||||
|
||||
$(":jqmData(role='page'):last").on("pageshow", function (event) {
|
||||
if (view.onShowed !== null)
|
||||
view.onShowed();
|
||||
});
|
||||
|
||||
$('input[type=radio].star').rating({
|
||||
callback: function (value, link) {
|
||||
var tip = $('#hover-test');
|
||||
if (value == undefined)
|
||||
{
|
||||
$('#hover-test').html("Nessuna" || 'value: ');
|
||||
}
|
||||
else
|
||||
$('#hover-test').html(link.title || 'value: ' + value);
|
||||
},
|
||||
focus: function (value, link) {
|
||||
var tip = $('#hover-test');
|
||||
tip[0].data = tip[0].data || tip.html();
|
||||
tip.html(link.title || 'value: ' + value);
|
||||
}
|
||||
// ,
|
||||
// blur: function(value, link){
|
||||
// var tip = $('#hover-test');
|
||||
// $('#hover-test').html(tip[0].data || '');
|
||||
// }
|
||||
});
|
||||
|
||||
if (!this.init) {
|
||||
|
||||
} else {
|
||||
this.init = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Router;
|
||||
});
|
||||
Reference in New Issue
Block a user