2015-12-17 03:34:20 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
|
|
define(function(require){ var module = {}
|
|
|
|
|
|
|
|
|
|
//var DEBUG = DEBUG != null ? DEBUG : true
|
|
|
|
|
|
|
|
|
|
|
2016-04-17 00:58:21 +03:00
|
|
|
|
2015-12-17 03:34:20 +03:00
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2015-12-31 10:37:21 +03:00
|
|
|
String.prototype.capitalize = function(){
|
|
|
|
|
return this[0].toUpperCase() + this.slice(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XXX not sure if this has to be a utility or a method...
|
|
|
|
|
Object.get = function(obj, name, dfl){
|
|
|
|
|
var val = obj[name]
|
|
|
|
|
if(val === undefined && dfl != null){
|
|
|
|
|
return dfl
|
|
|
|
|
}
|
|
|
|
|
return val
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compact a sparse array...
|
|
|
|
|
//
|
|
|
|
|
// NOTE: this will not compact in-place.
|
|
|
|
|
Array.prototype.compact = function(){
|
|
|
|
|
return this.filter(function(){ return true })
|
|
|
|
|
}
|
2016-04-12 19:01:40 +03:00
|
|
|
/*
|
|
|
|
|
Array.prototype.compact = function(){
|
|
|
|
|
var res = []
|
|
|
|
|
for(var i in res){
|
|
|
|
|
res.push(this[i])
|
|
|
|
|
}
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
*/
|
2015-12-31 10:37:21 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// return an array with duplicate elements removed...
|
|
|
|
|
//
|
2016-04-14 16:37:58 +03:00
|
|
|
Array.prototype.unique = function(normalize){
|
|
|
|
|
if(normalize){
|
2016-04-16 01:36:55 +03:00
|
|
|
var cache = this.map(function(e){ return normalize(e) })
|
2016-04-14 16:37:58 +03:00
|
|
|
return this.filter(function(e, i, a){ return cache.indexOf(cache[i]) == i })
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
return this.filter(function(e, i, a){ return a.indexOf(e) == i })
|
|
|
|
|
}
|
2015-12-31 10:37:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compare two arrays...
|
|
|
|
|
//
|
|
|
|
|
Array.prototype.cmp = function(other){
|
|
|
|
|
if(this === other){
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if(this.length != other.length){
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
for(var i=0; i<this.length; i++){
|
|
|
|
|
if(this[i] != other[i]){
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compare two Arrays as sets...
|
|
|
|
|
//
|
|
|
|
|
// This will ignore order
|
|
|
|
|
Array.prototype.setCmp = function(other){
|
|
|
|
|
return this === other
|
|
|
|
|
|| this.unique().sort().cmp(other.unique().sort())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-04-20 16:17:12 +03:00
|
|
|
module.chainCmp = function(cmp_chain){
|
|
|
|
|
return function(a, b, get, data){
|
|
|
|
|
var res
|
|
|
|
|
for(var i=0; i < cmp_chain.length; i++){
|
|
|
|
|
res = cmp_chain[i](a, b, get, data)
|
|
|
|
|
if(res != 0){
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-31 10:37:21 +03:00
|
|
|
|
|
|
|
|
// like .length but for sparse arrays will return the element count...
|
|
|
|
|
// XXX make this a prop...
|
|
|
|
|
/*
|
|
|
|
|
Array.prototype.len = function(){
|
|
|
|
|
//return this.compact().length
|
|
|
|
|
return Object.keys(this).length
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Object.defineProperty(Array.prototype, 'len', {
|
|
|
|
|
get : function () {
|
|
|
|
|
return Object.keys(this).length
|
|
|
|
|
},
|
|
|
|
|
set : function(val){},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-12-19 09:34:22 +03:00
|
|
|
// convert JS arguments to Array...
|
|
|
|
|
var args2array =
|
|
|
|
|
module.args2array =
|
|
|
|
|
function(args){
|
|
|
|
|
//return Array.apply(null, args)
|
|
|
|
|
return [].slice.call(args)
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-17 09:14:59 +03:00
|
|
|
// Quote a string and convert to RegExp to match self literally.
|
|
|
|
|
var quoteRegExp =
|
|
|
|
|
module.quoteRegExp =
|
|
|
|
|
function(str){
|
|
|
|
|
return str.replace(/([\.\\\/\(\)\[\]\$\*\+\-\{\}\@\^\&\?\<\>])/g, '\\$1')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XXX do we need to quote anything else???
|
|
|
|
|
var path2url =
|
|
|
|
|
module.path2url =
|
|
|
|
|
function(path){
|
|
|
|
|
// test if we have a schema, and if yes return as-is...
|
|
|
|
|
if(/^(http|https|file|[\w-]*):[\\\/]{2}/.test(path)){
|
|
|
|
|
return path
|
|
|
|
|
}
|
|
|
|
|
// skip encoding windows drives...
|
|
|
|
|
var drive = path.split(/^([a-z]:[\\\/])/i)
|
|
|
|
|
path = drive.pop()
|
|
|
|
|
drive = drive.pop() || ''
|
|
|
|
|
return drive + (path
|
|
|
|
|
.split(/[\\\/]/g)
|
|
|
|
|
// XXX these are too aggressive...
|
|
|
|
|
//.map(encodeURI)
|
|
|
|
|
//.map(encodeURIComponent)
|
|
|
|
|
.join('/')
|
|
|
|
|
// NOTE: keep '%' the first...
|
2015-12-18 07:55:14 +03:00
|
|
|
//.replace(/%/g, '%25')
|
2015-12-17 09:14:59 +03:00
|
|
|
.replace(/#/g, '%23')
|
|
|
|
|
.replace(/&/g, '%26'))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-12-17 03:34:20 +03:00
|
|
|
// NOTE: we are not using node's path module as we need this to work in
|
|
|
|
|
// all contexts, not only node... (???)
|
|
|
|
|
var normalizePath =
|
|
|
|
|
module.normalizePath =
|
|
|
|
|
function(path){
|
|
|
|
|
return typeof(path) == typeof('str') ? path
|
|
|
|
|
// normalize the slashes...
|
|
|
|
|
.replace(/(\/)/g, '/')
|
|
|
|
|
// remove duplicate '/'
|
|
|
|
|
.replace(/(\/)\1+/g, '/')
|
|
|
|
|
// remove trailing '/'
|
|
|
|
|
.replace(/\/+$/, '')
|
|
|
|
|
// take care of .
|
|
|
|
|
.replace(/\/\.\//g, '/')
|
|
|
|
|
.replace(/\/\.$/, '')
|
|
|
|
|
// take care of ..
|
|
|
|
|
.replace(/\/[^\/]+\/\.\.\//g, '/')
|
|
|
|
|
.replace(/\/[^\/]+\/\.\.$/, '')
|
|
|
|
|
: path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-14 16:01:17 +03:00
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
|
|
module.selectElemText = function(elem){
|
|
|
|
|
var range = document.createRange()
|
|
|
|
|
range.selectNodeContents(elem)
|
|
|
|
|
var sel = window.getSelection()
|
|
|
|
|
sel.removeAllRanges()
|
|
|
|
|
sel.addRange(range)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-12-19 09:34:22 +03:00
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2015-12-23 07:09:43 +03:00
|
|
|
// XXX experiment
|
2015-12-31 10:37:21 +03:00
|
|
|
if(typeof(jQuery) != typeof(undefined)){
|
|
|
|
|
jQuery.fn._drag = function(){
|
|
|
|
|
var dragging = false
|
|
|
|
|
var s,
|
|
|
|
|
px, py
|
|
|
|
|
|
|
|
|
|
var elem = $(this)
|
|
|
|
|
.on('mousedown touchstart', function(evt){
|
|
|
|
|
dragging = true
|
|
|
|
|
px = evt.clientX
|
|
|
|
|
px = evt.clientY
|
|
|
|
|
|
|
|
|
|
s = elem.rscale()
|
|
|
|
|
})
|
|
|
|
|
.on('mousemove touchmove', function(evt){
|
|
|
|
|
if(!dragging){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var x = evt.clientX
|
|
|
|
|
var dx = px - x
|
|
|
|
|
px = x
|
|
|
|
|
|
|
|
|
|
var y = evt.clientY
|
|
|
|
|
var dy = py - y
|
|
|
|
|
py = y
|
|
|
|
|
|
|
|
|
|
elem
|
|
|
|
|
.velocity('stop')
|
|
|
|
|
.velocity({
|
|
|
|
|
translateX: '-=' + (dx / s),
|
|
|
|
|
translateY: '-=' + (dy / s),
|
|
|
|
|
}, 0)
|
|
|
|
|
})
|
|
|
|
|
.on('mouseup touchend', function(evt){
|
|
|
|
|
dragging = false
|
|
|
|
|
elem.velocity('stop')
|
|
|
|
|
})
|
|
|
|
|
}
|
2016-04-14 16:01:17 +03:00
|
|
|
|
2016-04-17 00:58:21 +03:00
|
|
|
|
2016-04-14 16:01:17 +03:00
|
|
|
jQuery.fn.selectText = function(){
|
|
|
|
|
var range = document.createRange()
|
|
|
|
|
|
|
|
|
|
this.each(function(){
|
|
|
|
|
range.selectNodeContents(this)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
var sel = window.getSelection()
|
|
|
|
|
sel.removeAllRanges()
|
|
|
|
|
sel.addRange(range)
|
|
|
|
|
|
|
|
|
|
return this
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-04-17 00:58:21 +03:00
|
|
|
var keyboard = require('lib/keyboard')
|
|
|
|
|
|
|
|
|
|
// Make element editable...
|
|
|
|
|
//
|
|
|
|
|
// Options format:
|
|
|
|
|
// {
|
|
|
|
|
// multiline: false,
|
|
|
|
|
//
|
|
|
|
|
// reset_on_abort: true,
|
|
|
|
|
// clear_on_edit: true,
|
|
|
|
|
//
|
|
|
|
|
// abort_keys: [
|
|
|
|
|
// 'Esc',
|
|
|
|
|
// ...
|
|
|
|
|
// ],
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// XXX should we just use form elements???
|
|
|
|
|
// ...it's a trade-off, here we add editing functionality and fight
|
|
|
|
|
// a bit the original function, in an input we'll need to fight part
|
|
|
|
|
// of the editing functionality and add our own navigation...
|
|
|
|
|
// XXX move this to a more generic spot...
|
|
|
|
|
jQuery.fn.makeEditable = function(options){
|
|
|
|
|
options = options || {}
|
|
|
|
|
var that = this
|
|
|
|
|
|
|
|
|
|
var original = this.text()
|
|
|
|
|
|
|
|
|
|
if(options.clear_on_edit == null || options.clear_on_edit){
|
|
|
|
|
this.text('')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this
|
|
|
|
|
.prop('contenteditable', true)
|
|
|
|
|
// make the element focusable and selectable...
|
|
|
|
|
.attr('tabindex', '0')
|
2016-04-19 02:42:21 +03:00
|
|
|
.addClass('editable-field')
|
2016-04-17 00:58:21 +03:00
|
|
|
// NOTE: this will also focus the element...
|
|
|
|
|
.selectText()
|
|
|
|
|
.keydown(function(){
|
|
|
|
|
if(!that.prop('contenteditable')){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event.stopPropagation()
|
|
|
|
|
|
|
|
|
|
var n = keyboard.toKeyName(event.keyCode)
|
|
|
|
|
|
|
|
|
|
// abort...
|
|
|
|
|
if((options.abort_keys || ['Esc']).indexOf(n) >= 0){
|
|
|
|
|
// reset original value...
|
|
|
|
|
(options.reset_on_abort == null || options.reset_on_abort)
|
|
|
|
|
&& that.text(original)
|
|
|
|
|
|
|
|
|
|
that
|
|
|
|
|
.trigger('edit-aborted', original)
|
|
|
|
|
|
|
|
|
|
// done -- single line...
|
|
|
|
|
} else if(n == 'Enter'
|
|
|
|
|
&& !options.multiline){
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
|
|
|
|
|
that.trigger('edit-done', that.text())
|
|
|
|
|
|
|
|
|
|
// done -- multiline...
|
|
|
|
|
} else if(n == 'Enter'
|
|
|
|
|
&& (event.ctrlKey || event.metaKey)
|
|
|
|
|
&& options.multiline){
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
|
|
|
|
|
that.trigger('edit-done', that.text())
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return this
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-12-23 07:09:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-04-14 16:01:17 +03:00
|
|
|
|
2015-12-17 03:34:20 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
* vim:set ts=4 sw=4 : */
|
|
|
|
|
return module })
|