diff --git a/web/js/app.js b/web/js/app.js index 9b3a2fc1d..40d543244 100644 --- a/web/js/app.js +++ b/web/js/app.js @@ -30,6 +30,635 @@ throw new SyntaxError('Error parsing JSON, source is not valid.');};jQuery.quote c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';} return'"'+str+'"';};}(jQuery)); + +$.fn.scrollTo = function( target, options, callback ){ + if(typeof options == 'function' && arguments.length == 2){ callback = options; options = target; } + var settings = $.extend({ + scrollTarget : target, + offsetTop : 50, + duration : 10, + easing : 'swing' + }, options); + return this.each(function(){ + var scrollPane = $(this); + var scrollTarget = (typeof settings.scrollTarget == "number") ? settings.scrollTarget : $(settings.scrollTarget); + var scrollY = (typeof scrollTarget == "number") ? scrollTarget : scrollTarget.offset().top + scrollPane.scrollTop() - parseInt(settings.offsetTop); + scrollPane.animate({scrollTop : scrollY }, parseInt(settings.duration), settings.easing, function(){ + if (typeof callback == 'function') { callback.call(this); } + }); + }); +} + +/* + * Date Format 1.2.3 + * (c) 2007-2009 Steven Levithan + * MIT license + * + * Includes enhancements by Scott Trenda + * and Kris Kowal + * + * Accepts a date, a mask, or a date and a mask. + * Returns a formatted version of the given date. + * The date defaults to the current date/time. + * The mask defaults to dateFormat.masks.default. + */ + + +var dateFormat = function () { + var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, + timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, + timezoneClip = /[^-+\dA-Z]/g, + pad = function (val, len) { + val = String(val); + len = len || 2; + while (val.length < len) val = "0" + val; + return val; + }; + + // Regexes and supporting functions are cached through closure + return function (date, mask, utc) { + var dF = dateFormat; + + // You can't provide utc if you skip other args (use the "UTC:" mask prefix) + if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { + mask = date; + date = undefined; + } + + // Passing date through Date applies Date.parse, if necessary + date = date ? new Date(date) : new Date; + if (isNaN(date)) throw SyntaxError("invalid date"); + + mask = String(dF.masks[mask] || mask || dF.masks["default"]); + + // Allow setting the utc argument via the mask + if (mask.slice(0, 4) == "UTC:") { + mask = mask.slice(4); + utc = true; + } + + var _ = utc ? "getUTC" : "get", + d = date[_ + "Date"](), + D = date[_ + "Day"](), + m = date[_ + "Month"](), + y = date[_ + "FullYear"](), + H = date[_ + "Hours"](), + M = date[_ + "Minutes"](), + s = date[_ + "Seconds"](), + L = date[_ + "Milliseconds"](), + o = utc ? 0 : date.getTimezoneOffset(), + flags = { + d: d, + dd: pad(d), + ddd: dF.i18n.dayNames[D], + dddd: dF.i18n.dayNames[D + 7], + m: m + 1, + mm: pad(m + 1), + mmm: dF.i18n.monthNames[m], + mmmm: dF.i18n.monthNames[m + 12], + yy: String(y).slice(2), + yyyy: y, + h: H % 12 || 12, + hh: pad(H % 12 || 12), + H: H, + HH: pad(H), + M: M, + MM: pad(M), + s: s, + ss: pad(s), + l: pad(L, 3), + L: pad(L > 99 ? Math.round(L / 10) : L), + t: H < 12 ? "a" : "p", + tt: H < 12 ? "am" : "pm", + T: H < 12 ? "A" : "P", + TT: H < 12 ? "AM" : "PM", + Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), + o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), + S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] + }; + + return mask.replace(token, function ($0) { + return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); + }); + }; +}(); + +// Some common format strings +dateFormat.masks = { + "default": "ddd mmm dd yyyy HH:MM:ss", + shortDate: "m/d/yy", + mediumDate: "mmm d, yyyy", + longDate: "mmmm d, yyyy", + fullDate: "dddd, mmmm d, yyyy", + shortTime: "h:MM TT", + mediumTime: "h:MM:ss TT", + longTime: "h:MM:ss TT Z", + isoDate: "yyyy-mm-dd", + isoTime: "HH:MM:ss", + isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", + isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" +}; + +// Internationalization strings +dateFormat.i18n = { + dayNames: [ + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" + ], + monthNames: [ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" + ] +}; + +// For convenience... +Date.prototype.format = function (mask, utc) { + return dateFormat(this, mask, utc); +}; + + +/* + * http://code.google.com/p/flexible-js-formatting/ + * + * Copyright (C) 2004 Baron Schwartz + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +Date.parseFunctions = {count:0}; +Date.parseRegexes = []; +Date.formatFunctions = {count:0}; + +Date.prototype.dateFormat = function(format, ignore_offset) { + if (Date.formatFunctions[format] == null) { + Date.createNewFormat(format); + } + var func = Date.formatFunctions[format]; + if (ignore_offset || ! this.offset) { + return this[func](); + } else { + return (new Date(this.valueOf() - this.offset))[func](); + } +}; + +Date.createNewFormat = function(format) { + var funcName = "format" + Date.formatFunctions.count++; + Date.formatFunctions[format] = funcName; + var code = "Date.prototype." + funcName + " = function(){return "; + var special = false; + var ch = ''; + for (var i = 0; i < format.length; ++i) { + ch = format.charAt(i); + // escape character start + if (!special && ch == "\\") { + special = true; + } + // escaped string + else if (!special && ch == '"') { + var end = format.indexOf('"', i+1); + if (end==-1) + { + end = format.length; + } + code += "'" + String.escape(format.substring(i+1, end)) + "' + "; + i = end; + } + // escaped character + else if (special) { + special = false; + code += "'" + String.escape(ch) + "' + "; + } + else { + code += Date.getFormatCode(ch); + } + } + eval(code.substring(0, code.length - 3) + ";}"); +}; + +Date.getFormatCode = function(character) { + switch (character) { + case "d": + return "String.leftPad(this.getDate(), 2, '0') + "; + case "D": + return "Date.dayNames[this.getDay()].substring(0, 3) + "; + case "j": + return "this.getDate() + "; + case "l": + return "Date.dayNames[this.getDay()] + "; + case "S": + return "this.getSuffix() + "; + case "w": + return "this.getDay() + "; + case "z": + return "this.getDayOfYear() + "; + case "W": + return "this.getWeekOfYear() + "; + case "F": + return "Date.monthNames[this.getMonth()] + "; + case "m": + return "String.leftPad(this.getMonth() + 1, 2, '0') + "; + case "M": + return "Date.monthNames[this.getMonth()].substring(0, 3) + "; + case "n": + return "(this.getMonth() + 1) + "; + case "t": + return "this.getDaysInMonth() + "; + case "L": + return "(this.isLeapYear() ? 1 : 0) + "; + case "Y": + return "this.getFullYear() + "; + case "y": + return "('' + this.getFullYear()).substring(2, 4) + "; + case "a": + return "(this.getHours() < 12 ? 'am' : 'pm') + "; + case "A": + return "(this.getHours() < 12 ? 'AM' : 'PM') + "; + case "g": + return "((this.getHours() %12) ? this.getHours() % 12 : 12) + "; + case "G": + return "this.getHours() + "; + case "h": + return "String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + "; + case "H": + return "String.leftPad(this.getHours(), 2, '0') + "; + case "i": + return "String.leftPad(this.getMinutes(), 2, '0') + "; + case "s": + return "String.leftPad(this.getSeconds(), 2, '0') + "; + case "X": + return "String.leftPad(this.getMilliseconds(), 3, '0') + "; + case "O": + return "this.getGMTOffset() + "; + case "T": + return "this.getTimezone() + "; + case "Z": + return "(this.getTimezoneOffset() * -60) + "; + case "q": // quarter num, Q for name? + return "this.getQuarter() + "; + default: + return "'" + String.escape(character) + "' + "; + } +}; + +Date.parseDate = function(input, format) { + if (Date.parseFunctions[format] == null) { + Date.createParser(format); + } + var func = Date.parseFunctions[format]; + return Date[func](input); +}; + +Date.createParser = function(format) { + var funcName = "parse" + Date.parseFunctions.count++; + var regexNum = Date.parseRegexes.length; + var currentGroup = 1; + Date.parseFunctions[format] = funcName; + + var code = "Date." + funcName + " = function(input){\n" + + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, ms = -1, z = 0;\n" + + "var d = new Date();\n" + + "y = d.getFullYear();\n" + + "m = d.getMonth();\n" + + "d = d.getDate();\n" + + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n" + + "if (results && results.length > 0) {" ; + var regex = ""; + + var special = false; + var ch = ''; + for (var i = 0; i < format.length; ++i) { + ch = format.charAt(i); + if (!special && ch == "\\") { + special = true; + } + else if (special) { + special = false; + regex += String.escape(ch); + } + else { + obj = Date.formatCodeToRegex(ch, currentGroup); + currentGroup += obj.g; + regex += obj.s; + if (obj.g && obj.c) { + code += obj.c; + } + } + } + + code += "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0 && ms >= 0)\n" + + "{return new Date(y, m, d, h, i, s, ms).applyOffset(z);}\n" + + "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n" + + "{return new Date(y, m, d, h, i, s).applyOffset(z);}\n" + + "else if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n" + + "{return new Date(y, m, d, h, i).applyOffset(z);}\n" + + "else if (y > 0 && m >= 0 && d > 0 && h >= 0)\n" + + "{return new Date(y, m, d, h).applyOffset(z);}\n" + + "else if (y > 0 && m >= 0 && d > 0)\n" + + "{return new Date(y, m, d).applyOffset(z);}\n" + + "else if (y > 0 && m >= 0)\n" + + "{return new Date(y, m).applyOffset(z);}\n" + + "else if (y > 0)\n" + + "{return new Date(y).applyOffset(z);}\n" + + "}return null;}"; + + Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$"); + eval(code); +}; + +Date.formatCodeToRegex = function(character, currentGroup) { + switch (character) { + case "D": + return {g:0, + c:null, + s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"}; + case "j": + case "d": + return {g:1, + c:"d = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{1,2})"}; + case "l": + return {g:0, + c:null, + s:"(?:" + Date.dayNames.join("|") + ")"}; + case "S": + return {g:0, + c:null, + s:"(?:st|nd|rd|th)"}; + case "w": + return {g:0, + c:null, + s:"\\d"}; + case "z": + return {g:0, + c:null, + s:"(?:\\d{1,3})"}; + case "W": + return {g:0, + c:null, + s:"(?:\\d{2})"}; + case "F": + return {g:1, + c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n", + s:"(" + Date.monthNames.join("|") + ")"}; + case "M": + return {g:1, + c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n", + s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"}; + case "n": + case "m": + return {g:1, + c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n", + s:"(\\d{1,2})"}; + case "t": + return {g:0, + c:null, + s:"\\d{1,2}"}; + case "L": + return {g:0, + c:null, + s:"(?:1|0)"}; + case "Y": + return {g:1, + c:"y = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{4})"}; + case "y": + return {g:1, + c:"var ty = parseInt(results[" + currentGroup + "], 10);\n" + + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", + s:"(\\d{1,2})"}; + case "a": + return {g:1, + c:"if (results[" + currentGroup + "] == 'am') {\n" + + "if (h == 12) { h = 0; }\n" + + "} else { if (h < 12) { h += 12; }}", + s:"(am|pm)"}; + case "A": + return {g:1, + c:"if (results[" + currentGroup + "] == 'AM') {\n" + + "if (h == 12) { h = 0; }\n" + + "} else { if (h < 12) { h += 12; }}", + s:"(AM|PM)"}; + case "g": + case "G": + case "h": + case "H": + return {g:1, + c:"h = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{1,2})"}; + case "i": + return {g:1, + c:"i = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{2})"}; + case "s": + return {g:1, + c:"s = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{2})"}; + case "X": + return {g:1, + c:"ms = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{3})"}; + case "O": + case "P": + return {g:1, + c:"z = Date.parseOffset(results[" + currentGroup + "], 10);\n", + s:"(Z|[+-]\\d{2}:?\\d{2})"}; // "Z", "+05:00", "+0500" all acceptable. + case "T": + return {g:0, + c:null, + s:"[A-Z]{3}"}; + case "Z": + return {g:1, + c:"s = parseInt(results[" + currentGroup + "], 10);\n", + s:"([+-]\\d{1,5})"}; + default: + return {g:0, + c:null, + s:String.escape(character)}; + } +}; + +Date.parseOffset = function(str) { + if (str == "Z") { return 0 ; } // UTC, no offset. + var seconds ; + seconds = parseInt(str[0] + str[1] + str[2]) * 3600 ; // e.g., "+05" or "-08" + if (str[3] == ":") { // "+HH:MM" is preferred iso8601 format ("O") + seconds += parseInt(str[4] + str[5]) * 60; + } else { // "+HHMM" is frequently used, though. ("P") + seconds += parseInt(str[3] + str[4]) * 60; + } + return seconds ; +}; + +Date.today = function() { + var now = new Date(); + now.setHours(0); + now.setMinutes(0); + now.setSeconds(0); + + return now; +} + +// convert the parsed date into UTC, but store the offset so we can optionally use it in dateFormat() +Date.prototype.applyOffset = function(offset_seconds) { + this.offset = offset_seconds * 1000 ; + this.setTime(this.valueOf() + this.offset); + return this ; +}; + +Date.prototype.getTimezone = function() { + return this.toString().replace( + /^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace( + /^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3").replace( + /^.*?[0-9]{4} \(([A-Z]{3})\)/, "$1"); +}; + +Date.prototype.getGMTOffset = function() { + return (this.getTimezoneOffset() > 0 ? "-" : "+") + + String.leftPad(Math.floor(this.getTimezoneOffset() / 60), 2, "0") + + String.leftPad(this.getTimezoneOffset() % 60, 2, "0"); +}; + +Date.prototype.getDayOfYear = function() { + var num = 0; + Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28; + for (var i = 0; i < this.getMonth(); ++i) { + num += Date.daysInMonth[i]; + } + return num + this.getDate() - 1; +}; + +Date.prototype.getWeekOfYear = function() { + // Skip to Thursday of this week + var now = this.getDayOfYear() + (4 - this.getDay()); + // Find the first Thursday of the year + var jan1 = new Date(this.getFullYear(), 0, 1); + var then = (7 - jan1.getDay() + 4); + document.write(then); + return String.leftPad(((now - then) / 7) + 1, 2, "0"); +}; + +Date.prototype.isLeapYear = function() { + var year = this.getFullYear(); + return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year))); +}; + +Date.prototype.getFirstDayOfMonth = function() { + var day = (this.getDay() - (this.getDate() - 1)) % 7; + return (day < 0) ? (day + 7) : day; +}; + +Date.prototype.getLastDayOfMonth = function() { + var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7; + return (day < 0) ? (day + 7) : day; +}; + +Date.prototype.getDaysInMonth = function() { + Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28; + return Date.daysInMonth[this.getMonth()]; +}; +Date.prototype.getQuarter = function() { + return Date.quarterFromMonthNum[this.getMonth()]; +}; + +Date.prototype.getSuffix = function() { + switch (this.getDate()) { + case 1: + case 21: + case 31: + return "st"; + case 2: + case 22: + return "nd"; + case 3: + case 23: + return "rd"; + default: + return "th"; + } +}; + +String.escape = function(string) { + return string.replace(/('|\\)/g, "\\$1"); +}; + +String.leftPad = function (val, size, ch) { + var result = new String(val); + if (ch == null) { + ch = " "; + } + while (result.length < size) { + result = ch + result; + } + return result; +}; + +Date.quarterFromMonthNum = [1,1,1,2,2,2,3,3,3,4,4,4]; +Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31]; +Date.monthNames = + ["January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December"]; +Date.dayNames = + ["Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday"]; +Date.y2kYear = 50; +Date.monthNumbers = { + Jan:0, + Feb:1, + Mar:2, + Apr:3, + May:4, + Jun:5, + Jul:6, + Aug:7, + Sep:8, + Oct:9, + Nov:10, + Dec:11}; +Date.patterns = { + ISO8601LongPattern: "Y\\-m\\-d\\TH\\:i\\:sO", + ISO8601ShortPattern: "Y\\-m\\-d", + ShortDatePattern: "n/j/Y", + LongDatePattern: "l, F d, Y", + FullDateTimePattern: "l, F d, Y g:i:s A", + MonthDayPattern: "F d", + ShortTimePattern: "g:i A", + LongTimePattern: "g:i:s A", + SortableDateTimePattern: "Y-m-d\\TH:i:s", + UniversalSortableDateTimePattern: "Y-m-d H:i:sO", + YearMonthPattern: "F, Y"}; + + /** * * @author: Malishev Dmitry @@ -75,24 +704,34 @@ var fb = _DEBUG && 'undefined' != typeof(console) ? console : { var App = { // Main namespases for page specific functions // Core namespaces - Ajax: { Busy: {} }, + Ajax: { + Busy: {} + }, Core: {}, + // CONSTANT VALUES + Constants: { + UNLIM_VALUE: 'Unlim' + }, // Actions. More widly used funcs Actions: { - DB: {}, - WEB: {} + DB: {}, + WEB: {}, + PACKAGE: {} }, // Utilities Helpers: {}, - HTML: {Build: {}}, + HTML: { + Build: {} + }, Filters: {}, Env: { lang: GLOBAL.lang, }, i18n: {}, Listeners: { - DB: {}, - WEB: {} + DB: {}, + WEB: {}, + PACKAGE: {} }, View:{ HTML: { @@ -101,22 +740,25 @@ var App = { // pages related views }, Cache: { - clear: function(){} // TODO: stub method, will be used later + clear: function() {} // TODO: stub method, will be used later }, Ref: {}, Tmp: {}, Thread: { - run: function(delay, ref){ - setTimeout(function(){ + run: function(delay, ref) { + setTimeout(function() { ref(); }, delay*10); } }, - Settings: { GLOBAL: {}, General: {}}, + Settings: { + GLOBAL: {}, + General: {} + }, Templates: { Templator: null, - Tpl: {}, - _indexes: {} + Tpl: {}, + _indexes: {} } }; @@ -165,7 +807,7 @@ App.Ajax.request = function(method, data, callback, onError){ converters: { "text boost": function(value) { value = value.trim(); - return jsonParse(value); + return $.parseJSON(value); }}, async: true, cache: false, diff --git a/web/js/jquery.finder.js b/web/js/jquery.finder.js new file mode 100644 index 000000000..7eed0b183 --- /dev/null +++ b/web/js/jquery.finder.js @@ -0,0 +1,577 @@ +// jQuery finderSelect: a jQuery plugin that activates selecting elements +// within a parent with Ctrl+Click, Command+Click and Shift+Click. +// +// Copyright 2013 Mike Angell +// +// Please see: +// +// https://github.com/evulse/finderselect +// +// For complete documentation. + +(function( $ ) { + + var d = $(document); + var b = $('body'); + + var commands = { + highlight: highlight, + unHighlight: unHighlight, + highlightAll: highlightAll, + unHighlightAll: unHighlightAll, + selected: selected, + children: children, + update: update, + addHook: addHook + }; + + var hooks = {}; + + var o = {}; + + var f = $.fn.finderSelect = function() { + if (typeof arguments[0] === 'string') { + var args = Array.prototype.slice.call(arguments); + args.splice(0, 1); + return commands[arguments[0]].apply(this, args); + } + else { + finderSelect.apply(this, arguments); + return this; + } + + }; + + function finderSelect(opt) { + + var p = $(this); + var options = { + selectClass: "selected", + unSelectClass: "un-selected", + currentClass: "selected-current", + lastClass: "selected-last", + shiftClass: "selected-shift", + ctrlClass: "selected-ctrl", + triggerUpdate: "finderSelectUpdate", + children: false, + event: "mousedown", + cursor: "pointer", + dragEvent: "mouseenter", + enableClickDrag: true, + enableShiftClick: true, + enableCtrlClick: true, + enableSingleClick: true, + enableSelectAll: true, + enableDisableSelection: true, + enableTouchCtrlDefault: true, + enableDesktopCtrlDefault: false, + totalSelector: false, + menuSelector: false, + menuXOffset: 0, + menuYOffset: 0 + + }; + + $.extend(options, opt); + + o = options; + + if(!o.children) { + o.children = f.detect.children(p); + } + + f.h.off(f.get.siblings(p,o), o); + + if(o.cursor) { + f.set.cursor(p,o); + } + if(o.enableDisableSelection) { + f.core.disableSelection(p,o); + } + if(o.enableClickDrag) { + f.core.clickDrag(p,o); + } + if(o.enableSelectAll) { + f.core.selectAll(p,o); + } + if(o.enableShiftClick || o.enableCtrlClick || o.enableSingleClick) { + f.core.click(p,o); + } + if(o.totalSelector) { + f.core.totalUpdate(p,o); + } + if(o.menuSelector) { + f.core.loadMenu(p,o); + } + }; + + function highlight(el) { + f.h.on(el, o); + return this; + } + function unHighlight(el) { + f.h.off(el, o); + return this; + } + function highlightAll() { + var p = $(this); + f.h.on(p.find(o.children), o); + return this; + } + function unHighlightAll() { + var p = $(this); + f.h.off(p.find(o.children), o); + return this; + } + function selected() { + var p = $(this); + return p.find(o.children+'.'+o.selectClass); + } + function children() { + var p = $(this); + return p.find(o.children); + } + function update() { + var p = $(this); + f.t.update(p, o); + return this; + } + function addHook(hookName, fn) { + if(!hooks[hookName]){ + hooks[hookName] = []; + } + hooks[hookName] = [fn]; + + return this; + } + + f.core = { + clickDrag: function(p,o) { + f.set.mouseDown(false); + b.mousedown(function(e) { + if(f.detect.leftMouse(e)) { f.set.mouseDown(true);} + }); + b.mouseup(function(e) { + if(f.detect.leftMouse(e)) { f.set.mouseDown(false);} + }); + p.on(o.dragEvent, o.children, function(e){ + var c = f.get.clicks(p,o,$(this)); + + if (f.get.mouseDown() && f.detect.ctrl(e)) { + f.t.deleteSelection(o); + f.t.toggleDrag(p,c,o); + } + }); + + return p; + }, + click: function(p,o) { + p.on(o.event, o.children, function(e){ + if(f.detect.leftMouse(e)) { + if (!$(e.target).hasClass('ch-toggle')) { + var c = f.get.clicks(p,o,$(this)); + + var ref = $(e.target); + if (ref.parents('.data-row').hasClass('selected') && $('.selected').length == 1) {console.warn(1); + ref.parents('.data-row').removeClass('selected'); + ref.parents('.data-row').find('.ch-toggle').attr('checked', false); + return; + } + + if (!(f.detect.ctrl(e) && o.enableCtrlClick) && (f.detect.shift(e) && o.enableShiftClick)) { + f.t.deleteSelection(o); + f.t.shiftClick(p,c,o); + } + + if (((f.detect.ctrl(e) && o.enableCtrlClick) || (f.detect.touch() && o.enableTouchCtrlDefault) || o.enableDesktopCtrlDefault) && !(f.detect.shift(e) && o.enableShiftClick)) { + f.t.toggleClick(p,c,o); + } + + if (!(f.detect.ctrl(e) && o.enableCtrlClick) && !(f.detect.shift(e) && o.enableShiftClick) && o.enableSingleClick && !o.enableDesktopCtrlDefault) { + f.t.singleClick(p,c,o); + } + } + } + + o.onFinish(e); + }); + }, + selectAll: function(p,o) { + p.on('mouseover', function(){ + d.on("keydown", turnOff); + }); + p.on('mouseout', function(){ + d.off("keydown", turnOff); + }); + + function turnOff(e) { + if (f.detect.ctrl(e)) { + if (e.keyCode == 65) { + e.preventDefault(); + if(f.detect.alt(e)) { + f.t.unHAll(p, o); + } else { + f.t.hAll(p,o); + } + } + } + if (e.keyCode == 38) { + var last = f.get.click(p, o.shiftClass); + if(last.length == 0) { + last = f.get.click(p, o.lastClass); + } + var cur = f.get.prev(last,o); + if(last.length == 0) { + cur = p.find(o.children).last(); + } + if(f.detect.alt(e)) { + cur = p.find(o.children).first(); + } + e.preventDefault(); + if(cur.length != 0) { + + if(f.detect.shift(e) && o.enableShiftClick) { + var c = f.get.clicks(p,o,cur); + f.t.shiftClick(p,c,o); + } else { + var c = f.get.clicks(p,o,cur); + f.t.singleClick(p,c,o); + } + } + } + if (e.keyCode == 40) { + var last = f.get.click(p, o.shiftClass); + if(last.length == 0) { + last = f.get.click(p, o.lastClass); + } + var cur = f.get.next(last,o); + if(last.length == 0) { + cur = p.find(o.children).first(); + } + if(f.detect.alt(e)) { + cur = p.find(o.children).last(); + } + e.preventDefault(); + if(cur.length != 0) { + + if(f.detect.shift(e) && o.enableShiftClick) { + var c = f.get.clicks(p,o,cur); + f.t.shiftClick(p,c,o); + } else { + var c = f.get.clicks(p,o,cur); + f.t.singleClick(p,c,o); + } + + } + } + } + + }, + totalUpdate: function(p,o) { + p.on(o.triggerUpdate, function(){ + $(o.totalSelector).html($(this).find(o.children).filter('.'+o.selectClass).length) + }); + }, + loadMenu: function(p, o) { + p.bind("contextmenu",function(e){ + $(o.menuSelector).css({left:(e.pageX+o.menuXOffset),top:(e.pageY+o.menuYOffset)}).show(); + return false; + }).bind("mousedown",function(){ + $(o.menuSelector).hide(); + }); + $(o.menuSelector).bind("click",function(){ + $(this).hide(); + }); + }, + disableSelection: function(p, o) { + d.on('keydown', function(){ + p.on("selectstart", turnOffSelection); + }).on('keyup', function(){ + p.off("selectstart", turnOffSelection); + }); + + function turnOffSelection(e) { + e.preventDefault(); + } + } + }; + + + f.h = { + on: function(el, o) { + f.get.hook('highlight:before', [el, o]); + el.removeClass(o.unSelectClass); + el.addClass(o.selectClass); + f.get.hook('highlight:after', [el, o]); + }, + off: function(el,o) { + f.get.hook('unHighlight:before', [el, o]); + el.removeClass(o.selectClass); + el.addClass(o.unSelectClass); + f.get.hook('unHighlight:after', [el, o]); + }, + tog: function(el,o) { + + el.each(function () { + var child = $(this); + if(f.detect.h(child, o)) { + f.h.off(child, o); + } else { + f.h.on(child, o); + } + }); + }, + reset: function(el,o) { + el.each(function () { + var child = $(this); + if(f.detect.lastH(child, o)) { + f.h.on(child, o); + } else { + f.h.off(child, o); + } + }); + + }, + state: function(el,o) { + el.each(function () { + var child = $(this); + if(f.detect.h(child, o)) { + child.removeClass('stateUnSelected'); + child.addClass('stateSelected'); + } else { + child.removeClass('stateSelected'); + child.addClass('stateUnSelected'); + + } + }); + + } + }; + + f.detect = { + leftMouse: function(e) { + return (e.which == 1); + }, + shift: function(e) { + return e.shiftKey; + }, + alt: function(e) { + return e.altKey; + }, + ctrl: function(e) { + return (e.ctrlKey || e.metaKey); + }, + h: function(el,o) { + return el.hasClass(o.selectClass); + }, + lastH: function(el,o) { + return el.hasClass('stateSelected'); + }, + touch: function() { + return !!('ontouchstart' in window) // works on most browsers + || !!('onmsgesturechange' in window); // works on ie10 + }, + children: function(el) { + return el.children().get(0).tagName; + } + }; + + f.set = { + clicks: function(curr, shif, ctrl, p, o) { + f.set.click(p, false, o.currentClass); + f.set.click(p, curr, o.lastClass); + f.set.click(p, shif,o.shiftClass); + f.set.click(p, ctrl,o.ctrlClass); + f.t.update(p, o); + }, + click: function(p,el,c) { + f.get.click(p,c).removeClass(c); + if(el) { el.addClass(c); } + }, + mouseDown: function(bool) { + return b.data('down', bool); + }, + cursor: function(p,o) { + var s = f.get.siblings(p,o); + return s.css('cursor', o.cursor); + } + }; + + f.get = { + clicks: function(p, o, curr) { + var c = {}; + f.set.click(p, curr, o.currentClass); + c.current = {v:curr,c: o.currentClass}; + c.hard = {v:f.get.click(p, o.lastClass),c:o.lastClass}; + c.shift = {v:f.get.click(p, o.shiftClass),c:o.shiftClass}; + c.ctrl = {v:f.get.click(p, o.ctrlClass),c:o.ctrlClass}; + return c; + }, + click: function(p,c) { + return p.find('.'+c); + }, + mouseDown: function() { + return b.data('down'); + }, + siblings: function(p, o) { + return p.find(o.children); + }, + between: function(s,y, z) { + if(s.index(y.v) < s.index(z.v)) { + + return f.get.elem(true, y.v, false, z.c); + } else { + return f.get.elem(false, y.v, false, z.c); + } + }, + elem: function(d, el, s, u) { + var $els = [], $el = (d) ? el.next() : el.prev(); + while( $el.length ) { + if(typeof u === 'undefined' || !u || !$el.hasClass(u)) { + if(typeof s === 'undefined' || !s || $el.hasClass(s)) { + $els.push($el[0]); + } + $el = (d) ? $el.next() : $el.prev(); + } else { + $el = {}; + } + } + return $($els) + }, + next: function(p, o) { + return p.next(o.children); + }, + prev: function(p, o) { + return p.prev(o.children); + }, + hook: function(hookName, data){ + var hooked = hooks[hookName] + + if(hooked){ + for(i=0; i 0) { + c.hard.v = $(start[0]); + f.set.click(p, c.hard.v, o.lastClass); + } else { + var start = f.get.elem(z < x, c.hard.v, o.selectClass); + if(start.length > 0) { + start = (z > x ) ? $(start[0]) : $(start[start.length-1]); + c.hard.v = start; + f.set.click(p, c.hard.v, o.lastClass); + } else { + c.hard.v = s.first(); + f.set.click(p, c.hard.v, o.lastClass); + f.t.singleClick(s,{current:{v:s.first()}},o); + } + + } + + } + + var x = s.index(c.hard.v); + var y = s.index(c.shift.v); + var z = s.index(c.current.v); + + + if(c.hard.v.length == 0){ + f.t.singleClick(s,{current:{v:s.first()}},o); + } + + if(c.shift.v.length != 0) { + if((x < y && x < z && z < y) || (x > y && x > z && z > y)) { + f.h.off(f.get.between(s, c.shift, c.current), o); + } + if((x < y && x > z && z < y) || (x > y && x < z && z > y)) { + f.h.off(f.get.between(s, c.shift, c.hard), o); + f.h.on(f.get.between(s, c.current, c.hard), o); + } + if((x > y && x > z && z < y) || (x < y && x < z && z > y) || (x == y)) { + f.h.on(f.get.between(s, c.shift, c.current), o); + } else { + f.h.off(c.shift.v, o); + f.t.unHExist(z>y, c.shift.v,o); + } + } else { + f.t.unHExist(z>x,c.hard.v,o); + f.h.on(f.get.between(s, c.current, c.hard), o); + } + + f.h.on(c.current.v, o); + f.set.clicks(c.hard.v, c.current.v, null, p, o); + + }, + unHAll: function(p,o) { + f.h.off(p.find(o.children), o); + f.t.update(p, o); + }, + hAll: function(p,o) { + f.h.on(p.find(o.children), o); + f.t.update(p, o); + }, + unHExist: function(bool,el,o) { + if(bool) { + f.h.off(f.get.elem(false, el, false, o.unSelectClass), o); + } else { + + f.h.off(f.get.elem(true, el, false, o.unSelectClass), o); + } + } + + }; + +})(window.jQuery || window.Zepto); diff --git a/web/templates/footer.html b/web/templates/footer.html index 344e5a411..e8e9cd9d9 100644 --- a/web/templates/footer.html +++ b/web/templates/footer.html @@ -1,9 +1,32 @@

+ diff --git a/web/templates/header.html b/web/templates/header.html index 26f6e5ece..0de10fd3b 100644 --- a/web/templates/header.html +++ b/web/templates/header.html @@ -4,7 +4,7 @@ Vesta - <?php echo "$TAB"; ?> - + - + - + + - + -