Restructure of lib directory.
This commit is contained in:
parent
e27664ec1c
commit
c8b276ba38
25 changed files with 0 additions and 15369 deletions
|
@ -1,66 +0,0 @@
|
|||
$ = jQuery.sub()
|
||||
|
||||
class App.Com
|
||||
_instance = undefined # Must be declared here to force the closure on the class
|
||||
@ajax: (args) -> # Must be a static method
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
|
||||
_instance.ajax(args)
|
||||
_instance
|
||||
|
||||
# The actual Singleton class
|
||||
class _Singleton
|
||||
defaults:
|
||||
contentType: 'application/json'
|
||||
dataType: 'json'
|
||||
processData: false
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'}
|
||||
cache: false
|
||||
async: true
|
||||
|
||||
queue_list: {}
|
||||
count: 0
|
||||
|
||||
constructor: (@args) ->
|
||||
|
||||
# bindings
|
||||
$('body').bind( 'ajaxSend', =>
|
||||
@_show_spinner()
|
||||
).bind( 'ajaxComplete', =>
|
||||
@_hide_spinner()
|
||||
)
|
||||
|
||||
# show error messages
|
||||
$('body').bind( 'ajaxError', ( e, jqxhr, settings, exception ) ->
|
||||
status = jqxhr.status
|
||||
detail = jqxhr.responseText
|
||||
if !status && !detail
|
||||
detail = 'General communication error, maybe internet is not available!'
|
||||
new App.ErrorModal(
|
||||
message: 'StatusCode: ' + status
|
||||
detail: detail
|
||||
close: true
|
||||
)
|
||||
)
|
||||
|
||||
ajax: (params, defaults) ->
|
||||
data = $.extend({}, @defaults, defaults, params)
|
||||
if params['id']
|
||||
if @queue_list[ params['id'] ]
|
||||
@queue_list[ params['id'] ].abort()
|
||||
@queue_list[ params['id'] ] = $.ajax( data )
|
||||
else
|
||||
$.ajax( data )
|
||||
|
||||
# console.log('AJAX', params['url'] )
|
||||
|
||||
_show_spinner: =>
|
||||
@count++
|
||||
$('.spinner').show()
|
||||
|
||||
_hide_spinner: =>
|
||||
@count--
|
||||
if @count == 0
|
||||
$('.spinner').hide()
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
$ = jQuery.sub()
|
||||
|
||||
class App.Auth
|
||||
|
||||
@login: (params) ->
|
||||
console.log 'login(...)', params
|
||||
App.Com.ajax(
|
||||
id: 'login',
|
||||
type: 'POST',
|
||||
url: '/signin',
|
||||
data: JSON.stringify(params.data),
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# clear store
|
||||
App.Store.clear('all')
|
||||
|
||||
# execute callback
|
||||
params.success(data, status, xhr)
|
||||
|
||||
error: (xhr, statusText, error) =>
|
||||
params.error(xhr, statusText, error)
|
||||
)
|
||||
|
||||
@loginCheck: ->
|
||||
console.log 'loginCheck(...)'
|
||||
App.Com.ajax(
|
||||
id: 'login_check',
|
||||
async: false,
|
||||
type: 'GET',
|
||||
url: '/signshow',
|
||||
success: (data, status, xhr) =>
|
||||
console.log 'logincheck:success', data
|
||||
|
||||
# if session is not valid
|
||||
if data.error
|
||||
|
||||
# update config
|
||||
for key, value of data.config
|
||||
window.Config[key] = value
|
||||
|
||||
# empty session
|
||||
window.Session = {}
|
||||
|
||||
# update websocked auth info
|
||||
App.WebSocket.auth()
|
||||
|
||||
# rebuild navbar with new navbar items
|
||||
App.Event.trigger 'navrebuild'
|
||||
|
||||
return false;
|
||||
|
||||
# set avatar
|
||||
if !data.session.image
|
||||
data.session.image = 'http://placehold.it/48x48'
|
||||
|
||||
# update config
|
||||
for key, value of data.config
|
||||
window.Config[key] = value
|
||||
|
||||
# store user data
|
||||
for key, value of data.session
|
||||
window.Session[key] = value
|
||||
|
||||
# update websocked auth info
|
||||
App.WebSocket.auth()
|
||||
|
||||
# refresh/load default collections
|
||||
for key, value of data.default_collections
|
||||
App.Collection.reset( type: key, data: value )
|
||||
|
||||
# rebuild navbar with new navbar items
|
||||
App.Event.trigger 'navrebuild', data.session
|
||||
|
||||
# rebuild navbar with updated ticket count of overviews
|
||||
App.Event.trigger 'navupdate_remote'
|
||||
|
||||
error: (xhr, statusText, error) =>
|
||||
console.log 'loginCheck:error'#, error, statusText, xhr.statusCode
|
||||
|
||||
# empty session
|
||||
window.Session = {}
|
||||
|
||||
# clear store
|
||||
App.Store.clear('all')
|
||||
|
||||
# update websocked auth info
|
||||
App.WebSocket.auth()
|
||||
)
|
||||
|
||||
@logout: ->
|
||||
console.log 'logout(...)'
|
||||
App.Com.ajax(
|
||||
id: 'logout',
|
||||
type: 'DELETE',
|
||||
url: '/signout',
|
||||
success: =>
|
||||
|
||||
# update websocked auth info
|
||||
App.WebSocket.auth()
|
||||
|
||||
# clear store
|
||||
App.Store.clear('all')
|
||||
|
||||
error: (xhr, statusText, error) =>
|
||||
|
||||
# update websocked auth info
|
||||
App.WebSocket.auth()
|
||||
)
|
|
@ -1,179 +0,0 @@
|
|||
/*!
|
||||
* linkify - v0.3 - 6/27/2009
|
||||
* http://benalman.com/code/test/js-linkify/
|
||||
*
|
||||
* Copyright (c) 2009 "Cowboy" Ben Alman
|
||||
* Licensed under the MIT license
|
||||
* http://benalman.com/about/license/
|
||||
*
|
||||
* Some regexps adapted from http://userscripts.org/scripts/review/7122
|
||||
*/
|
||||
|
||||
// Turn text into linkified html.
|
||||
//
|
||||
// var html = linkify( text, options );
|
||||
//
|
||||
// options:
|
||||
//
|
||||
// callback (Function) - default: undefined - if defined, this will be called
|
||||
// for each link- or non-link-chunk with two arguments, text and href. If the
|
||||
// chunk is non-link, href will be omitted.
|
||||
//
|
||||
// punct_regexp (RegExp | Boolean) - a RegExp that can be used to trim trailing
|
||||
// punctuation from links, instead of the default.
|
||||
//
|
||||
// This is a work in progress, please let me know if (and how) it fails!
|
||||
|
||||
window.linkify = (function(){
|
||||
var
|
||||
SCHEME = "[a-z\\d.-]+://",
|
||||
IPV4 = "(?:(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.){3}(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])",
|
||||
HOSTNAME = "(?:(?:[^\\s!@#$%^&*()_=+[\\]{}\\\\|;:'\",.<>/?]+)\\.)+",
|
||||
TLD = "(?:ac|ad|aero|ae|af|ag|ai|al|am|an|ao|aq|arpa|ar|asia|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|biz|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|cat|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|coop|com|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|info|int|in|io|iq|ir|is|it|je|jm|jobs|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mil|mk|ml|mm|mn|mobi|mo|mp|mq|mr|ms|mt|museum|mu|mv|mw|mx|my|mz|name|na|nc|net|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pro|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tel|tf|tg|th|tj|tk|tl|tm|tn|to|tp|travel|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|xn--0zwm56d|xn--11b5bs3a9aj6g|xn--80akhbyknj4f|xn--9t4b11yi5a|xn--deba0ad|xn--g6w251d|xn--hgbk6aj7f53bba|xn--hlcj6aya9esc7a|xn--jxalpdlp|xn--kgbechtv|xn--zckzah|ye|yt|yu|za|zm|zw)",
|
||||
HOST_OR_IP = "(?:" + HOSTNAME + TLD + "|" + IPV4 + ")",
|
||||
PATH = "(?:[;/][^#?<>\\s]*)?",
|
||||
QUERY_FRAG = "(?:\\?[^#<>\\s]*)?(?:#[^<>\\s]*)?",
|
||||
URI1 = "\\b" + SCHEME + "[^<>\\s]+",
|
||||
URI2 = "\\b" + HOST_OR_IP + PATH + QUERY_FRAG + "(?!\\w)",
|
||||
|
||||
MAILTO = "mailto:",
|
||||
EMAIL = "(?:" + MAILTO + ")?[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@" + HOST_OR_IP + QUERY_FRAG + "(?!\\w)",
|
||||
|
||||
URI_RE = new RegExp( "(?:" + URI1 + "|" + URI2 + "|" + EMAIL + ")", "ig" ),
|
||||
SCHEME_RE = new RegExp( "^" + SCHEME, "i" ),
|
||||
|
||||
quotes = {
|
||||
"'": "`",
|
||||
'>': '<',
|
||||
')': '(',
|
||||
']': '[',
|
||||
'}': '{',
|
||||
'»': '«',
|
||||
'›': '‹'
|
||||
},
|
||||
|
||||
default_options = {
|
||||
callback: function( text, href ) {
|
||||
// return href ? '<a href="' + href + '" title="' + href + '">' + text + '<\/a>' : text;
|
||||
return href ? '<a href="' + href + '" title="' + href + '" target="_blank">' + text + '<\/a>' : text;
|
||||
},
|
||||
punct_regexp: /(?:[!?.,:;'"]|(?:&|&)(?:lt|gt|quot|apos|raquo|laquo|rsaquo|lsaquo);)$/
|
||||
};
|
||||
|
||||
return function( txt, options ) {
|
||||
options = options || {};
|
||||
|
||||
// me
|
||||
txt = txt
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
// me
|
||||
// Temp variables.
|
||||
var arr,
|
||||
i,
|
||||
link,
|
||||
href,
|
||||
|
||||
// Output HTML.
|
||||
html = '',
|
||||
|
||||
// Store text / link parts, in order, for re-combination.
|
||||
parts = [],
|
||||
|
||||
// Used for keeping track of indices in the text.
|
||||
idx_prev,
|
||||
idx_last,
|
||||
idx,
|
||||
link_last,
|
||||
|
||||
// Used for trimming trailing punctuation and quotes from links.
|
||||
matches_begin,
|
||||
matches_end,
|
||||
quote_begin,
|
||||
quote_end;
|
||||
|
||||
// Initialize options.
|
||||
for ( i in default_options ) {
|
||||
if ( options[ i ] === undefined ) {
|
||||
options[ i ] = default_options[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
// Find links.
|
||||
while ( arr = URI_RE.exec( txt ) ) {
|
||||
|
||||
link = arr[0];
|
||||
idx_last = URI_RE.lastIndex;
|
||||
idx = idx_last - link.length;
|
||||
|
||||
// Not a link if preceded by certain characters.
|
||||
if ( /[\/:]/.test( txt.charAt( idx - 1 ) ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Trim trailing punctuation.
|
||||
do {
|
||||
// If no changes are made, we don't want to loop forever!
|
||||
link_last = link;
|
||||
|
||||
quote_end = link.substr( -1 )
|
||||
quote_begin = quotes[ quote_end ];
|
||||
|
||||
// Ending quote character?
|
||||
if ( quote_begin ) {
|
||||
matches_begin = link.match( new RegExp( '\\' + quote_begin + '(?!$)', 'g' ) );
|
||||
matches_end = link.match( new RegExp( '\\' + quote_end, 'g' ) );
|
||||
|
||||
// If quotes are unbalanced, remove trailing quote character.
|
||||
if ( ( matches_begin ? matches_begin.length : 0 ) < ( matches_end ? matches_end.length : 0 ) ) {
|
||||
link = link.substr( 0, link.length - 1 );
|
||||
idx_last--;
|
||||
}
|
||||
}
|
||||
|
||||
// Ending non-quote punctuation character?
|
||||
if ( options.punct_regexp ) {
|
||||
link = link.replace( options.punct_regexp, function(a){
|
||||
idx_last -= a.length;
|
||||
return '';
|
||||
});
|
||||
}
|
||||
} while ( link.length && link !== link_last );
|
||||
|
||||
href = link;
|
||||
|
||||
// Add appropriate protocol to naked links.
|
||||
if ( !SCHEME_RE.test( href ) ) {
|
||||
href = ( href.indexOf( '@' ) !== -1 ? ( !href.indexOf( MAILTO ) ? '' : MAILTO )
|
||||
: !href.indexOf( 'irc.' ) ? 'irc://'
|
||||
: !href.indexOf( 'ftp.' ) ? 'ftp://'
|
||||
: 'http://' )
|
||||
+ href;
|
||||
}
|
||||
|
||||
// Push preceding non-link text onto the array.
|
||||
if ( idx_prev != idx ) {
|
||||
parts.push([ txt.slice( idx_prev, idx ) ]);
|
||||
idx_prev = idx_last;
|
||||
}
|
||||
|
||||
// Push massaged link onto the array
|
||||
parts.push([ link, href ]);
|
||||
};
|
||||
|
||||
// Push remaining non-link text onto the array.
|
||||
parts.push([ txt.substr( idx_prev ) ]);
|
||||
|
||||
// Process the array items.
|
||||
for ( i = 0; i < parts.length; i++ ) {
|
||||
html += options.callback.apply( window, parts[i] );
|
||||
}
|
||||
|
||||
// In case of catastrophic failure, return the original text;
|
||||
return html || txt;
|
||||
};
|
||||
|
||||
})();
|
100
app/assets/javascripts/app/lib/bootstrap-dropdown.js
vendored
100
app/assets/javascripts/app/lib/bootstrap-dropdown.js
vendored
|
@ -1,100 +0,0 @@
|
|||
/* ============================================================
|
||||
* bootstrap-dropdown.js v2.0.4
|
||||
* http://twitter.github.com/bootstrap/javascript.html#dropdowns
|
||||
* ============================================================
|
||||
* Copyright 2012 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ============================================================ */
|
||||
|
||||
|
||||
!function ($) {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
|
||||
/* DROPDOWN CLASS DEFINITION
|
||||
* ========================= */
|
||||
|
||||
var toggle = '[data-toggle="dropdown"]'
|
||||
, Dropdown = function (element) {
|
||||
var $el = $(element).on('click.dropdown.data-api', this.toggle)
|
||||
$('html').on('click.dropdown.data-api', function () {
|
||||
$el.parent().removeClass('open')
|
||||
})
|
||||
}
|
||||
|
||||
Dropdown.prototype = {
|
||||
|
||||
constructor: Dropdown
|
||||
|
||||
, toggle: function (e) {
|
||||
var $this = $(this)
|
||||
, $parent
|
||||
, selector
|
||||
, isActive
|
||||
|
||||
if ($this.is('.disabled, :disabled')) return
|
||||
|
||||
selector = $this.attr('data-target')
|
||||
|
||||
if (!selector) {
|
||||
selector = $this.attr('href')
|
||||
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
|
||||
}
|
||||
|
||||
$parent = $(selector)
|
||||
$parent.length || ($parent = $this.parent())
|
||||
|
||||
isActive = $parent.hasClass('open')
|
||||
|
||||
clearMenus()
|
||||
|
||||
if (!isActive) $parent.toggleClass('open')
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function clearMenus() {
|
||||
$(toggle).parent().removeClass('open')
|
||||
}
|
||||
|
||||
|
||||
/* DROPDOWN PLUGIN DEFINITION
|
||||
* ========================== */
|
||||
|
||||
$.fn.dropdown = function (option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
, data = $this.data('dropdown')
|
||||
if (!data) $this.data('dropdown', (data = new Dropdown(this)))
|
||||
if (typeof option == 'string') data[option].call($this)
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.dropdown.Constructor = Dropdown
|
||||
|
||||
|
||||
/* APPLY TO STANDARD DROPDOWN ELEMENTS
|
||||
* =================================== */
|
||||
|
||||
$(function () {
|
||||
$('html').on('click.dropdown.data-api', clearMenus)
|
||||
$('body')
|
||||
.on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() })
|
||||
.on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
|
||||
})
|
||||
|
||||
}(window.jQuery);
|
218
app/assets/javascripts/app/lib/bootstrap-modal.js
vendored
218
app/assets/javascripts/app/lib/bootstrap-modal.js
vendored
|
@ -1,218 +0,0 @@
|
|||
/* =========================================================
|
||||
* bootstrap-modal.js v2.0.4
|
||||
* http://twitter.github.com/bootstrap/javascript.html#modals
|
||||
* =========================================================
|
||||
* Copyright 2012 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================= */
|
||||
|
||||
|
||||
!function ($) {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
|
||||
/* MODAL CLASS DEFINITION
|
||||
* ====================== */
|
||||
|
||||
var Modal = function (content, options) {
|
||||
this.options = options
|
||||
this.$element = $(content)
|
||||
.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
|
||||
}
|
||||
|
||||
Modal.prototype = {
|
||||
|
||||
constructor: Modal
|
||||
|
||||
, toggle: function () {
|
||||
return this[!this.isShown ? 'show' : 'hide']()
|
||||
}
|
||||
|
||||
, show: function () {
|
||||
var that = this
|
||||
, e = $.Event('show')
|
||||
|
||||
this.$element.trigger(e)
|
||||
|
||||
if (this.isShown || e.isDefaultPrevented()) return
|
||||
|
||||
$('body').addClass('modal-open')
|
||||
|
||||
this.isShown = true
|
||||
|
||||
escape.call(this)
|
||||
backdrop.call(this, function () {
|
||||
var transition = $.support.transition && that.$element.hasClass('fade')
|
||||
|
||||
if (!that.$element.parent().length) {
|
||||
that.$element.appendTo(document.body) //don't move modals dom position
|
||||
}
|
||||
|
||||
that.$element
|
||||
.show()
|
||||
|
||||
if (transition) {
|
||||
that.$element[0].offsetWidth // force reflow
|
||||
}
|
||||
|
||||
that.$element.addClass('in')
|
||||
|
||||
transition ?
|
||||
that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
|
||||
that.$element.trigger('shown')
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
, hide: function (e) {
|
||||
e && e.preventDefault()
|
||||
|
||||
var that = this
|
||||
|
||||
e = $.Event('hide')
|
||||
|
||||
this.$element.trigger(e)
|
||||
|
||||
if (!this.isShown || e.isDefaultPrevented()) return
|
||||
|
||||
this.isShown = false
|
||||
|
||||
$('body').removeClass('modal-open')
|
||||
|
||||
escape.call(this)
|
||||
|
||||
this.$element.removeClass('in')
|
||||
|
||||
$.support.transition && this.$element.hasClass('fade') ?
|
||||
hideWithTransition.call(this) :
|
||||
hideModal.call(this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* MODAL PRIVATE METHODS
|
||||
* ===================== */
|
||||
|
||||
function hideWithTransition() {
|
||||
var that = this
|
||||
, timeout = setTimeout(function () {
|
||||
that.$element.off($.support.transition.end)
|
||||
hideModal.call(that)
|
||||
}, 500)
|
||||
|
||||
this.$element.one($.support.transition.end, function () {
|
||||
clearTimeout(timeout)
|
||||
hideModal.call(that)
|
||||
})
|
||||
}
|
||||
|
||||
function hideModal(that) {
|
||||
this.$element
|
||||
.hide()
|
||||
.trigger('hidden')
|
||||
|
||||
backdrop.call(this)
|
||||
}
|
||||
|
||||
function backdrop(callback) {
|
||||
var that = this
|
||||
, animate = this.$element.hasClass('fade') ? 'fade' : ''
|
||||
|
||||
if (this.isShown && this.options.backdrop) {
|
||||
var doAnimate = $.support.transition && animate
|
||||
|
||||
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
|
||||
.appendTo(document.body)
|
||||
|
||||
if (this.options.backdrop != 'static') {
|
||||
this.$backdrop.click($.proxy(this.hide, this))
|
||||
}
|
||||
|
||||
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
|
||||
|
||||
this.$backdrop.addClass('in')
|
||||
|
||||
doAnimate ?
|
||||
this.$backdrop.one($.support.transition.end, callback) :
|
||||
callback()
|
||||
|
||||
} else if (!this.isShown && this.$backdrop) {
|
||||
this.$backdrop.removeClass('in')
|
||||
|
||||
$.support.transition && this.$element.hasClass('fade')?
|
||||
this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
|
||||
removeBackdrop.call(this)
|
||||
|
||||
} else if (callback) {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
function removeBackdrop() {
|
||||
this.$backdrop.remove()
|
||||
this.$backdrop = null
|
||||
}
|
||||
|
||||
function escape() {
|
||||
var that = this
|
||||
if (this.isShown && this.options.keyboard) {
|
||||
$(document).on('keyup.dismiss.modal', function ( e ) {
|
||||
e.which == 27 && that.hide()
|
||||
})
|
||||
} else if (!this.isShown) {
|
||||
$(document).off('keyup.dismiss.modal')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* MODAL PLUGIN DEFINITION
|
||||
* ======================= */
|
||||
|
||||
$.fn.modal = function (option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
, data = $this.data('modal')
|
||||
, options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('modal', (data = new Modal(this, options)))
|
||||
if (typeof option == 'string') data[option]()
|
||||
else if (options.show) data.show()
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.modal.defaults = {
|
||||
backdrop: true
|
||||
, keyboard: true
|
||||
, show: true
|
||||
}
|
||||
|
||||
$.fn.modal.Constructor = Modal
|
||||
|
||||
|
||||
/* MODAL DATA-API
|
||||
* ============== */
|
||||
|
||||
$(function () {
|
||||
$('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
|
||||
var $this = $(this), href
|
||||
, $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
|
||||
, option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
|
||||
|
||||
e.preventDefault()
|
||||
$target.modal(option)
|
||||
})
|
||||
})
|
||||
|
||||
}(window.jQuery);
|
|
@ -1,98 +0,0 @@
|
|||
/* ===========================================================
|
||||
* bootstrap-popover.js v2.0.4
|
||||
* http://twitter.github.com/bootstrap/javascript.html#popovers
|
||||
* ===========================================================
|
||||
* Copyright 2012 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* =========================================================== */
|
||||
|
||||
|
||||
!function ($) {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
|
||||
/* POPOVER PUBLIC CLASS DEFINITION
|
||||
* =============================== */
|
||||
|
||||
var Popover = function ( element, options ) {
|
||||
this.init('popover', element, options)
|
||||
}
|
||||
|
||||
|
||||
/* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
|
||||
========================================== */
|
||||
|
||||
Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
|
||||
|
||||
constructor: Popover
|
||||
|
||||
, setContent: function () {
|
||||
var $tip = this.tip()
|
||||
, title = this.getTitle()
|
||||
, content = this.getContent()
|
||||
|
||||
$tip.find('.popover-title')[this.isHTML(title) ? 'html' : 'text'](title)
|
||||
$tip.find('.popover-content > *')[this.isHTML(content) ? 'html' : 'text'](content)
|
||||
|
||||
$tip.removeClass('fade top bottom left right in')
|
||||
}
|
||||
|
||||
, hasContent: function () {
|
||||
return this.getTitle() || this.getContent()
|
||||
}
|
||||
|
||||
, getContent: function () {
|
||||
var content
|
||||
, $e = this.$element
|
||||
, o = this.options
|
||||
|
||||
content = $e.attr('data-content')
|
||||
|| (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
, tip: function () {
|
||||
if (!this.$tip) {
|
||||
this.$tip = $(this.options.template)
|
||||
}
|
||||
return this.$tip
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
/* POPOVER PLUGIN DEFINITION
|
||||
* ======================= */
|
||||
|
||||
$.fn.popover = function (option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
, data = $this.data('popover')
|
||||
, options = typeof option == 'object' && option
|
||||
if (!data) $this.data('popover', (data = new Popover(this, options)))
|
||||
if (typeof option == 'string') data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.popover.Constructor = Popover
|
||||
|
||||
$.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
|
||||
placement: 'right'
|
||||
, content: ''
|
||||
, template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
|
||||
})
|
||||
|
||||
}(window.jQuery);
|
135
app/assets/javascripts/app/lib/bootstrap-tab.js
vendored
135
app/assets/javascripts/app/lib/bootstrap-tab.js
vendored
|
@ -1,135 +0,0 @@
|
|||
/* ========================================================
|
||||
* bootstrap-tab.js v2.0.4
|
||||
* http://twitter.github.com/bootstrap/javascript.html#tabs
|
||||
* ========================================================
|
||||
* Copyright 2012 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ======================================================== */
|
||||
|
||||
|
||||
!function ($) {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
|
||||
/* TAB CLASS DEFINITION
|
||||
* ==================== */
|
||||
|
||||
var Tab = function ( element ) {
|
||||
this.element = $(element)
|
||||
}
|
||||
|
||||
Tab.prototype = {
|
||||
|
||||
constructor: Tab
|
||||
|
||||
, show: function () {
|
||||
var $this = this.element
|
||||
, $ul = $this.closest('ul:not(.dropdown-menu)')
|
||||
, selector = $this.attr('data-target')
|
||||
, previous
|
||||
, $target
|
||||
, e
|
||||
|
||||
if (!selector) {
|
||||
selector = $this.attr('href')
|
||||
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
|
||||
}
|
||||
|
||||
if ( $this.parent('li').hasClass('active') ) return
|
||||
|
||||
previous = $ul.find('.active a').last()[0]
|
||||
|
||||
e = $.Event('show', {
|
||||
relatedTarget: previous
|
||||
})
|
||||
|
||||
$this.trigger(e)
|
||||
|
||||
if (e.isDefaultPrevented()) return
|
||||
|
||||
$target = $(selector)
|
||||
|
||||
this.activate($this.parent('li'), $ul)
|
||||
this.activate($target, $target.parent(), function () {
|
||||
$this.trigger({
|
||||
type: 'shown'
|
||||
, relatedTarget: previous
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
, activate: function ( element, container, callback) {
|
||||
var $active = container.find('> .active')
|
||||
, transition = callback
|
||||
&& $.support.transition
|
||||
&& $active.hasClass('fade')
|
||||
|
||||
function next() {
|
||||
$active
|
||||
.removeClass('active')
|
||||
.find('> .dropdown-menu > .active')
|
||||
.removeClass('active')
|
||||
|
||||
element.addClass('active')
|
||||
|
||||
if (transition) {
|
||||
element[0].offsetWidth // reflow for transition
|
||||
element.addClass('in')
|
||||
} else {
|
||||
element.removeClass('fade')
|
||||
}
|
||||
|
||||
if ( element.parent('.dropdown-menu') ) {
|
||||
element.closest('li.dropdown').addClass('active')
|
||||
}
|
||||
|
||||
callback && callback()
|
||||
}
|
||||
|
||||
transition ?
|
||||
$active.one($.support.transition.end, next) :
|
||||
next()
|
||||
|
||||
$active.removeClass('in')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TAB PLUGIN DEFINITION
|
||||
* ===================== */
|
||||
|
||||
$.fn.tab = function ( option ) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
, data = $this.data('tab')
|
||||
if (!data) $this.data('tab', (data = new Tab(this)))
|
||||
if (typeof option == 'string') data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.tab.Constructor = Tab
|
||||
|
||||
|
||||
/* TAB DATA-API
|
||||
* ============ */
|
||||
|
||||
$(function () {
|
||||
$('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
|
||||
e.preventDefault()
|
||||
$(this).tab('show')
|
||||
})
|
||||
})
|
||||
|
||||
}(window.jQuery);
|
275
app/assets/javascripts/app/lib/bootstrap-tooltip.js
vendored
275
app/assets/javascripts/app/lib/bootstrap-tooltip.js
vendored
|
@ -1,275 +0,0 @@
|
|||
/* ===========================================================
|
||||
* bootstrap-tooltip.js v2.0.4
|
||||
* http://twitter.github.com/bootstrap/javascript.html#tooltips
|
||||
* Inspired by the original jQuery.tipsy by Jason Frame
|
||||
* ===========================================================
|
||||
* Copyright 2012 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================== */
|
||||
|
||||
|
||||
!function ($) {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
|
||||
/* TOOLTIP PUBLIC CLASS DEFINITION
|
||||
* =============================== */
|
||||
|
||||
var Tooltip = function (element, options) {
|
||||
this.init('tooltip', element, options)
|
||||
}
|
||||
|
||||
Tooltip.prototype = {
|
||||
|
||||
constructor: Tooltip
|
||||
|
||||
, init: function (type, element, options) {
|
||||
var eventIn
|
||||
, eventOut
|
||||
|
||||
this.type = type
|
||||
this.$element = $(element)
|
||||
this.options = this.getOptions(options)
|
||||
this.enabled = true
|
||||
|
||||
if (this.options.trigger != 'manual') {
|
||||
eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
|
||||
eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
|
||||
this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
|
||||
this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
|
||||
}
|
||||
|
||||
this.options.selector ?
|
||||
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
|
||||
this.fixTitle()
|
||||
}
|
||||
|
||||
, getOptions: function (options) {
|
||||
options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
|
||||
|
||||
if (options.delay && typeof options.delay == 'number') {
|
||||
options.delay = {
|
||||
show: options.delay
|
||||
, hide: options.delay
|
||||
}
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
, enter: function (e) {
|
||||
var self = $(e.currentTarget)[this.type](this._options).data(this.type)
|
||||
|
||||
if (!self.options.delay || !self.options.delay.show) return self.show()
|
||||
|
||||
clearTimeout(this.timeout)
|
||||
self.hoverState = 'in'
|
||||
this.timeout = setTimeout(function() {
|
||||
if (self.hoverState == 'in') self.show()
|
||||
}, self.options.delay.show)
|
||||
}
|
||||
|
||||
, leave: function (e) {
|
||||
var self = $(e.currentTarget)[this.type](this._options).data(this.type)
|
||||
|
||||
if (this.timeout) clearTimeout(this.timeout)
|
||||
if (!self.options.delay || !self.options.delay.hide) return self.hide()
|
||||
|
||||
self.hoverState = 'out'
|
||||
this.timeout = setTimeout(function() {
|
||||
if (self.hoverState == 'out') self.hide()
|
||||
}, self.options.delay.hide)
|
||||
}
|
||||
|
||||
, show: function () {
|
||||
var $tip
|
||||
, inside
|
||||
, pos
|
||||
, actualWidth
|
||||
, actualHeight
|
||||
, placement
|
||||
, tp
|
||||
|
||||
if (this.hasContent() && this.enabled) {
|
||||
$tip = this.tip()
|
||||
this.setContent()
|
||||
|
||||
if (this.options.animation) {
|
||||
$tip.addClass('fade')
|
||||
}
|
||||
|
||||
placement = typeof this.options.placement == 'function' ?
|
||||
this.options.placement.call(this, $tip[0], this.$element[0]) :
|
||||
this.options.placement
|
||||
|
||||
inside = /in/.test(placement)
|
||||
|
||||
$tip
|
||||
.remove()
|
||||
.css({ top: 0, left: 0, display: 'block' })
|
||||
.appendTo(inside ? this.$element : document.body)
|
||||
|
||||
pos = this.getPosition(inside)
|
||||
|
||||
actualWidth = $tip[0].offsetWidth
|
||||
actualHeight = $tip[0].offsetHeight
|
||||
|
||||
switch (inside ? placement.split(' ')[1] : placement) {
|
||||
case 'bottom':
|
||||
tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||
break
|
||||
case 'top':
|
||||
tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
|
||||
break
|
||||
case 'left':
|
||||
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
|
||||
break
|
||||
case 'right':
|
||||
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
|
||||
break
|
||||
}
|
||||
|
||||
$tip
|
||||
.css(tp)
|
||||
.addClass(placement)
|
||||
.addClass('in')
|
||||
}
|
||||
}
|
||||
|
||||
, isHTML: function(text) {
|
||||
// html string detection logic adapted from jQuery
|
||||
return typeof text != 'string'
|
||||
|| ( text.charAt(0) === "<"
|
||||
&& text.charAt( text.length - 1 ) === ">"
|
||||
&& text.length >= 3
|
||||
) || /^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(text)
|
||||
}
|
||||
|
||||
, setContent: function () {
|
||||
var $tip = this.tip()
|
||||
, title = this.getTitle()
|
||||
|
||||
$tip.find('.tooltip-inner')[this.isHTML(title) ? 'html' : 'text'](title)
|
||||
$tip.removeClass('fade in top bottom left right')
|
||||
}
|
||||
|
||||
, hide: function () {
|
||||
var that = this
|
||||
, $tip = this.tip()
|
||||
|
||||
$tip.removeClass('in')
|
||||
|
||||
function removeWithAnimation() {
|
||||
var timeout = setTimeout(function () {
|
||||
$tip.off($.support.transition.end).remove()
|
||||
}, 500)
|
||||
|
||||
$tip.one($.support.transition.end, function () {
|
||||
clearTimeout(timeout)
|
||||
$tip.remove()
|
||||
})
|
||||
}
|
||||
|
||||
$.support.transition && this.$tip.hasClass('fade') ?
|
||||
removeWithAnimation() :
|
||||
$tip.remove()
|
||||
}
|
||||
|
||||
, fixTitle: function () {
|
||||
var $e = this.$element
|
||||
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
|
||||
$e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
|
||||
}
|
||||
}
|
||||
|
||||
, hasContent: function () {
|
||||
return this.getTitle()
|
||||
}
|
||||
|
||||
, getPosition: function (inside) {
|
||||
return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
|
||||
width: this.$element[0].offsetWidth
|
||||
, height: this.$element[0].offsetHeight
|
||||
})
|
||||
}
|
||||
|
||||
, getTitle: function () {
|
||||
var title
|
||||
, $e = this.$element
|
||||
, o = this.options
|
||||
|
||||
title = $e.attr('data-original-title')
|
||||
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
|
||||
|
||||
return title
|
||||
}
|
||||
|
||||
, tip: function () {
|
||||
return this.$tip = this.$tip || $(this.options.template)
|
||||
}
|
||||
|
||||
, validate: function () {
|
||||
if (!this.$element[0].parentNode) {
|
||||
this.hide()
|
||||
this.$element = null
|
||||
this.options = null
|
||||
}
|
||||
}
|
||||
|
||||
, enable: function () {
|
||||
this.enabled = true
|
||||
}
|
||||
|
||||
, disable: function () {
|
||||
this.enabled = false
|
||||
}
|
||||
|
||||
, toggleEnabled: function () {
|
||||
this.enabled = !this.enabled
|
||||
}
|
||||
|
||||
, toggle: function () {
|
||||
this[this.tip().hasClass('in') ? 'hide' : 'show']()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* TOOLTIP PLUGIN DEFINITION
|
||||
* ========================= */
|
||||
|
||||
$.fn.tooltip = function ( option ) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
, data = $this.data('tooltip')
|
||||
, options = typeof option == 'object' && option
|
||||
if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
|
||||
if (typeof option == 'string') data[option]()
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.tooltip.Constructor = Tooltip
|
||||
|
||||
$.fn.tooltip.defaults = {
|
||||
animation: true
|
||||
, placement: 'top'
|
||||
, selector: false
|
||||
, template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
|
||||
, trigger: 'hover'
|
||||
, title: ''
|
||||
, delay: 0
|
||||
}
|
||||
|
||||
}(window.jQuery);
|
|
@ -1,61 +0,0 @@
|
|||
/* ===================================================
|
||||
* bootstrap-transition.js v2.0.4
|
||||
* http://twitter.github.com/bootstrap/javascript.html#transitions
|
||||
* ===================================================
|
||||
* Copyright 2012 Twitter, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================== */
|
||||
|
||||
|
||||
!function ($) {
|
||||
|
||||
$(function () {
|
||||
|
||||
"use strict"; // jshint ;_;
|
||||
|
||||
|
||||
/* CSS TRANSITION SUPPORT (http://www.modernizr.com/)
|
||||
* ======================================================= */
|
||||
|
||||
$.support.transition = (function () {
|
||||
|
||||
var transitionEnd = (function () {
|
||||
|
||||
var el = document.createElement('bootstrap')
|
||||
, transEndEventNames = {
|
||||
'WebkitTransition' : 'webkitTransitionEnd'
|
||||
, 'MozTransition' : 'transitionend'
|
||||
, 'OTransition' : 'oTransitionEnd'
|
||||
, 'msTransition' : 'MSTransitionEnd'
|
||||
, 'transition' : 'transitionend'
|
||||
}
|
||||
, name
|
||||
|
||||
for (name in transEndEventNames){
|
||||
if (el.style[name] !== undefined) {
|
||||
return transEndEventNames[name]
|
||||
}
|
||||
}
|
||||
|
||||
}())
|
||||
|
||||
return transitionEnd && {
|
||||
end: transitionEnd
|
||||
}
|
||||
|
||||
})()
|
||||
|
||||
})
|
||||
|
||||
}(window.jQuery);
|
|
@ -1,181 +0,0 @@
|
|||
class App.ClipBoard
|
||||
_instance = undefined
|
||||
|
||||
@bind: (el) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.bind(el)
|
||||
|
||||
@getSelected: ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.getSelected()
|
||||
|
||||
@getSelectedLast: ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.getSelectedLast()
|
||||
|
||||
@keycode: (code) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.keycode(code)
|
||||
|
||||
class _Singleton
|
||||
constructor: ->
|
||||
@selection = ''
|
||||
@selectionLast = ''
|
||||
|
||||
# bind to fill selected text into
|
||||
bind: (el) ->
|
||||
$(el).bind('mouseup', =>
|
||||
|
||||
# check selection on mouse up
|
||||
@selection = @_getSelected()
|
||||
if @selection
|
||||
@selectionLast = @selection
|
||||
)
|
||||
$(el).bind('keyup', (e) =>
|
||||
|
||||
# check selection on sonder key
|
||||
if e.keyCode == 91
|
||||
@selection = @_getSelected()
|
||||
if @selection
|
||||
@selectionLast = @selection
|
||||
|
||||
# check selection of arrow keys
|
||||
if e.keyCode == 37 || e.keyCode == 38 || e.keyCode == 39 || e.keyCode == 40
|
||||
@selection = @_getSelected()
|
||||
if @selection
|
||||
@selectionLast = @selection
|
||||
)
|
||||
|
||||
# get cross browser selected string
|
||||
_getSelected: ->
|
||||
text = '';
|
||||
if window.getSelection
|
||||
text = window.getSelection()
|
||||
else if document.getSelection
|
||||
text = document.getSelection()
|
||||
else if document.selection
|
||||
text = document.selection.createRange().text
|
||||
if text
|
||||
text = text.toString().trim()
|
||||
text
|
||||
|
||||
# get current selection
|
||||
getSelected: ->
|
||||
@selection
|
||||
|
||||
# get latest selection
|
||||
getSelectedLast: ->
|
||||
@selectionLast
|
||||
|
||||
keycode: (code) ->
|
||||
for key, value of @keycodesTable()
|
||||
if value.toString() is code.toString()
|
||||
return key
|
||||
|
||||
keycodesTable: ->
|
||||
map = {
|
||||
'backspace' : 8,
|
||||
'tab' : 9,
|
||||
'enter' : 13,
|
||||
'shift' : 16,
|
||||
'ctrl' : 17,
|
||||
'alt' : 18,
|
||||
'space' : 32,
|
||||
'pause_break' : '19',
|
||||
'caps_lock' : '20',
|
||||
'escape' : '27',
|
||||
'page_up' : '33',
|
||||
'page down' : '34',
|
||||
'end' : '35',
|
||||
'home' : '36',
|
||||
'left_arrow' : '37',
|
||||
'up_arrow' : '38',
|
||||
'right_arrow' : '39',
|
||||
'down_arrow' : '40',
|
||||
'insert' : '45',
|
||||
'delete' : '46',
|
||||
'0' : '48',
|
||||
'1' : '49',
|
||||
'2' : '50',
|
||||
'3' : '51',
|
||||
'4' : '52',
|
||||
'5' : '53',
|
||||
'6' : '54',
|
||||
'7' : '55',
|
||||
'8' : '56',
|
||||
'9' : '57',
|
||||
'a' : '65',
|
||||
'b' : '66',
|
||||
'c' : '67',
|
||||
'd' : '68',
|
||||
'e' : '69',
|
||||
'f' : '70',
|
||||
'g' : '71',
|
||||
'h' : '72',
|
||||
'i' : '73',
|
||||
'j' : '74',
|
||||
'k' : '75',
|
||||
'l' : '76',
|
||||
'm' : '77',
|
||||
'n' : '78',
|
||||
'o' : '79',
|
||||
'p' : '80',
|
||||
'q' : '81',
|
||||
'r' : '82',
|
||||
's' : '83',
|
||||
't' : '84',
|
||||
'u' : '85',
|
||||
'v' : '86',
|
||||
'w' : '87',
|
||||
'x' : '88',
|
||||
'y' : '89',
|
||||
'z' : '90',
|
||||
'left_window key' : '91',
|
||||
'right_window key' : '92',
|
||||
'select_key' : '93',
|
||||
'numpad 0' : '96',
|
||||
'numpad 1' : '97',
|
||||
'numpad 2' : '98',
|
||||
'numpad 3' : '99',
|
||||
'numpad 4' : '100',
|
||||
'numpad 5' : '101',
|
||||
'numpad 6' : '102',
|
||||
'numpad 7' : '103',
|
||||
'numpad 8' : '104',
|
||||
'numpad 9' : '105',
|
||||
'multiply' : '106',
|
||||
'add' : '107',
|
||||
'subtract' : '109',
|
||||
'decimal point' : '110',
|
||||
'divide' : '111',
|
||||
'f1' : '112',
|
||||
'f2' : '113',
|
||||
'f3' : '114',
|
||||
'f4' : '115',
|
||||
'f5' : '116',
|
||||
'f6' : '117',
|
||||
'f7' : '118',
|
||||
'f8' : '119',
|
||||
'f9' : '120',
|
||||
'f10' : '121',
|
||||
'f11' : '122',
|
||||
'f12' : '123',
|
||||
'num_lock' : '144',
|
||||
'scroll_lock' : '145',
|
||||
'semi_colon' : '186',
|
||||
'equal_sign' : '187',
|
||||
'comma' : '188',
|
||||
'dash' : '189',
|
||||
'period' : '190',
|
||||
'forward_slash' : '191',
|
||||
'grave_accent' : '192',
|
||||
'open_bracket' : '219',
|
||||
'backslash' : '220',
|
||||
'closebracket' : '221',
|
||||
'single_quote' : '222'
|
||||
}
|
||||
map
|
|
@ -1,363 +0,0 @@
|
|||
class App.Collection
|
||||
_instance = undefined
|
||||
|
||||
@init: ->
|
||||
_instance = new _Singleton
|
||||
|
||||
@load: ( args ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.load( args )
|
||||
|
||||
@reset: ( args ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.reset( args )
|
||||
|
||||
@find: ( type, id, callback, force ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.find( type, id, callback, force )
|
||||
|
||||
@get: ( args ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.get( args )
|
||||
|
||||
@all: ( type ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.all( type )
|
||||
|
||||
@deleteAll: ( type ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.deleteAll( type )
|
||||
|
||||
@findByAttribute: ( type, key, value ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.findByAttribute( type, key, value )
|
||||
|
||||
@count: ( type ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.count( type )
|
||||
|
||||
@fetch: ( type ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.fetch( type )
|
||||
|
||||
@observe: (args) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.observe(args)
|
||||
|
||||
@observeUnbindLevel: (level) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.observeUnbindLevel(level)
|
||||
|
||||
@_observeStats: ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance._observeStats()
|
||||
|
||||
class _Singleton
|
||||
|
||||
constructor: (@args) ->
|
||||
|
||||
# add trigger - bind new events
|
||||
App.Event.bind 'loadCollection', (data) =>
|
||||
|
||||
# load collections
|
||||
if data.collections
|
||||
for type of data.collections
|
||||
|
||||
console.log 'loadCollection:trigger', type, data.collections[type]
|
||||
@load( localStorage: data.localStorage, type: type, data: data.collections[type] )
|
||||
|
||||
# add trigger - bind new events
|
||||
App.Event.bind 'resetCollection', (data) =>
|
||||
|
||||
# load collections
|
||||
if data.collections
|
||||
for type of data.collections
|
||||
|
||||
console.log 'resetCollection:trigger', type, data.collections[type]
|
||||
@reset( localStorage: data.localStorage, type: type, data: data.collections[type] )
|
||||
|
||||
# find collections to load
|
||||
@_loadCollectionAll()
|
||||
|
||||
_loadCollectionAll: ->
|
||||
list = App.Store.list()
|
||||
for key in list
|
||||
parts = key.split('::')
|
||||
if parts[0] is 'collection'
|
||||
data = App.Store.get( key )
|
||||
if data && data.localStorage
|
||||
console.log('load INIT', data)
|
||||
@load( data )
|
||||
|
||||
reset: (params) ->
|
||||
console.log( 'reset', params )
|
||||
|
||||
# empty in-memory
|
||||
App[ params.type ].refresh( [], { clear: true } )
|
||||
|
||||
# remove permanent storage
|
||||
list = App.Store.list()
|
||||
for key in list
|
||||
parts = key.split('::')
|
||||
if parts[0] is 'collection' && parts[1] is params.type
|
||||
App.Store.delete(key)
|
||||
|
||||
# load with new data
|
||||
@load(params)
|
||||
|
||||
load: (params) ->
|
||||
console.log( 'load', params )
|
||||
|
||||
return if _.isEmpty( params.data )
|
||||
|
||||
localStorage = params.localStorage
|
||||
|
||||
# load full array once
|
||||
if _.isArray( params.data )
|
||||
# console.log( 'load ARRAY', params.data)
|
||||
App[ params.type ].refresh( params.data )
|
||||
|
||||
# remember in store if not already requested from local storage
|
||||
if !localStorage
|
||||
for object in params.data
|
||||
App.Store.write( 'collection::' + params.type + '::' + object.id, { type: params.type, localStorage: true, data: [ object ] } )
|
||||
return
|
||||
|
||||
# load data from object
|
||||
# if _.isObject( params.data )
|
||||
for key, object of params.data
|
||||
# console.log( 'load OB', object)
|
||||
App[ params.type ].refresh( object )
|
||||
|
||||
# remember in store if not already requested from local storage
|
||||
if !localStorage
|
||||
App.Store.write( 'collection::' + params.type + '::' + object.id, { type: params.type, localStorage: true, data: [ object ] } )
|
||||
|
||||
find: ( type, id, callback, force ) ->
|
||||
|
||||
# console.log( 'find', type, id, force )
|
||||
# if App[type].exists( id ) && !callback
|
||||
if !force && App[type].exists( id )
|
||||
# console.log( 'find exists', type, id )
|
||||
data = App[type].find( id )
|
||||
if callback
|
||||
callback( data )
|
||||
else
|
||||
if force
|
||||
console.log( 'find forced to load!', type, id )
|
||||
else
|
||||
console.log( 'find not loaded!', type, id )
|
||||
if callback
|
||||
|
||||
# execute callback if record got loaded
|
||||
App[type].one 'refresh', ->
|
||||
console.log 'loaded..' + type + '..', id
|
||||
|
||||
data = App.Collection.find( type, id )
|
||||
callback( data )
|
||||
|
||||
# fetch object
|
||||
console.log 'loading..' + type + '..', id
|
||||
App[type].fetch( id: id )
|
||||
return true
|
||||
return false
|
||||
|
||||
# users
|
||||
if type == 'User'
|
||||
|
||||
# set socal media links
|
||||
if data['accounts']
|
||||
for account of data['accounts']
|
||||
if account == 'twitter'
|
||||
data['accounts'][account]['link'] = 'http://twitter.com/' + data['accounts'][account]['username']
|
||||
if account == 'facebook'
|
||||
data['accounts'][account]['link'] = 'https://www.facebook.com/profile.php?id=' + data['accounts'][account]['uid']
|
||||
|
||||
# set image url
|
||||
if data && !data['image']
|
||||
data['image'] = 'http://placehold.it/48x48'
|
||||
|
||||
return data
|
||||
|
||||
# tickets
|
||||
else if type == 'Ticket'
|
||||
|
||||
# priority
|
||||
data.ticket_priority = @find( 'TicketPriority', data.ticket_priority_id )
|
||||
|
||||
# state
|
||||
data.ticket_state = @find( 'TicketState', data.ticket_state_id )
|
||||
|
||||
# group
|
||||
data.group = @find( 'Group', data.group_id )
|
||||
|
||||
# customer
|
||||
if data.customer_id
|
||||
data.customer = @find( 'User', data.customer_id )
|
||||
|
||||
# owner
|
||||
if data.owner_id
|
||||
data.owner = @find( 'User', data.owner_id )
|
||||
|
||||
# add created & updated
|
||||
if data.created_by_id
|
||||
data.created_by = @find( 'User', data.created_by_id )
|
||||
if data.updated_by_id
|
||||
data.updated_by = @find( 'User', data.updated_by_id )
|
||||
|
||||
return data
|
||||
|
||||
# articles
|
||||
else if type == 'TicketArticle'
|
||||
|
||||
# add created & updated
|
||||
data.created_by = @find( 'User', data.created_by_id )
|
||||
|
||||
# add possible actions
|
||||
data.article_type = @find( 'TicketArticleType', data.ticket_article_type_id )
|
||||
data.article_sender = @find( 'TicketArticleSender', data.ticket_article_sender_id )
|
||||
|
||||
return data
|
||||
|
||||
# history
|
||||
else if type == 'History'
|
||||
|
||||
# add user
|
||||
data.created_by = @find( 'User', data.created_by_id )
|
||||
|
||||
# add possible actions
|
||||
if data.history_attribute_id
|
||||
data.attribute = @find( 'HistoryAttribute', data.history_attribute_id )
|
||||
if data.history_type_id
|
||||
data.type = @find( 'HistoryType', data.history_type_id )
|
||||
if data.history_object_id
|
||||
data.object = @find( 'HistoryObject', data.history_object_id )
|
||||
|
||||
return data
|
||||
|
||||
else
|
||||
return data
|
||||
|
||||
get: (params) ->
|
||||
console.log('get')
|
||||
App[ params.type ].refresh( object, options: { clear: true } )
|
||||
|
||||
all: (params) ->
|
||||
all = App[ params.type ].all()
|
||||
all_complied = []
|
||||
for item in all
|
||||
item_new = @find( params.type, item.id )
|
||||
all_complied.push item_new
|
||||
|
||||
if params.filter
|
||||
all_complied = @_filter( all_complied, params.filter )
|
||||
|
||||
if params.filterExtended
|
||||
all_complied = @_filterExtended( all_complied, params.filterExtended )
|
||||
|
||||
if params.sortBy
|
||||
all_complied = @_sortBy( all_complied, params.sortBy )
|
||||
|
||||
if params.order
|
||||
all_complied = @_order( all_complied, params.order )
|
||||
|
||||
return all_complied
|
||||
|
||||
deleteAll: (type) ->
|
||||
App[type].deleteAll()
|
||||
|
||||
findByAttribute: ( type, key, value ) ->
|
||||
App[type].findByAttribute( key, value )
|
||||
|
||||
count: ( type ) ->
|
||||
App[type].count()
|
||||
|
||||
fetch: ( type ) ->
|
||||
App[type].fetch()
|
||||
|
||||
_sortBy: ( collection, attribute ) ->
|
||||
_.sortBy( collection, (item) ->
|
||||
return '' if item[ attribute ] is undefined || item[ attribute ] is null
|
||||
return item[ attribute ].toLowerCase()
|
||||
)
|
||||
|
||||
_order: ( collection, attribute ) ->
|
||||
if attribute is 'DESC'
|
||||
return collection.reverse()
|
||||
return collection
|
||||
|
||||
_filter: ( collection, filter ) ->
|
||||
for key, value of filter
|
||||
collection = _.filter( collection, (item) ->
|
||||
if item[ key ] is value
|
||||
return item
|
||||
)
|
||||
return collection
|
||||
|
||||
_filterExtended: ( collection, filters ) ->
|
||||
collection = _.filter( collection, (item) ->
|
||||
|
||||
# check all filters
|
||||
for filter in filters
|
||||
|
||||
# all conditions need match
|
||||
matchInner = undefined
|
||||
for key, value of filter
|
||||
|
||||
if matchInner isnt false
|
||||
reg = new RegExp( value, 'i' )
|
||||
if item[ key ] isnt undefined && item[ key ] isnt null && item[ key ].match( reg )
|
||||
matchInner = true
|
||||
else
|
||||
matchInner = false
|
||||
|
||||
# if all matched, add item to new collection
|
||||
if matchInner is true
|
||||
return item
|
||||
|
||||
return
|
||||
)
|
||||
return collection
|
||||
|
||||
observeUnbindLevel: (level) ->
|
||||
return if !@observeCurrent
|
||||
return if !@observeCurrent[level]
|
||||
for observers in @observeCurrent[level]
|
||||
@_observeUnbind( observers )
|
||||
@observeCurrent[level] = []
|
||||
|
||||
observe: (data) ->
|
||||
if !@observeCurrent
|
||||
@observeCurrent = {}
|
||||
|
||||
if !@observeCurrent[ data.level ]
|
||||
@observeCurrent[ data.level ] = []
|
||||
|
||||
@observeCurrent[ data.level ].push data.collections
|
||||
for observe in data.collections
|
||||
events = observe.event.split(' ')
|
||||
for event in events
|
||||
if App[ observe.collection ]
|
||||
App[ observe.collection ].bind( event, observe.callback )
|
||||
|
||||
_observeUnbind: (observers) ->
|
||||
for observe in observers
|
||||
events = observe.event.split(' ')
|
||||
for event in events
|
||||
if App[ observe.collection ]
|
||||
App[ observe.collection ].unbind( event, observe.callback )
|
||||
|
||||
_observeStats: ->
|
||||
@observeCurrent
|
|
@ -1,90 +0,0 @@
|
|||
class App.Event
|
||||
_instance = undefined
|
||||
|
||||
@init: ->
|
||||
_instance = new _Singleton
|
||||
|
||||
@bind: ( events, callback, level ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.bind( events, callback, level )
|
||||
|
||||
@unbind: ( events, callback, level ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.unbind( events, callback, level )
|
||||
|
||||
@trigger: ( events, data ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.trigger( events, data )
|
||||
|
||||
@unbindLevel: (level) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.unbindLevel(level)
|
||||
|
||||
@_allBindings: ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance._allBindings()
|
||||
|
||||
class _Singleton
|
||||
|
||||
constructor: ->
|
||||
@eventCurrent = {}
|
||||
|
||||
unbindLevel: (level) ->
|
||||
return if !@eventCurrent[level]
|
||||
for item in @eventCurrent[level]
|
||||
@unbind( item.event, item.callback, level )
|
||||
@eventCurrent[level] = []
|
||||
|
||||
bind: ( events, callback, level ) ->
|
||||
|
||||
if !level
|
||||
level = '_all'
|
||||
|
||||
if !@eventCurrent[level]
|
||||
@eventCurrent[level] = []
|
||||
|
||||
# level boundary events
|
||||
eventList = events.split(' ')
|
||||
for event in eventList
|
||||
|
||||
# remember all events
|
||||
@eventCurrent[ level ].push {
|
||||
event: event,
|
||||
callback: callback,
|
||||
}
|
||||
|
||||
# bind
|
||||
Spine.bind( event, callback )
|
||||
|
||||
unbind: ( events, callback, level ) ->
|
||||
|
||||
if !level
|
||||
level = '_all'
|
||||
|
||||
if !@eventCurrent[level]
|
||||
@eventCurrent[level] = []
|
||||
|
||||
eventList = events.split(' ')
|
||||
for event in eventList
|
||||
|
||||
# remove from
|
||||
@eventCurrent[level] = _.filter( @eventCurrent[level], (item) ->
|
||||
if callback
|
||||
return item if item.event isnt event && item.callback isnt callback
|
||||
else
|
||||
return item if item.event isnt event
|
||||
)
|
||||
Spine.unbind( event, callback )
|
||||
|
||||
trigger: ( events, data ) ->
|
||||
eventList = events.split(' ')
|
||||
for event in eventList
|
||||
Spine.trigger event, data
|
||||
|
||||
_allBindings: ->
|
||||
@eventCurrent
|
File diff suppressed because it is too large
Load diff
|
@ -1,169 +0,0 @@
|
|||
$ = jQuery.sub()
|
||||
|
||||
class App.i18n
|
||||
_instance = undefined
|
||||
|
||||
@init: ->
|
||||
_instance ?= new _Singleton
|
||||
|
||||
@translateContent: ( string, args... ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.translate_content( string, args )
|
||||
|
||||
@translateInline: ( string, args... ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.translate_inline( string, args )
|
||||
|
||||
@translateTimestamp: ( args ) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.timestamp( args )
|
||||
|
||||
class _Singleton
|
||||
|
||||
constructor: ->
|
||||
@locale = 'de'
|
||||
@timestampFormat = 'yyyy-mm-dd HH:MM'
|
||||
@set( @locale )
|
||||
|
||||
# $('.translation [contenteditable]')
|
||||
$('body')
|
||||
.delegate '.translation', 'focus', (e) =>
|
||||
$this = $(e.target)
|
||||
$this.data 'before', $this.html()
|
||||
# console.log('11111current', $this.html())
|
||||
return $this
|
||||
# .delegate '.translation', 'blur keyup paste', (e) =>
|
||||
.delegate '.translation', 'blur', (e) =>
|
||||
$this = $(e.target)
|
||||
source = $this.attr('data-text')
|
||||
|
||||
# get new translation
|
||||
translation_new = $this.html()
|
||||
translation_new = ('' + translation_new)
|
||||
.replace(/<.+?>/g, '')
|
||||
|
||||
# set new translation
|
||||
$this.html(translation_new)
|
||||
|
||||
# update translation
|
||||
return if $this.data('before') is translation_new
|
||||
console.log 'Translation Update', translation_new, $this.data 'before'
|
||||
$this.data 'before', translation_new
|
||||
|
||||
# update runtime translation map
|
||||
@map[ source ] = translation_new
|
||||
|
||||
# replace rest in page
|
||||
$(".translation[data-text='#{source}']").html( translation_new )
|
||||
|
||||
# update permanent translation map
|
||||
translation = App.Collection.findByAttribute( 'Translation', 'source', source )
|
||||
if translation
|
||||
translation.updateAttribute( 'target', translation_new )
|
||||
else
|
||||
translation = new App.Translation
|
||||
translation.load(
|
||||
locale: @locale,
|
||||
source: source,
|
||||
target: translation_new,
|
||||
)
|
||||
translation.save()
|
||||
|
||||
return $this
|
||||
|
||||
set: ( locale ) ->
|
||||
@map = {}
|
||||
App.Com.ajax(
|
||||
id: 'i18n-set-' + locale,
|
||||
type: 'GET',
|
||||
url: '/translations/lang/' + locale,
|
||||
async: false,
|
||||
success: (data, status, xhr) =>
|
||||
|
||||
# set timestamp format
|
||||
if data.timestampFormat
|
||||
@timestampFormat = data.timestampFormat
|
||||
|
||||
# load translation collection
|
||||
for object in data.list
|
||||
|
||||
# set runtime lookup table
|
||||
@map[ object[1] ] = object[2]
|
||||
|
||||
# load in collection if needed
|
||||
App.Translation.refresh( { id: object[0], source: object[1], target: object[2], locale: @locale } )
|
||||
|
||||
error: (xhr, statusText, error) =>
|
||||
console.log 'error', error, statusText, xhr.statusCode
|
||||
)
|
||||
|
||||
translate_inline: ( string, args... ) =>
|
||||
@translate( string, args... )
|
||||
|
||||
translate_content: ( string, args... ) =>
|
||||
translated = @translate( string, args... )
|
||||
# replace = '<span class="translation" contenteditable="true" data-text="' + @escape(string) + '">' + translated + '<span class="icon-edit"></span>'
|
||||
if window.Config['Translation']
|
||||
replace = '<span class="translation" contenteditable="true" data-text="' + @escape(string) + '">' + translated + ''
|
||||
# if !@_translated
|
||||
# replace += '<span class="missing">XX</span>'
|
||||
replace += '</span>'
|
||||
else
|
||||
translated
|
||||
|
||||
translate: ( string, args... ) =>
|
||||
|
||||
# return '' on undefined
|
||||
return '' if string is undefined
|
||||
|
||||
# return translation
|
||||
if @map[string] isnt undefined
|
||||
@_translated = true
|
||||
translated = @map[string]
|
||||
else
|
||||
@_translated = false
|
||||
translated = string
|
||||
|
||||
# search %s
|
||||
for arg in args
|
||||
translated = translated.replace(/%s/, arg)
|
||||
|
||||
# escape
|
||||
translated = @escape(translated)
|
||||
|
||||
# return translated string
|
||||
return translated
|
||||
|
||||
escape: ( string ) ->
|
||||
string = ( '' + string )
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/\x22/g, '"')
|
||||
|
||||
timestamp: ( time ) =>
|
||||
s = ( num, digits ) ->
|
||||
while num.toString().length < digits
|
||||
num = "0" + num
|
||||
return num
|
||||
|
||||
timeObject = new Date(time)
|
||||
d = timeObject.getDate()
|
||||
m = timeObject.getMonth() + 1
|
||||
y = timeObject.getFullYear()
|
||||
S = timeObject.getSeconds()
|
||||
M = timeObject.getMinutes()
|
||||
H = timeObject.getHours()
|
||||
format = @timestampFormat
|
||||
format = format.replace /dd/, s( d, 2 )
|
||||
format = format.replace /d/, d
|
||||
format = format.replace /mm/, s( m, 2 )
|
||||
format = format.replace /m/, m
|
||||
format = format.replace /yyyy/, y
|
||||
format = format.replace /SS/, s( S, 2 )
|
||||
format = format.replace /MM/, s( M, 2 )
|
||||
format = format.replace /HH/, s( H, 2 )
|
||||
return format
|
|
@ -1,76 +0,0 @@
|
|||
|
||||
class App.Run extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
@log 'RUN app'
|
||||
@el = $('#app')
|
||||
|
||||
# init collections
|
||||
App.Collection.init()
|
||||
|
||||
# create web socket connection
|
||||
App.WebSocket.connect()
|
||||
|
||||
# init of i18n
|
||||
App.i18n.init()
|
||||
|
||||
# start navigation controller
|
||||
new App.Navigation( el: @el.find('#navigation') )
|
||||
|
||||
# check if session already exists/try to get session data from server
|
||||
App.Auth.loginCheck()
|
||||
|
||||
# start notify controller
|
||||
new App.Notify( el: @el.find('#notify') )
|
||||
|
||||
# start content
|
||||
new App.Content( el: @el.find('#content') )
|
||||
|
||||
# bind to fill selected text into
|
||||
App.ClipBoard.bind( @el )
|
||||
|
||||
class App.Content extends Spine.Controller
|
||||
className: 'container'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@log 'RUN content'
|
||||
|
||||
for route, callback of Config.Routes
|
||||
do (route, callback) =>
|
||||
@route(route, (params) ->
|
||||
|
||||
# remove observers for page
|
||||
App.Collection.observeUnbindLevel('page')
|
||||
|
||||
# remove events for page
|
||||
App.Event.unbindLevel('page')
|
||||
|
||||
# unbind in controller area
|
||||
@el.unbind()
|
||||
@el.undelegate()
|
||||
|
||||
# send current controller
|
||||
params_only = {}
|
||||
for i of params
|
||||
if typeof params[i] isnt 'object'
|
||||
params_only[i] = params[i]
|
||||
|
||||
# tell server what we are calling right now
|
||||
App.WebSocket.send(
|
||||
action: 'active_controller',
|
||||
controller: route,
|
||||
params: params_only,
|
||||
)
|
||||
|
||||
# remove waypoints
|
||||
$('footer').waypoint('remove')
|
||||
|
||||
params.el = @el
|
||||
new callback( params )
|
||||
|
||||
# scroll to top
|
||||
# window.scrollTo(0,0)
|
||||
)
|
||||
|
||||
Spine.Route.setup()
|
File diff suppressed because one or more lines are too long
9301
app/assets/javascripts/app/lib/jquery-1.8.1.js
vendored
9301
app/assets/javascripts/app/lib/jquery-1.8.1.js
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -1,162 +0,0 @@
|
|||
/**
|
||||
* @name Elastic
|
||||
* @descripton Elastic is jQuery plugin that grow and shrink your textareas automatically
|
||||
* @version 1.6.11
|
||||
* @requires jQuery 1.2.6+
|
||||
*
|
||||
* @author Jan Jarfalk
|
||||
* @author-email jan.jarfalk@unwrongest.com
|
||||
* @author-website http://www.unwrongest.com
|
||||
*
|
||||
* @licence MIT License - http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
(function($){
|
||||
jQuery.fn.extend({
|
||||
elastic: function() {
|
||||
|
||||
// We will create a div clone of the textarea
|
||||
// by copying these attributes from the textarea to the div.
|
||||
var mimics = [
|
||||
'paddingTop',
|
||||
'paddingRight',
|
||||
'paddingBottom',
|
||||
'paddingLeft',
|
||||
'fontSize',
|
||||
'lineHeight',
|
||||
'fontFamily',
|
||||
'width',
|
||||
'fontWeight',
|
||||
'border-top-width',
|
||||
'border-right-width',
|
||||
'border-bottom-width',
|
||||
'border-left-width',
|
||||
'borderTopStyle',
|
||||
'borderTopColor',
|
||||
'borderRightStyle',
|
||||
'borderRightColor',
|
||||
'borderBottomStyle',
|
||||
'borderBottomColor',
|
||||
'borderLeftStyle',
|
||||
'borderLeftColor'
|
||||
];
|
||||
|
||||
return this.each( function() {
|
||||
|
||||
// Elastic only works on textareas
|
||||
if ( this.type !== 'textarea' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var $textarea = jQuery(this),
|
||||
$twin = jQuery('<div />').css({
|
||||
'position' : 'absolute',
|
||||
'display' : 'none',
|
||||
'word-wrap' : 'break-word',
|
||||
'white-space' :'pre-wrap'
|
||||
}),
|
||||
lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
|
||||
minheight = parseInt($textarea.css('height'),10) || lineHeight*3,
|
||||
maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
|
||||
goalheight = 0;
|
||||
|
||||
// Opera returns max-height of -1 if not set
|
||||
if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
|
||||
|
||||
// Append the twin to the DOM
|
||||
// We are going to meassure the height of this, not the textarea.
|
||||
$twin.appendTo($textarea.parent());
|
||||
|
||||
// Copy the essential styles (mimics) from the textarea to the twin
|
||||
var i = mimics.length;
|
||||
while(i--){
|
||||
$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
|
||||
}
|
||||
|
||||
// Updates the width of the twin. (solution for textareas with widths in percent)
|
||||
function setTwinWidth(){
|
||||
var curatedWidth = Math.floor(parseInt($textarea.width(),10));
|
||||
if($twin.width() !== curatedWidth){
|
||||
$twin.css({'width': curatedWidth + 'px'});
|
||||
|
||||
// Update height of textarea
|
||||
update(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Sets a given height and overflow state on the textarea
|
||||
function setHeightAndOverflow(height, overflow){
|
||||
|
||||
var curratedHeight = Math.floor(parseInt(height,10));
|
||||
if($textarea.height() !== curratedHeight){
|
||||
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
|
||||
}
|
||||
}
|
||||
|
||||
// This function will update the height of the textarea if necessary
|
||||
function update(forced) {
|
||||
|
||||
// Get curated content from the textarea.
|
||||
var textareaContent = $textarea.val().replace(/&/g,'&').replace(/ {2}/g, ' ').replace(/<|>/g, '>').replace(/\n/g, '<br />');
|
||||
|
||||
// Compare curated content with curated twin.
|
||||
var twinContent = $twin.html().replace(/<br>/ig,'<br />');
|
||||
|
||||
if(forced || textareaContent+' ' !== twinContent){
|
||||
|
||||
// Add an extra white space so new rows are added when you are at the end of a row.
|
||||
$twin.html(textareaContent+' ');
|
||||
|
||||
// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
|
||||
if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){
|
||||
|
||||
var goalheight = $twin.height()+lineHeight;
|
||||
if(goalheight >= maxheight) {
|
||||
setHeightAndOverflow(maxheight,'auto');
|
||||
} else if(goalheight <= minheight) {
|
||||
setHeightAndOverflow(minheight,'hidden');
|
||||
} else {
|
||||
setHeightAndOverflow(goalheight,'hidden');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Hide scrollbars
|
||||
$textarea.css({'overflow':'hidden'});
|
||||
|
||||
// Update textarea size on keyup, change, cut and paste
|
||||
$textarea.bind('keyup change cut paste', function(){
|
||||
update();
|
||||
});
|
||||
|
||||
// Update width of twin if browser or textarea is resized (solution for textareas with widths in percent)
|
||||
$(window).bind('resize', setTwinWidth);
|
||||
$textarea.bind('resize', setTwinWidth);
|
||||
$textarea.bind('update', update);
|
||||
|
||||
// Compact textarea on blur
|
||||
$textarea.bind('blur',function(){
|
||||
if($twin.height() < maxheight){
|
||||
if($twin.height() > minheight) {
|
||||
$textarea.height($twin.height());
|
||||
} else {
|
||||
$textarea.height(minheight);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// And this line is to catch the browser paste event
|
||||
$textarea.bind('input paste',function(e){ setTimeout( update, 250); });
|
||||
|
||||
// Run update once when elastic is initialized
|
||||
update();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
|
@ -1,220 +0,0 @@
|
|||
/**
|
||||
* jQuery Noty Plugin v1.1.1
|
||||
* Authors: Nedim Arabacı (http://ned.im), Muhittin Özer (http://muhittinozer.com)
|
||||
*
|
||||
* Examples and Documentation - http://needim.github.com/noty/
|
||||
*
|
||||
* Licensed under the MIT licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
**/
|
||||
(function($) {
|
||||
$.noty = function(options, customContainer) {
|
||||
|
||||
var base = this;
|
||||
var $noty = null;
|
||||
var isCustom = false;
|
||||
|
||||
base.init = function(options) {
|
||||
base.options = $.extend({}, $.noty.defaultOptions, options);
|
||||
base.options.type = base.options.cssPrefix+base.options.type;
|
||||
base.options.id = base.options.type+'_'+new Date().getTime();
|
||||
base.options.layout = base.options.cssPrefix+'layout_'+base.options.layout;
|
||||
|
||||
if (base.options.custom.container) customContainer = base.options.custom.container;
|
||||
isCustom = ($.type(customContainer) === 'object') ? true : false;
|
||||
|
||||
return base.addQueue();
|
||||
};
|
||||
|
||||
// Push notification to queue
|
||||
base.addQueue = function() {
|
||||
var isGrowl = ($.inArray(base.options.layout, $.noty.growls) == -1) ? false : true;
|
||||
if (!isGrowl) (base.options.force) ? $.noty.queue.unshift({options: base.options}) : $.noty.queue.push({options: base.options});
|
||||
return base.render(isGrowl);
|
||||
};
|
||||
|
||||
// Render the noty
|
||||
base.render = function(isGrowl) {
|
||||
|
||||
// Layout spesific container settings
|
||||
var container = (isCustom) ? customContainer.addClass(base.options.theme+' '+base.options.layout+' noty_custom_container') : $('body');
|
||||
if (isGrowl) {
|
||||
if ($('ul.noty_cont.' + base.options.layout).length == 0)
|
||||
container.prepend($('<ul/>').addClass('noty_cont ' + base.options.layout));
|
||||
container = $('ul.noty_cont.' + base.options.layout);
|
||||
} else {
|
||||
if ($.noty.available) {
|
||||
var fromQueue = $.noty.queue.shift(); // Get noty from queue
|
||||
if ($.type(fromQueue) === 'object') {
|
||||
$.noty.available = false;
|
||||
base.options = fromQueue.options;
|
||||
} else {
|
||||
$.noty.available = true; // Queue is over
|
||||
return base.options.id;
|
||||
}
|
||||
} else {
|
||||
return base.options.id;
|
||||
}
|
||||
}
|
||||
base.container = container;
|
||||
|
||||
// Generating noty bar
|
||||
base.bar = $('<div class="noty_bar"/>').attr('id', base.options.id).addClass(base.options.theme+' '+base.options.layout+' '+base.options.type);
|
||||
$noty = base.bar;
|
||||
$noty.append(base.options.template).find('.noty_text').html(base.options.text);
|
||||
$noty.data('noty_options', base.options);
|
||||
|
||||
// Close button display
|
||||
(base.options.closeButton) ? $noty.addClass('noty_closable').find('.noty_close').show() : $noty.find('.noty_close').remove();
|
||||
|
||||
// Bind close event to button
|
||||
$noty.find('.noty_close').bind('click', function() { $noty.trigger('noty.close'); });
|
||||
|
||||
// If we have a button we must disable closeOnSelfClick and closeOnSelfOver option
|
||||
if (base.options.buttons) base.options.closeOnSelfClick = base.options.closeOnSelfOver = false;
|
||||
// Close on self click
|
||||
if (base.options.closeOnSelfClick) $noty.bind('click', function() { $noty.trigger('noty.close'); }).css('cursor', 'pointer');
|
||||
// Close on self mouseover
|
||||
if (base.options.closeOnSelfOver) $noty.bind('mouseover', function() { $noty.trigger('noty.close'); }).css('cursor', 'pointer');
|
||||
|
||||
// Set buttons if available
|
||||
if (base.options.buttons) {
|
||||
$buttons = $('<div/>').addClass('noty_buttons');
|
||||
$noty.find('.noty_message').append($buttons);
|
||||
$.each(base.options.buttons, function(i, button) {
|
||||
bclass = (button.type) ? button.type : 'gray';
|
||||
$button = $('<button/>').addClass(bclass).html(button.text).appendTo($noty.find('.noty_buttons'))
|
||||
.bind('click', function() {
|
||||
if ($.isFunction(button.click)) {
|
||||
button.click.call($button, $noty);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return base.show(isGrowl);
|
||||
};
|
||||
|
||||
base.show = function(isGrowl) {
|
||||
|
||||
// is Modal?
|
||||
if (base.options.modal) $('<div/>').addClass('noty_modal').addClass(base.options.theme).prependTo($('body')).fadeIn('fast');
|
||||
|
||||
$noty.close = function() { return this.trigger('noty.close'); };
|
||||
|
||||
// Prepend noty to container
|
||||
(isGrowl) ? base.container.prepend($('<li/>').append($noty)) : base.container.prepend($noty);
|
||||
|
||||
// topCenter and center specific options
|
||||
if (base.options.layout == 'noty_layout_topCenter' || base.options.layout == 'noty_layout_center') {
|
||||
$.noty.reCenter($noty);
|
||||
}
|
||||
|
||||
$noty.bind('noty.setText', function(event, text) {
|
||||
$noty.find('.noty_text').html(text); $.noty.reCenter($noty);
|
||||
});
|
||||
|
||||
$noty.bind('noty.getId', function(event) {
|
||||
return $noty.data('noty_options').id;
|
||||
});
|
||||
|
||||
// Bind close event
|
||||
$noty.one('noty.close', function(event) {
|
||||
var options = $noty.data('noty_options');
|
||||
|
||||
// Modal Cleaning
|
||||
if (options.modal) $('.noty_modal').fadeOut('fast', function() { $(this).remove(); });
|
||||
|
||||
$noty.clearQueue().stop().animate(
|
||||
$noty.data('noty_options').animateClose,
|
||||
$noty.data('noty_options').speed,
|
||||
$noty.data('noty_options').easing,
|
||||
$noty.data('noty_options').onClose)
|
||||
.promise().done(function() {
|
||||
|
||||
// Layout spesific cleaning
|
||||
if ($.inArray($noty.data('noty_options').layout, $.noty.growls) > -1) {
|
||||
$noty.parent().remove();
|
||||
} else {
|
||||
$noty.remove();
|
||||
|
||||
// queue render
|
||||
$.noty.available = true;
|
||||
base.render(false);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
// Start the show
|
||||
$noty.animate(base.options.animateOpen, base.options.speed, base.options.easing, base.options.onShow);
|
||||
|
||||
// If noty is have a timeout option
|
||||
if (base.options.timeout) $noty.delay(base.options.timeout).promise().done(function() { $noty.trigger('noty.close'); });
|
||||
return base.options.id;
|
||||
};
|
||||
|
||||
// Run initializer
|
||||
return base.init(options);
|
||||
};
|
||||
|
||||
// API
|
||||
$.noty.get = function(id) { return $('#'+id); };
|
||||
$.noty.close = function(id) {
|
||||
$.noty.get(id).trigger('noty.close');
|
||||
};
|
||||
$.noty.setText = function(id, text) {
|
||||
$.noty.get(id).trigger('noty.setText', text);
|
||||
};
|
||||
$.noty.closeAll = function() {
|
||||
$.noty.clearQueue();
|
||||
$('.noty_bar').trigger('noty.close');
|
||||
};
|
||||
$.noty.reCenter = function(noty) {
|
||||
noty.css({'left': ($(window).width() - noty.outerWidth()) / 2 + 'px'});
|
||||
};
|
||||
$.noty.clearQueue = function() {
|
||||
$.noty.queue = [];
|
||||
};
|
||||
|
||||
$.noty.queue = [];
|
||||
$.noty.growls = ['noty_layout_topLeft', 'noty_layout_topRight', 'noty_layout_bottomLeft', 'noty_layout_bottomRight'];
|
||||
$.noty.available = true;
|
||||
$.noty.defaultOptions = {
|
||||
layout: 'top',
|
||||
theme: 'noty_theme_default',
|
||||
animateOpen: {height: 'toggle'},
|
||||
animateClose: {height: 'toggle'},
|
||||
easing: 'swing',
|
||||
text: '',
|
||||
type: 'alert',
|
||||
speed: 500,
|
||||
timeout: 5000,
|
||||
closeButton: false,
|
||||
closeOnSelfClick: true,
|
||||
closeOnSelfOver: false,
|
||||
force: false,
|
||||
onShow: false,
|
||||
onClose: false,
|
||||
buttons: false,
|
||||
modal: false,
|
||||
template: '<div class="noty_message"><span class="noty_text"></span><div class="noty_close"></div></div>',
|
||||
cssPrefix: 'noty_',
|
||||
custom: {
|
||||
container: null
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.noty = function(options) {
|
||||
return this.each(function() {
|
||||
(new $.noty(options, $(this)));
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
//Helper
|
||||
function noty(options) {
|
||||
return jQuery.noty(options); // returns an id
|
||||
}
|
|
@ -1,353 +0,0 @@
|
|||
/*
|
||||
|
||||
jQuery Tags Input Plugin 1.3.3
|
||||
|
||||
Copyright (c) 2011 XOXCO, Inc
|
||||
|
||||
Documentation for this plugin lives here:
|
||||
http://xoxco.com/clickable/jquery-tags-input
|
||||
|
||||
Licensed under the MIT license:
|
||||
http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
ben@xoxco.com
|
||||
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
var delimiter = new Array();
|
||||
var tags_callbacks = new Array();
|
||||
$.fn.doAutosize = function(o){
|
||||
var minWidth = $(this).data('minwidth'),
|
||||
maxWidth = $(this).data('maxwidth'),
|
||||
val = '',
|
||||
input = $(this),
|
||||
testSubject = $('#'+$(this).data('tester_id'));
|
||||
|
||||
if (val === (val = input.val())) {return;}
|
||||
|
||||
// Enter new content into testSubject
|
||||
var escaped = val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>');
|
||||
testSubject.html(escaped);
|
||||
// Calculate new width + whether to change
|
||||
var testerWidth = testSubject.width(),
|
||||
newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
|
||||
currentWidth = input.width(),
|
||||
isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
|
||||
|| (newWidth > minWidth && newWidth < maxWidth);
|
||||
|
||||
// Animate width
|
||||
if (isValidWidthChange) {
|
||||
input.width(newWidth);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
$.fn.resetAutosize = function(options){
|
||||
// alert(JSON.stringify(options));
|
||||
var minWidth = $(this).data('minwidth') || options.minInputWidth || $(this).width(),
|
||||
maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.tagsinput').width() - options.inputPadding),
|
||||
val = '',
|
||||
input = $(this),
|
||||
testSubject = $('<tester/>').css({
|
||||
position: 'absolute',
|
||||
top: -9999,
|
||||
left: -9999,
|
||||
width: 'auto',
|
||||
fontSize: input.css('fontSize'),
|
||||
fontFamily: input.css('fontFamily'),
|
||||
fontWeight: input.css('fontWeight'),
|
||||
letterSpacing: input.css('letterSpacing'),
|
||||
whiteSpace: 'nowrap'
|
||||
}),
|
||||
testerId = $(this).attr('id')+'_autosize_tester';
|
||||
if(! $('#'+testerId).length > 0){
|
||||
testSubject.attr('id', testerId);
|
||||
testSubject.appendTo('body');
|
||||
}
|
||||
|
||||
input.data('minwidth', minWidth);
|
||||
input.data('maxwidth', maxWidth);
|
||||
input.data('tester_id', testerId);
|
||||
input.css('width', minWidth);
|
||||
};
|
||||
|
||||
$.fn.addTag = function(value,options) {
|
||||
options = jQuery.extend({focus:false,callback:true},options);
|
||||
this.each(function() {
|
||||
var id = $(this).attr('id');
|
||||
|
||||
var tagslist = $(this).val().split(delimiter[id]);
|
||||
if (tagslist[0] == '') {
|
||||
tagslist = new Array();
|
||||
}
|
||||
|
||||
value = jQuery.trim(value);
|
||||
|
||||
if (options.unique) {
|
||||
var skipTag = $(tagslist).tagExist(value);
|
||||
if(skipTag == true) {
|
||||
//Marks fake input as not_valid to let styling it
|
||||
$('#'+id+'_tag').addClass('not_valid');
|
||||
}
|
||||
} else {
|
||||
var skipTag = false;
|
||||
}
|
||||
|
||||
if (value !='' && skipTag != true) {
|
||||
$('<span>').addClass('tag').append(
|
||||
$('<span>').text(value).append(' '),
|
||||
$('<a>', {
|
||||
href : '#',
|
||||
title : 'Removing tag',
|
||||
text : 'x'
|
||||
}).click(function () {
|
||||
return $('#' + id).removeTag(escape(value));
|
||||
})
|
||||
).insertBefore('#' + id + '_addTag');
|
||||
|
||||
tagslist.push(value);
|
||||
|
||||
$('#'+id+'_tag').val('');
|
||||
if (options.focus) {
|
||||
$('#'+id+'_tag').focus();
|
||||
} else {
|
||||
$('#'+id+'_tag').blur();
|
||||
}
|
||||
|
||||
$.fn.tagsInput.updateTagsField(this,tagslist);
|
||||
|
||||
if (options.callback && tags_callbacks[id] && tags_callbacks[id]['onAddTag']) {
|
||||
var f = tags_callbacks[id]['onAddTag'];
|
||||
f.call(this, value);
|
||||
}
|
||||
if(tags_callbacks[id] && tags_callbacks[id]['onChange'])
|
||||
{
|
||||
var i = tagslist.length;
|
||||
var f = tags_callbacks[id]['onChange'];
|
||||
f.call(this, $(this), tagslist[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
$.fn.removeTag = function(value) {
|
||||
value = unescape(value);
|
||||
this.each(function() {
|
||||
var id = $(this).attr('id');
|
||||
|
||||
var old = $(this).val().split(delimiter[id]);
|
||||
|
||||
$('#'+id+'_tagsinput .tag').remove();
|
||||
str = '';
|
||||
for (i=0; i< old.length; i++) {
|
||||
if (old[i]!=value) {
|
||||
str = str + delimiter[id] +old[i];
|
||||
}
|
||||
}
|
||||
|
||||
$.fn.tagsInput.importTags(this,str);
|
||||
|
||||
if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) {
|
||||
var f = tags_callbacks[id]['onRemoveTag'];
|
||||
f.call(this, value);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
$.fn.tagExist = function(val) {
|
||||
return (jQuery.inArray(val, $(this)) >= 0); //true when tag exists, false when not
|
||||
};
|
||||
|
||||
// clear all existing tags and import new ones from a string
|
||||
$.fn.importTags = function(str) {
|
||||
id = $(this).attr('id');
|
||||
$('#'+id+'_tagsinput .tag').remove();
|
||||
$.fn.tagsInput.importTags(this,str);
|
||||
}
|
||||
|
||||
$.fn.tagsInput = function(options) {
|
||||
var settings = jQuery.extend({
|
||||
interactive:true,
|
||||
defaultText:'add a tag',
|
||||
minChars:0,
|
||||
width:'300px',
|
||||
height:'100px',
|
||||
autocomplete: {selectFirst: false },
|
||||
'hide':true,
|
||||
'delimiter':',',
|
||||
'unique':true,
|
||||
removeWithBackspace:true,
|
||||
placeholderColor:'#666666',
|
||||
autosize: true,
|
||||
comfortZone: 20,
|
||||
inputPadding: 6*2
|
||||
},options);
|
||||
|
||||
this.each(function() {
|
||||
if (settings.hide) {
|
||||
$(this).hide();
|
||||
}
|
||||
|
||||
var id = $(this).attr('id')
|
||||
|
||||
var data = jQuery.extend({
|
||||
pid:id,
|
||||
real_input: '#'+id,
|
||||
holder: '#'+id+'_tagsinput',
|
||||
input_wrapper: '#'+id+'_addTag',
|
||||
fake_input: '#'+id+'_tag'
|
||||
},settings);
|
||||
|
||||
delimiter[id] = data.delimiter;
|
||||
|
||||
if (settings.onAddTag || settings.onRemoveTag || settings.onChange) {
|
||||
tags_callbacks[id] = new Array();
|
||||
tags_callbacks[id]['onAddTag'] = settings.onAddTag;
|
||||
tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag;
|
||||
tags_callbacks[id]['onChange'] = settings.onChange;
|
||||
}
|
||||
|
||||
var markup = '<div id="'+id+'_tagsinput" class="tagsinput"><div id="'+id+'_addTag">';
|
||||
|
||||
if (settings.interactive) {
|
||||
markup = markup + '<input id="'+id+'_tag" value="" data-default="'+settings.defaultText+'" />';
|
||||
}
|
||||
|
||||
markup = markup + '</div><div class="tags_clear"></div></div>';
|
||||
|
||||
$(markup).insertAfter(this);
|
||||
|
||||
$(data.holder).css('width',settings.width);
|
||||
$(data.holder).css('height',settings.height);
|
||||
|
||||
if ($(data.real_input).val()!='') {
|
||||
$.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val());
|
||||
}
|
||||
if (settings.interactive) {
|
||||
$(data.fake_input).val($(data.fake_input).attr('data-default'));
|
||||
$(data.fake_input).css('color',settings.placeholderColor);
|
||||
$(data.fake_input).resetAutosize(settings);
|
||||
|
||||
$(data.holder).bind('click',data,function(event) {
|
||||
$(event.data.fake_input).focus();
|
||||
});
|
||||
|
||||
$(data.fake_input).bind('focus',data,function(event) {
|
||||
if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('data-default')) {
|
||||
$(event.data.fake_input).val('');
|
||||
}
|
||||
$(event.data.fake_input).css('color','#000000');
|
||||
});
|
||||
|
||||
if (settings.autocomplete_url != undefined) {
|
||||
// 2012-02-23 me
|
||||
// autocomplete_options = {source: settings.autocomplete_url};
|
||||
autocomplete_options = settings.auto;
|
||||
// 2012-02-23 me
|
||||
for (attrname in settings.autocomplete) {
|
||||
autocomplete_options[attrname] = settings.autocomplete[attrname];
|
||||
}
|
||||
|
||||
if (jQuery.Autocompleter !== undefined) {
|
||||
$(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete);
|
||||
$(data.fake_input).bind('result',data,function(event,data,formatted) {
|
||||
if (data) {
|
||||
$('#'+id).addTag(data[0] + "",{focus:true,unique:(settings.unique)});
|
||||
}
|
||||
});
|
||||
} else if (jQuery.ui.autocomplete !== undefined) {
|
||||
$(data.fake_input).autocomplete(autocomplete_options);
|
||||
$(data.fake_input).bind('autocompleteselect',data,function(event,ui) {
|
||||
$(event.data.real_input).addTag(ui.item.value,{focus:true,unique:(settings.unique)});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// if a user tabs out of the field, create a new tag
|
||||
// this is only available if autocomplete is not used.
|
||||
$(data.fake_input).bind('blur',data,function(event) {
|
||||
var d = $(this).attr('data-default');
|
||||
if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) {
|
||||
if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) )
|
||||
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)});
|
||||
} else {
|
||||
$(event.data.fake_input).val($(event.data.fake_input).attr('data-default'));
|
||||
$(event.data.fake_input).css('color',settings.placeholderColor);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
}
|
||||
// if user types a comma, create a new tag
|
||||
$(data.fake_input).bind('keypress',data,function(event) {
|
||||
if (event.which==event.data.delimiter.charCodeAt(0) || event.which==13 ) {
|
||||
event.preventDefault();
|
||||
if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) )
|
||||
$(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)});
|
||||
$(event.data.fake_input).resetAutosize(settings);
|
||||
return false;
|
||||
} else if (event.data.autosize) {
|
||||
$(event.data.fake_input).doAutosize(settings);
|
||||
|
||||
}
|
||||
});
|
||||
//Delete last tag on backspace
|
||||
data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event)
|
||||
{
|
||||
if(event.keyCode == 8 && $(this).val() == '')
|
||||
{
|
||||
event.preventDefault();
|
||||
var last_tag = $(this).closest('.tagsinput').find('.tag:last').text();
|
||||
var id = $(this).attr('id').replace(/_tag$/, '');
|
||||
last_tag = last_tag.replace(/[\s]+x$/, '');
|
||||
$('#' + id).removeTag(escape(last_tag));
|
||||
$(this).trigger('focus');
|
||||
}
|
||||
});
|
||||
$(data.fake_input).blur();
|
||||
|
||||
//Removes the not_valid class when user changes the value of the fake input
|
||||
if(data.unique) {
|
||||
$(data.fake_input).keydown(function(event){
|
||||
if(event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéíóúÁÉÍÓÚñÑ,/]+/)) {
|
||||
$(this).removeClass('not_valid');
|
||||
}
|
||||
});
|
||||
}
|
||||
} // if settings.interactive
|
||||
return false;
|
||||
});
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
$.fn.tagsInput.updateTagsField = function(obj,tagslist) {
|
||||
var id = $(obj).attr('id');
|
||||
$(obj).val(tagslist.join(delimiter[id]));
|
||||
};
|
||||
|
||||
$.fn.tagsInput.importTags = function(obj,val) {
|
||||
$(obj).val('');
|
||||
var id = $(obj).attr('id');
|
||||
var tags = val.split(delimiter[id]);
|
||||
for (i=0; i<tags.length; i++) {
|
||||
$(obj).addTag(tags[i],{focus:false,callback:false});
|
||||
}
|
||||
if(tags_callbacks[id] && tags_callbacks[id]['onChange'])
|
||||
{
|
||||
var f = tags_callbacks[id]['onChange'];
|
||||
f.call(obj, obj, tags[i]);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
|
@ -1,61 +0,0 @@
|
|||
class App.Store
|
||||
_instance = undefined # Must be declared here to force the closure on the class
|
||||
@renew: ->
|
||||
_instance = new _Singleton
|
||||
|
||||
@write: (key, value) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.write(key, value)
|
||||
|
||||
@get: (args) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.get(args)
|
||||
|
||||
@delete: (args) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.delete(args)
|
||||
|
||||
@clear: ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.clear()
|
||||
|
||||
@list: () ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance.list()
|
||||
|
||||
# The actual Singleton class
|
||||
class _Singleton
|
||||
|
||||
# write to local storage
|
||||
write: (key, value) ->
|
||||
localStorage.setItem( key, JSON.stringify( value ) )
|
||||
|
||||
# get item
|
||||
get: (key) ->
|
||||
value = localStorage.getItem( key )
|
||||
return if !value
|
||||
object = JSON.parse( value )
|
||||
return object
|
||||
|
||||
# delete item
|
||||
delete: (key) ->
|
||||
localStorage.removeItem( key )
|
||||
|
||||
# clear local storage
|
||||
clear: ->
|
||||
localStorage.clear()
|
||||
|
||||
# return list of all keys
|
||||
list: ->
|
||||
list = []
|
||||
logLength = localStorage.length-1;
|
||||
for count in [0..logLength]
|
||||
key = localStorage.key( count )
|
||||
if key
|
||||
list.push key
|
||||
list
|
File diff suppressed because it is too large
Load diff
|
@ -1,674 +0,0 @@
|
|||
/*!
|
||||
jQuery Waypoints - v1.1.6
|
||||
Copyright (c) 2011-2012 Caleb Troughton
|
||||
Dual licensed under the MIT license and GPL license.
|
||||
https://github.com/imakewebthings/jquery-waypoints/blob/master/MIT-license.txt
|
||||
https://github.com/imakewebthings/jquery-waypoints/blob/master/GPL-license.txt
|
||||
*/
|
||||
|
||||
/*
|
||||
Waypoints is a small jQuery plugin that makes it easy to execute a function
|
||||
whenever you scroll to an element.
|
||||
|
||||
GitHub Repository: https://github.com/imakewebthings/jquery-waypoints
|
||||
Documentation and Examples: http://imakewebthings.github.com/jquery-waypoints
|
||||
|
||||
Changelog:
|
||||
v1.1.6
|
||||
- Fix potential memory leak by unbinding events on empty context elements.
|
||||
v1.1.5
|
||||
- Make plugin compatible with Browserify/RequireJS. (Thanks @cjroebuck)
|
||||
v1.1.4
|
||||
- Add handler option to give alternate binding method. (Issue #34)
|
||||
v1.1.3
|
||||
- Fix cases where waypoints are added post-load and should be triggered
|
||||
immediately. (Issue #28)
|
||||
v1.1.2
|
||||
- Fixed error thrown by waypoints with triggerOnce option that were
|
||||
triggered via resize refresh.
|
||||
v1.1.1
|
||||
- Fixed bug in initialization where all offsets were being calculated
|
||||
as if set to 0 initially, causing unwarranted triggers during the
|
||||
subsequent refresh.
|
||||
- Added onlyOnScroll, an option for individual waypoints that disables
|
||||
triggers due to an offset refresh that crosses the current scroll
|
||||
point. (All credit to @knuton on this one.)
|
||||
v1.1
|
||||
- Moved the continuous option out of global settings and into the options
|
||||
object for individual waypoints.
|
||||
- Added the context option, which allows for using waypoints within any
|
||||
scrollable element, not just the window.
|
||||
v1.0.2
|
||||
- Moved scroll and resize handler bindings out of load. Should play nicer
|
||||
with async loaders like Head JS and LABjs.
|
||||
- Fixed a 1px off error when using certain % offsets.
|
||||
- Added unit tests.
|
||||
v1.0.1
|
||||
- Added $.waypoints('viewportHeight').
|
||||
- Fixed iOS bug (using the new viewportHeight method).
|
||||
- Added offset function alias: 'bottom-in-view'.
|
||||
v1.0
|
||||
- Initial release.
|
||||
|
||||
Support:
|
||||
- jQuery versions 1.4.3+
|
||||
- IE6+, FF3+, Chrome 6+, Safari 4+, Opera 11
|
||||
- Other versions and browsers may work, these are just the ones I've looked at.
|
||||
*/
|
||||
|
||||
(function($, wp, wps, window, undefined){
|
||||
'$:nomunge';
|
||||
|
||||
var $w = $(window),
|
||||
|
||||
// Keeping common strings as variables = better minification
|
||||
eventName = 'waypoint.reached',
|
||||
|
||||
/*
|
||||
For the waypoint and direction passed in, trigger the waypoint.reached
|
||||
event and deal with the triggerOnce option.
|
||||
*/
|
||||
triggerWaypoint = function(way, dir) {
|
||||
way.element.trigger(eventName, dir);
|
||||
if (way.options.triggerOnce) {
|
||||
way.element[wp]('destroy');
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
Given a jQuery element and Context, returns the index of that element in the waypoints
|
||||
array. Returns the index, or -1 if the element is not a waypoint.
|
||||
*/
|
||||
waypointIndex = function(el, context) {
|
||||
if (!context) return -1;
|
||||
var i = context.waypoints.length - 1;
|
||||
while (i >= 0 && context.waypoints[i].element[0] !== el[0]) {
|
||||
i -= 1;
|
||||
}
|
||||
return i;
|
||||
},
|
||||
|
||||
// Private list of all elements used as scrolling contexts for waypoints.
|
||||
contexts = [],
|
||||
|
||||
/*
|
||||
Context Class - represents a scrolling context. Properties include:
|
||||
element: jQuery object containing a single HTML element.
|
||||
waypoints: Array of waypoints operating under this scroll context.
|
||||
oldScroll: Keeps the previous scroll position to determine scroll direction.
|
||||
didScroll: Flag used in scrolling the context's scroll event.
|
||||
didResize: Flag used in scrolling the context's resize event.
|
||||
doScroll: Function that checks for crossed waypoints. Called from throttler.
|
||||
*/
|
||||
Context = function(context) {
|
||||
$.extend(this, {
|
||||
element: $(context),
|
||||
oldScroll: 0,
|
||||
|
||||
/*
|
||||
List of all elements that have been registered as waypoints.
|
||||
Each object in the array contains:
|
||||
element: jQuery object containing a single HTML element.
|
||||
offset: The window scroll offset, in px, that triggers the waypoint event.
|
||||
options: Options object that was passed to the waypoint fn function.
|
||||
*/
|
||||
'waypoints': [],
|
||||
|
||||
didScroll: false,
|
||||
didResize: false,
|
||||
|
||||
doScroll: $.proxy(function() {
|
||||
var newScroll = this.element.scrollTop(),
|
||||
|
||||
// Are we scrolling up or down? Used for direction argument in callback.
|
||||
isDown = newScroll > this.oldScroll,
|
||||
that = this,
|
||||
|
||||
// Get a list of all waypoints that were crossed since last scroll move.
|
||||
pointsHit = $.grep(this.waypoints, function(el, i) {
|
||||
return isDown ?
|
||||
(el.offset > that.oldScroll && el.offset <= newScroll) :
|
||||
(el.offset <= that.oldScroll && el.offset > newScroll);
|
||||
}),
|
||||
len = pointsHit.length;
|
||||
|
||||
// iOS adjustment
|
||||
if (!this.oldScroll || !newScroll) {
|
||||
$[wps]('refresh');
|
||||
}
|
||||
|
||||
// Done with scroll comparisons, store new scroll before ejection
|
||||
this.oldScroll = newScroll;
|
||||
|
||||
// No waypoints crossed? Eject.
|
||||
if (!len) return;
|
||||
|
||||
// If several waypoints triggered, need to do so in reverse order going up
|
||||
if (!isDown) pointsHit.reverse();
|
||||
|
||||
/*
|
||||
One scroll move may cross several waypoints. If the waypoint's continuous
|
||||
option is true it should fire even if it isn't the last waypoint. If false,
|
||||
it will only fire if it's the last one.
|
||||
*/
|
||||
$.each(pointsHit, function(i, point) {
|
||||
if (point.options.continuous || i === len - 1) {
|
||||
triggerWaypoint(point, [isDown ? 'down' : 'up']);
|
||||
}
|
||||
});
|
||||
}, this)
|
||||
});
|
||||
|
||||
// Setup scroll and resize handlers. Throttled at the settings-defined rate limits.
|
||||
$(context).bind('scroll.waypoints', $.proxy(function() {
|
||||
if (!this.didScroll) {
|
||||
this.didScroll = true;
|
||||
window.setTimeout($.proxy(function() {
|
||||
this.doScroll();
|
||||
this.didScroll = false;
|
||||
}, this), $[wps].settings.scrollThrottle);
|
||||
}
|
||||
}, this)).bind('resize.waypoints', $.proxy(function() {
|
||||
if (!this.didResize) {
|
||||
this.didResize = true;
|
||||
window.setTimeout($.proxy(function() {
|
||||
$[wps]('refresh');
|
||||
this.didResize = false;
|
||||
}, this), $[wps].settings.resizeThrottle);
|
||||
}
|
||||
}, this));
|
||||
|
||||
$w.load($.proxy(function() {
|
||||
/*
|
||||
Fire a scroll check, should the page be loaded at a non-zero scroll value,
|
||||
as with a fragment id link or a page refresh.
|
||||
*/
|
||||
this.doScroll();
|
||||
}, this));
|
||||
},
|
||||
|
||||
/* Returns a Context object from the contexts array, given the raw HTML element
|
||||
for that context. */
|
||||
getContextByElement = function(element) {
|
||||
var found = null;
|
||||
|
||||
$.each(contexts, function(i, c) {
|
||||
if (c.element[0] === element) {
|
||||
found = c;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
},
|
||||
|
||||
// Methods exposed to the effin' object
|
||||
methods = {
|
||||
/*
|
||||
jQuery.fn.waypoint([handler], [options])
|
||||
|
||||
handler
|
||||
function, optional
|
||||
A callback function called when the user scrolls past the element.
|
||||
The function signature is function(event, direction) where event is
|
||||
a standard jQuery Event Object and direction is a string, either 'down'
|
||||
or 'up' indicating which direction the user is scrolling.
|
||||
|
||||
options
|
||||
object, optional
|
||||
A map of options to apply to this set of waypoints, including where on
|
||||
the browser window the waypoint is triggered. For a full list of
|
||||
options and their defaults, see $.fn.waypoint.defaults.
|
||||
|
||||
This is how you register an element as a waypoint. When the user scrolls past
|
||||
that element it triggers waypoint.reached, a custom event. Since the
|
||||
parameters for creating a waypoint are optional, we have a few different
|
||||
possible signatures. Let’s look at each of them.
|
||||
|
||||
someElements.waypoint();
|
||||
|
||||
Calling .waypoint with no parameters will register the elements as waypoints
|
||||
using the default options. The elements will fire the waypoint.reached event,
|
||||
but calling it in this way does not bind any handler to the event. You can
|
||||
bind to the event yourself, as with any other event, like so:
|
||||
|
||||
someElements.bind('waypoint.reached', function(event, direction) {
|
||||
// make it rain
|
||||
});
|
||||
|
||||
You will usually want to create a waypoint and immediately bind a function to
|
||||
waypoint.reached, and can do so by passing a handler as the first argument to
|
||||
.waypoint:
|
||||
|
||||
someElements.waypoint(function(event, direction) {
|
||||
if (direction === 'down') {
|
||||
// do this on the way down
|
||||
}
|
||||
else {
|
||||
// do this on the way back up through the waypoint
|
||||
}
|
||||
});
|
||||
|
||||
This will still use the default options, which will trigger the waypoint when
|
||||
the top of the element hits the top of the window. We can pass .waypoint an
|
||||
options object to customize things:
|
||||
|
||||
someElements.waypoint(function(event, direction) {
|
||||
// do something amazing
|
||||
}, {
|
||||
offset: '50%' // middle of the page
|
||||
});
|
||||
|
||||
You can also pass just an options object.
|
||||
|
||||
someElements.waypoint({
|
||||
offset: 100 // 100px from the top
|
||||
});
|
||||
|
||||
This behaves like .waypoint(), in that it registers the elements as waypoints
|
||||
but binds no event handlers.
|
||||
|
||||
Calling .waypoint on an existing waypoint will extend the previous options.
|
||||
If the call includes a handler, it will be bound to waypoint.reached without
|
||||
unbinding any other handlers.
|
||||
*/
|
||||
init: function(f, options) {
|
||||
// Register each element as a waypoint, add to array.
|
||||
this.each(function() {
|
||||
var cElement = $.fn[wp].defaults.context,
|
||||
context,
|
||||
$this = $(this);
|
||||
|
||||
// Default window context or a specific element?
|
||||
if (options && options.context) {
|
||||
cElement = options.context;
|
||||
}
|
||||
|
||||
// Find the closest element that matches the context
|
||||
if (!$.isWindow(cElement)) {
|
||||
cElement = $this.closest(cElement)[0];
|
||||
}
|
||||
context = getContextByElement(cElement);
|
||||
|
||||
// Not a context yet? Create and push.
|
||||
if (!context) {
|
||||
context = new Context(cElement);
|
||||
contexts.push(context);
|
||||
}
|
||||
|
||||
// Extend default and preexisting options
|
||||
var ndx = waypointIndex($this, context),
|
||||
base = ndx < 0 ? $.fn[wp].defaults : context.waypoints[ndx].options,
|
||||
opts = $.extend({}, base, options);
|
||||
|
||||
// Offset aliases
|
||||
opts.offset = opts.offset === "bottom-in-view" ?
|
||||
function() {
|
||||
var cHeight = $.isWindow(cElement) ? $[wps]('viewportHeight')
|
||||
: $(cElement).height();
|
||||
return cHeight - $(this).outerHeight();
|
||||
} : opts.offset;
|
||||
|
||||
// Update, or create new waypoint
|
||||
if (ndx < 0) {
|
||||
context.waypoints.push({
|
||||
'element': $this,
|
||||
'offset': null,
|
||||
'options': opts
|
||||
});
|
||||
}
|
||||
else {
|
||||
context.waypoints[ndx].options = opts;
|
||||
}
|
||||
|
||||
// Bind the function if it was passed in.
|
||||
if (f) {
|
||||
$this.bind(eventName, f);
|
||||
}
|
||||
// Bind the function in the handler option if it exists.
|
||||
if (options && options.handler) {
|
||||
$this.bind(eventName, options.handler);
|
||||
}
|
||||
});
|
||||
|
||||
// Need to re-sort+refresh the waypoints array after new elements are added.
|
||||
$[wps]('refresh');
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
jQuery.fn.waypoint('remove')
|
||||
|
||||
Passing the string 'remove' to .waypoint unregisters the elements as waypoints
|
||||
and wipes any custom options, but leaves the waypoint.reached events bound.
|
||||
Calling .waypoint again in the future would reregister the waypoint and the old
|
||||
handlers would continue to work.
|
||||
*/
|
||||
remove: function() {
|
||||
return this.each(function(i, el) {
|
||||
var $el = $(el);
|
||||
|
||||
$.each(contexts, function(i, c) {
|
||||
var ndx = waypointIndex($el, c);
|
||||
|
||||
if (ndx >= 0) {
|
||||
c.waypoints.splice(ndx, 1);
|
||||
|
||||
if (!c.waypoints.length) {
|
||||
c.element.unbind('scroll.waypoints resize.waypoints');
|
||||
contexts.splice(i, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
jQuery.fn.waypoint('destroy')
|
||||
|
||||
Passing the string 'destroy' to .waypoint will unbind all waypoint.reached
|
||||
event handlers on those elements and unregisters them as waypoints.
|
||||
*/
|
||||
destroy: function() {
|
||||
return this.unbind(eventName)[wp]('remove');
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
Methods used by the jQuery object extension.
|
||||
*/
|
||||
jQMethods = {
|
||||
|
||||
/*
|
||||
jQuery.waypoints('refresh')
|
||||
|
||||
This will force a recalculation of each waypoint’s trigger point based on
|
||||
its offset option and context. This is called automatically whenever the window
|
||||
(or other defined context) is resized, new waypoints are added, or a waypoint’s
|
||||
options are modified. If your project is changing the DOM or page layout without
|
||||
doing one of these things, you may want to manually call this refresh.
|
||||
*/
|
||||
refresh: function() {
|
||||
$.each(contexts, function(i, c) {
|
||||
var isWin = $.isWindow(c.element[0]),
|
||||
contextOffset = isWin ? 0 : c.element.offset().top,
|
||||
contextHeight = isWin ? $[wps]('viewportHeight') : c.element.height(),
|
||||
contextScroll = isWin ? 0 : c.element.scrollTop();
|
||||
|
||||
$.each(c.waypoints, function(j, o) {
|
||||
/* $.each isn't safe from element removal due to triggerOnce.
|
||||
Should rewrite the loop but this is way easier. */
|
||||
if (!o) return;
|
||||
|
||||
// Adjustment is just the offset if it's a px value
|
||||
var adjustment = o.options.offset,
|
||||
oldOffset = o.offset;
|
||||
|
||||
// Set adjustment to the return value if offset is a function.
|
||||
if (typeof o.options.offset === "function") {
|
||||
adjustment = o.options.offset.apply(o.element);
|
||||
}
|
||||
// Calculate the adjustment if offset is a percentage.
|
||||
else if (typeof o.options.offset === "string") {
|
||||
var amount = parseFloat(o.options.offset);
|
||||
adjustment = o.options.offset.indexOf("%") ?
|
||||
Math.ceil(contextHeight * (amount / 100)) : amount;
|
||||
}
|
||||
|
||||
/*
|
||||
Set the element offset to the window scroll offset, less
|
||||
all our adjustments.
|
||||
*/
|
||||
o.offset = o.element.offset().top - contextOffset
|
||||
+ contextScroll - adjustment;
|
||||
|
||||
/*
|
||||
An element offset change across the current scroll point triggers
|
||||
the event, just as if we scrolled past it unless prevented by an
|
||||
optional flag.
|
||||
*/
|
||||
if (o.options.onlyOnScroll) return;
|
||||
|
||||
if (oldOffset !== null && c.oldScroll > oldOffset && c.oldScroll <= o.offset) {
|
||||
triggerWaypoint(o, ['up']);
|
||||
}
|
||||
else if (oldOffset !== null && c.oldScroll < oldOffset && c.oldScroll >= o.offset) {
|
||||
triggerWaypoint(o, ['down']);
|
||||
}
|
||||
/* For new waypoints added after load, check that down should have
|
||||
already been triggered */
|
||||
else if (!oldOffset && c.element.scrollTop() > o.offset) {
|
||||
triggerWaypoint(o, ['down']);
|
||||
}
|
||||
});
|
||||
|
||||
// Keep waypoints sorted by offset value.
|
||||
c.waypoints.sort(function(a, b) {
|
||||
return a.offset - b.offset;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
jQuery.waypoints('viewportHeight')
|
||||
|
||||
This will return the height of the viewport, adjusting for inconsistencies
|
||||
that come with calling $(window).height() in iOS. Recommended for use
|
||||
within any offset functions.
|
||||
*/
|
||||
viewportHeight: function() {
|
||||
return (window.innerHeight ? window.innerHeight : $w.height());
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
jQuery.waypoints()
|
||||
|
||||
This will return a jQuery object with a collection of all registered waypoint
|
||||
elements.
|
||||
|
||||
$('.post').waypoint();
|
||||
$('.ad-unit').waypoint(function(event, direction) {
|
||||
// Passed an ad unit
|
||||
});
|
||||
console.log($.waypoints());
|
||||
|
||||
The example above would log a jQuery object containing all .post and .ad-unit
|
||||
elements.
|
||||
*/
|
||||
aggregate: function() {
|
||||
var points = $();
|
||||
$.each(contexts, function(i, c) {
|
||||
$.each(c.waypoints, function(i, e) {
|
||||
points = points.add(e.element);
|
||||
});
|
||||
});
|
||||
return points;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
fn extension. Delegates to appropriate method.
|
||||
*/
|
||||
$.fn[wp] = function(method) {
|
||||
|
||||
if (methods[method]) {
|
||||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
}
|
||||
else if (typeof method === "function" || !method) {
|
||||
return methods.init.apply(this, arguments);
|
||||
}
|
||||
else if (typeof method === "object") {
|
||||
return methods.init.apply(this, [null, method]);
|
||||
}
|
||||
else {
|
||||
$.error( 'Method ' + method + ' does not exist on jQuery ' + wp );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
The default options object that is extended when calling .waypoint. It has the
|
||||
following properties:
|
||||
|
||||
context
|
||||
string | element | jQuery*
|
||||
default: window
|
||||
The context defines which scrollable element the waypoint belongs to and acts
|
||||
within. The default, window, means the waypoint offset is calculated with relation
|
||||
to the whole viewport. You can set this to another element to use the waypoints
|
||||
within that element. Accepts a selector string, *but if you use jQuery 1.6+ it
|
||||
also accepts a raw HTML element or jQuery object.
|
||||
|
||||
continuous
|
||||
boolean
|
||||
default: true
|
||||
If true, and multiple waypoints are triggered in one scroll, this waypoint will
|
||||
trigger even if it is not the last waypoint reached. If false, it will only
|
||||
trigger if it is the last waypoint.
|
||||
|
||||
handler
|
||||
function
|
||||
default: undefined
|
||||
An alternative way to bind functions to the waypoint, without using the function
|
||||
as the first argument to the waypoint function.
|
||||
|
||||
offset
|
||||
number | string | function
|
||||
default: 0
|
||||
Determines how far the top of the element must be from the top of the browser
|
||||
window to trigger a waypoint. It can be a number, which is taken as a number
|
||||
of pixels, a string representing a percentage of the viewport height, or a
|
||||
function that will return a number of pixels.
|
||||
|
||||
onlyOnScroll
|
||||
boolean
|
||||
default: false
|
||||
If true, this waypoint will not trigger if an offset change during a refresh
|
||||
causes it to pass the current scroll point.
|
||||
|
||||
triggerOnce
|
||||
boolean
|
||||
default: false
|
||||
If true, the waypoint will be destroyed when triggered.
|
||||
|
||||
An offset of 250 would trigger the waypoint when the top of the element is 250px
|
||||
from the top of the viewport. Negative values for any offset work as you might
|
||||
expect. A value of -100 would trigger the waypoint when the element is 100px above
|
||||
the top of the window.
|
||||
|
||||
offset: '100%'
|
||||
|
||||
A string percentage will determine the pixel offset based on the height of the
|
||||
window. When resizing the window, this offset will automatically be recalculated
|
||||
without needing to call $.waypoints('refresh').
|
||||
|
||||
// The bottom of the element is in view
|
||||
offset: function() {
|
||||
return $.waypoints('viewportHeight') - $(this).outerHeight();
|
||||
}
|
||||
|
||||
Offset can take a function, which must return a number of pixels from the top of
|
||||
the window. The this value will always refer to the raw HTML element of the
|
||||
waypoint. As with % values, functions are recalculated automatically when the
|
||||
window resizes. For more on recalculating offsets, see $.waypoints('refresh').
|
||||
|
||||
An offset value of 'bottom-in-view' will act as an alias for the function in the
|
||||
example above, as this is a common usage.
|
||||
|
||||
offset: 'bottom-in-view'
|
||||
|
||||
You can see this alias in use on the Scroll Analytics example page.
|
||||
|
||||
The triggerOnce flag, if true, will destroy the waypoint after the first trigger.
|
||||
This is just a shortcut for calling .waypoint('destroy') within the waypoint
|
||||
handler. This is useful in situations such as scroll analytics, where you only
|
||||
want to record an event once for each page visit.
|
||||
|
||||
The context option lets you use Waypoints within an element other than the window.
|
||||
You can define the context with a selector string and the waypoint will act within
|
||||
the nearest ancestor that matches this selector.
|
||||
|
||||
$('.something-scrollable .waypoint').waypoint({
|
||||
context: '.something-scrollable'
|
||||
});
|
||||
|
||||
You can see this in action on the Dial Controls example.
|
||||
|
||||
The handler option gives authors an alternative way to bind functions when
|
||||
creating a waypoint. In place of:
|
||||
|
||||
$('.item').waypoint(function(event, direction) {
|
||||
// make things happen
|
||||
});
|
||||
|
||||
You may instead write:
|
||||
|
||||
$('.item').waypoint({
|
||||
handler: function(event, direction) {
|
||||
// make things happen
|
||||
}
|
||||
});
|
||||
|
||||
*/
|
||||
$.fn[wp].defaults = {
|
||||
continuous: true,
|
||||
offset: 0,
|
||||
triggerOnce: false,
|
||||
context: window
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
jQuery object extension. Delegates to appropriate methods above.
|
||||
*/
|
||||
$[wps] = function(method) {
|
||||
if (jQMethods[method]) {
|
||||
return jQMethods[method].apply(this);
|
||||
}
|
||||
else {
|
||||
return jQMethods['aggregate']();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
$.waypoints.settings
|
||||
|
||||
Settings object that determines some of the plugin’s behavior.
|
||||
|
||||
resizeThrottle
|
||||
number
|
||||
default: 200
|
||||
For performance reasons, the refresh performed during resizes is
|
||||
throttled. This value is the rate-limit in milliseconds between resize
|
||||
refreshes. For more information on throttling, check out Ben Alman’s
|
||||
throttle / debounce plugin.
|
||||
http://benalman.com/projects/jquery-throttle-debounce-plugin/
|
||||
|
||||
scrollThrottle
|
||||
number
|
||||
default: 100
|
||||
For performance reasons, checking for any crossed waypoints during a
|
||||
scroll event is throttled. This value is the rate-limit in milliseconds
|
||||
between scroll checks. For more information on throttling, check out Ben
|
||||
Alman’s throttle / debounce plugin.
|
||||
http://benalman.com/projects/jquery-throttle-debounce-plugin/
|
||||
*/
|
||||
$[wps].settings = {
|
||||
resizeThrottle: 200,
|
||||
scrollThrottle: 100
|
||||
};
|
||||
|
||||
$w.load(function() {
|
||||
// Calculate everything once on load.
|
||||
$[wps]('refresh');
|
||||
});
|
||||
})(jQuery, 'waypoint', 'waypoints', window);
|
|
@ -1,163 +0,0 @@
|
|||
$ = jQuery.sub()
|
||||
|
||||
class App.WebSocket
|
||||
_instance = undefined # Must be declared here to force the closure on the class
|
||||
@connect: (args) -> # Must be a static method
|
||||
if _instance == undefined
|
||||
_instance ?= new _Singleton
|
||||
_instance
|
||||
|
||||
@close: (args) -> # Must be a static method
|
||||
if _instance isnt undefined
|
||||
_instance.close()
|
||||
|
||||
@send: (args) -> # Must be a static method
|
||||
@connect()
|
||||
_instance.send(args)
|
||||
|
||||
@auth: (args) -> # Must be a static method
|
||||
@connect()
|
||||
_instance.auth(args)
|
||||
|
||||
# The actual Singleton class
|
||||
class _Singleton extends App.Controller
|
||||
queue: []
|
||||
supported: true
|
||||
|
||||
constructor: (@args) ->
|
||||
@connect()
|
||||
|
||||
send: (data) =>
|
||||
return if !@supported
|
||||
# console.log 'ws:send trying', data, @ws, @ws.readyState
|
||||
|
||||
# A value of 0 indicates that the connection has not yet been established.
|
||||
# A value of 1 indicates that the connection is established and communication is possible.
|
||||
# A value of 2 indicates that the connection is going through the closing handshake.
|
||||
# A value of 3 indicates that the connection has been closed or could not be opened.
|
||||
if @ws.readyState is 0
|
||||
@queue.push data
|
||||
else
|
||||
# console.log( 'ws:send', data )
|
||||
string = JSON.stringify( data )
|
||||
@ws.send(string)
|
||||
|
||||
auth: (data) =>
|
||||
return if !@supported
|
||||
|
||||
# logon websocket
|
||||
data = {
|
||||
action: 'login',
|
||||
session: window.Session
|
||||
}
|
||||
@send(data)
|
||||
|
||||
close: =>
|
||||
return if !@supported
|
||||
|
||||
@ws.close()
|
||||
|
||||
ping: =>
|
||||
return if !@supported
|
||||
|
||||
# console.log 'send websockend ping'
|
||||
@send( { action: 'ping' } )
|
||||
|
||||
# check if ping is back within 2 min
|
||||
@clearDelay('websocket-ping-check')
|
||||
check = =>
|
||||
console.log 'no websockend ping response, reconnect...'
|
||||
@close()
|
||||
@delay check, 120000, 'websocket-ping-check'
|
||||
|
||||
pong: ->
|
||||
return if !@supported
|
||||
# console.log 'received websockend ping'
|
||||
|
||||
# test again after 1 min
|
||||
@delay @ping, 60000
|
||||
|
||||
connect: =>
|
||||
# console.log '------------ws connect....--------------'
|
||||
|
||||
if !window.WebSocket
|
||||
@error = new App.ErrorModal(
|
||||
message: 'Sorry, no websocket support!'
|
||||
)
|
||||
@supported = false
|
||||
return
|
||||
|
||||
protocol = 'ws://'
|
||||
if window.location.protocol is 'https:'
|
||||
protocol = 'wss://'
|
||||
|
||||
@ws = new window.WebSocket( protocol + window.location.hostname + ":6042/" )
|
||||
|
||||
# Set event handlers.
|
||||
@ws.onopen = =>
|
||||
console.log( 'onopen' )
|
||||
|
||||
# close error message show up (because try so connect again) if exists
|
||||
@clearDelay('websocket-no-connection-try-reconnect')
|
||||
if @error
|
||||
@error.modalHide()
|
||||
@error = undefined
|
||||
|
||||
@auth()
|
||||
|
||||
# empty queue
|
||||
for item in @queue
|
||||
# console.log( 'ws:send queue', item )
|
||||
@send(item)
|
||||
@queue = []
|
||||
|
||||
# send ping to check connection
|
||||
@delay @ping, 60000
|
||||
|
||||
@ws.onmessage = (e) =>
|
||||
pipe = JSON.parse( e.data )
|
||||
console.log( 'ws:onmessage', pipe )
|
||||
|
||||
# go through all blocks
|
||||
for item in pipe
|
||||
|
||||
# reset reconnect loop
|
||||
if item['action'] is 'pong'
|
||||
@pong()
|
||||
|
||||
# fill collection
|
||||
if item['collection']
|
||||
console.log( "ws:onmessage collection:" + item['collection'] )
|
||||
App.Store.write( item['collection'], item['data'] )
|
||||
|
||||
# fire event
|
||||
if item['event']
|
||||
if typeof item['event'] is 'object'
|
||||
for event in item['event']
|
||||
console.log( "ws:onmessage event:" + event )
|
||||
App.Event.trigger( event, item['data'] )
|
||||
else
|
||||
console.log( "ws:onmessage event:" + item['event'] )
|
||||
App.Event.trigger( item['event'], item['data'] )
|
||||
|
||||
# bind to send messages
|
||||
App.Event.bind 'ws:send', (data) =>
|
||||
@send(data)
|
||||
|
||||
@ws.onclose = (e) =>
|
||||
console.log( 'onclose', e )
|
||||
|
||||
# show error message, first try to reconnect
|
||||
if !@error
|
||||
message = =>
|
||||
@error = new App.ErrorModal(
|
||||
message: 'No connection to websocket, trying to reconnect...'
|
||||
)
|
||||
@delay message, 7000, 'websocket-no-connection-try-reconnect'
|
||||
|
||||
# try reconnect after 4.5 sec.
|
||||
@delay @connect, 4500
|
||||
|
||||
@ws.onerror = ->
|
||||
console.log( 'onerror' )
|
||||
|
Loading…
Reference in a new issue