4 * {@link http://ajatus.info Ajatus - Distributed CRM}
5 * @requires jQuery v1.2.1
7 * Copyright (c) 2007 Jerry Jalava <jerry.jalava@gmail.com>
8 * Copyright (c) 2007 Nemein Oy <http://nemein.com>
9 * Website: http://ajatus.info
10 * Licensed under the GPL license
11 * http://www.gnu.org/licenses/gpl.html
17 TODO Additional fields [widget, support]
18 TODO Skype widget -bergie
19 TODO Formatter service
20 TODO XMMP & Email formatter
22 TODO Implement arhive view and action
23 TODO Implement file attachments
24 TODO Documentation (API)
25 TODO Auto-saving to forms (after 5 mins)
26 TODO Context syntax tags (me:, attn:, by:, for:)
29 if (typeof console
== 'undefined') {
31 console
.log = function() {
38 $.ajatus
.application_content_area
= null;
40 $.ajatus
.version
= [0, 0, 9];
42 $.ajatus
.active_type
= null;
45 * Holds all converters available in Ajatus.
47 $.ajatus
.converter
= {};
50 * Parses and evaluates JSON string to Javascript
51 * @param {String} json_str JSON String
52 * @returns Parsed JSON string or false on failure
54 $.ajatus
.converter
.parseJSON = function (json_str
) {
56 return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
57 json_str
.replace(/"(\\.|[^"\\])*"/g, ''))) &&
58 eval('(' + json_str
+ ')');
65 * Parses Javascript to JSON
66 * @param {Mixed} item Javascript to be parsed
67 * @param {String} type of the Javascript item to be parsed (Optional)
68 * @returns JSON string
71 $.ajatus
.converter
.toJSON = function (item
,item_type
) {
83 var a
= ['['], b
, f
, i
, l
= x
.length
, v
;
84 for (i
= 0; i
< l
; i
+= 1) {
87 if (typeof v
== 'string') {
105 return isFinite(x
) ? String(x
) : 'null';
109 if (x
instanceof Array
) {
112 var a
= ['{'], b
, f
, i
, v
;
116 if (typeof v
== 'string') {
120 a
.push(s
.str(i
), ':', v
);
130 if (/["\\\x00-\x1f]/.test(x
)) {
131 x
= x
.replace(/([\x00-\x1f\\"])/g, function(a
, b
) {
138 Math
.floor(c
/ 16).toString(16) +
139 (c
% 16).toString(16);
142 return '"' + x
+ '"';
145 conv = function (x
) {
146 var itemtype
= typeof x
;
169 var itemtype
= item_type
|| typeof item
;
190 throw("Unknown type for $.ajatus.converter.toJSON");
195 * Holds all formatters available in Ajatus.
198 $.ajatus
.formatter
= {};
201 * Holds all date formatters available in Ajatus.
204 $.ajatus
.formatter
.date
= {};
207 * Formats numbers < 10 to two digit numbers
208 * @param {Number} number Number to format
209 * @returns Formatted number
212 $.ajatus
.formatter
.date
.fix_length = function(number
){
213 return ((number
< 10) ? '0' : '') + number
;
217 * Checks if given value is ISO8601 Formatted Date
218 * @param {String} value Value to check
219 * @returns True, False if value not string or ISO8601 formatted
222 $.ajatus
.formatter
.date
.is_iso8601 = function(value
) {
223 if (typeof value
!= 'string') {
226 var regexp
= "([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
227 var isod
= value
.match(new RegExp(regexp
));
235 * Converts JS Date to ISO8601 Formatted JS Date
236 * @param {Date} date Javascript date to convert
237 * @returns ISO8601 formatted Date
240 $.ajatus
.formatter
.date
.js_to_iso8601 = function(date
) {
242 str
+= date
.getFullYear();
243 str
+= "-" + $.ajatus
.formatter
.date
.fix_length(date
.getMonth() + 1);
244 str
+= "-" + $.ajatus
.formatter
.date
.fix_length(date
.getDate());
245 str
+= "T" + $.ajatus
.formatter
.date
.fix_length(date
.getHours());
246 str
+= ":" + $.ajatus
.formatter
.date
.fix_length(date
.getMinutes());
247 str
+= ":" + $.ajatus
.formatter
.date
.fix_length(date
.getSeconds());
254 * Converts ISO8601 Formatted JS Date to JS Date
255 * @param {Date} iso_date ISO8601 formatted date to convert
256 * @returns Javascript Date
259 $.ajatus
.formatter
.date
.iso8601_to_js = function(iso_date
) {
260 var regexp
= "([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
261 var isod
= iso_date
.match(new RegExp(regexp
));
269 var date
= new Date(isod
[1], 0, 1);
270 date
.setMonth(isod
[3] - 1);
271 date
.setDate(isod
[5]);
272 date
.setHours(isod
[7]);
273 date
.setMinutes(isod
[8]);
274 date
.setSeconds(isod
[10]);
280 * Converts Date string from calendar widget to ISO8601 Formatted JS Date
281 * @param {String} caldate Date value from calendar widget
282 * @param {String} format Format used in conversion (Default: "MDY/")
283 * @param {String} caltime Time value from calendar widget
284 * @param {String} time_format Format used in conversion (Default: "HMS:")
285 * @returns ISO8601 formated Javascript Date
288 $.ajatus
.formatter
.date
.caldate_to_iso8601 = function(caldate
, format
, caltime
, time_format
) {
290 var format
= format
|| ($.ajatus
.i10n
.datetime
.date
|| "MDY/");
291 var time_format
= time_format
|| ($.ajatus
.i10n
.datetime
.time
|| "HMS:");
293 var cdparts
= caldate
.split(format
.charAt(3));
294 var fparts
= format
.split("");
295 var date
= new Date();
297 $.each(cdparts
, function(i
,v
){
299 if (fparts
[i
] == 'M') {
302 if (fparts
[i
] == 'D') {
305 if (fparts
[i
] == 'Y') {
311 var time_separator
= time_format
.charAt(time_format
.length
- 1);
312 var tfparts
= time_format
.split("");
313 var ctparts
= caltime
.split(time_separator
);
315 $.each(ctparts
, function(i
,v
){
317 if (tfparts
[i
] == 'H') {
320 if (tfparts
[i
] == 'M') {
323 if (tfparts
[i
] == 'S') {
333 return $.ajatus
.formatter
.date
.js_to_iso8601(date
);
337 * Converts ISO8601 Formatted JS Date to calendar widget date string
338 * @param {Date} iso_date ISO8601 Fromatted Date
339 * @param {String} format Format used in conversion (Default: "MDY/")
340 * @returns Calendar widget supported value
343 $.ajatus
.formatter
.date
.iso8601_to_caldate = function(iso_date
, format
) {
344 var format
= format
|| ($.ajatus
.i10n
.datetime
.date
|| "MDY/");
346 var date
= $.ajatus
.formatter
.date
.iso8601_to_js(iso_date
);
349 var day
= date
.getDate();
350 var month
= date
.getMonth();
351 var year
= date
.getFullYear();
354 for (var i
= 0; i
< 3; i
++) {
355 date_str
+= format
.charAt(3) +
356 (format
.charAt(i
) == 'D' ? $.ajatus
.formatter
.date
.fix_length(day
) :
357 (format
.charAt(i
) == 'M' ? $.ajatus
.formatter
.date
.fix_length(month
) :
358 (format
.charAt(i
) == 'Y' ? year
: '?')));
360 date_str
= date_str
.substring(format
.charAt(3) ? 1 : 0);
366 * Converts ISO8601 Formatted JS Date to calendar widget time string
367 * @param {Date} iso_date ISO8601 Fromatted Date
368 * @param {String} format Format used in conversion (Default: "HMS:")
369 * @returns Calendar widget supported value
372 $.ajatus
.formatter
.date
.iso8601_to_caltime = function(iso_date
, format
) {
373 var format
= format
|| ($.ajatus
.i10n
.datetime
.time
|| "HMS:");
375 var date
= $.ajatus
.formatter
.date
.iso8601_to_js(iso_date
);
379 H
: $.ajatus
.formatter
.date
.fix_length(date
.getHours()),
380 M
: $.ajatus
.formatter
.date
.fix_length(date
.getMinutes()),
381 S
: $.ajatus
.formatter
.date
.fix_length(date
.getSeconds())
383 var separator
= format
.charAt(format
.length
- 1);
384 var fparts
= format
.split("");
386 $.each(fparts
, function(i
,k
){
387 time_str
+= fparts
[k
] + separator
;
389 time_str
= time_str
.substring(1);
395 $.ajatus
.tabs
.prepare = function(tab
) {
396 tab
.bind('mouseover', function(e
){
397 tab
.addClass('tabs-hover');
399 tab
.bind('mouseout', function(e
){
400 tab
.removeClass('tabs-hover');
403 $.ajatus
.tabs
.set_active_by_hash = function(hash
) {
404 // $.ajatus.debug('$.ajatus.tabs.set_active_by_hash('+hash+')');
406 $.ajatus
.views
.on_change(hash
);
408 var views_tab_holder
= $('#tabs-views ul');
409 var app_tab_holder
= $('#tabs-application ul');
411 var selected_tab
= jQuery('li a[@href$="' + hash
+ '"]', views_tab_holder
).parent();
412 if (selected_tab
[0] != undefined) {
413 // $.ajatus.debug('views selected_tab:');
414 // $.ajatus.debug(selected_tab);
415 jQuery('li', views_tab_holder
).removeClass('tabs-selected').blur();
416 jQuery('li', app_tab_holder
).removeClass('tabs-selected').blur();
417 selected_tab
.addClass('tabs-selected').focus();
419 selected_tab
= jQuery('li a[@href$="' + hash
+ '"]', app_tab_holder
).parent();
420 // $.ajatus.debug('app selected_tab:');
421 // $.ajatus.debug(selected_tab);
422 if (selected_tab
[0] != undefined) {
423 jQuery('li', views_tab_holder
).removeClass('tabs-selected').blur();
424 jQuery('li', app_tab_holder
).removeClass('tabs-selected').blur();
425 selected_tab
.addClass('tabs-selected').focus();
427 jQuery('li', views_tab_holder
).removeClass('tabs-selected').blur();
428 jQuery('li', app_tab_holder
).removeClass('tabs-selected').blur();
432 $.ajatus
.tabs
.on_click = function(e
) {
433 var trgt
= target(e
);
434 jQuery("li", parent(e
)).removeClass("tabs-selected").index(trgt
);
435 jQuery(trgt
).addClass("tabs-selected");
437 var new_hash
= jQuery('a', trgt
)[0].hash
;
438 location
.hash
= new_hash
;
440 if ( $.ajatus
.history
441 && $.ajatus
.history
.enabled
)
443 $.ajatus
.history
.update(new_hash
);
446 $.ajatus
.views
.on_change(new_hash
);
448 function parent(event
) {
449 var element
= event
.target
;
452 if (element
.tagName
== "UL")
457 while(element
.tagName
!= "UL")
459 element
= element
.parentNode
;
465 function target(event
) {
466 var element
= event
.target
;
469 if (element
.tagName
== "UL")
471 element
= jQuery(element
).find('li').eq(0);
475 while(element
.tagName
!= "LI")
477 element
= element
.parentNode
;
484 $.ajatus
.security_pass = function() {
486 netscape
.security
.PrivilegeManager
.enablePrivilege("UniversalBrowserRead UniversalBrowserWrite UniversalFileRead");
488 alert("Permission UniversalBrowserRead denied. with error "+e
);
492 $.ajatus
.init = function(element
, options
) {
493 //$.ajatus.security_pass();
495 var application_element
= $(element
);
496 $.ajatus
.application_element
= application_element
;
497 $.ajatus
.application_content_area
= $('#middle #content', $.ajatus
.application_element
);
498 $.ajatus
.application_dynamic_elements
= $('#dynamic-elements', $.ajatus
.application_element
);
500 $.ajatus
.preferences
.client
.server_url
= window
.location
.protocol
+ '//' + document
.hostname
+ (window
.location
.port
!= '' ? ':'+window
.location
.port
: '') + '/';
502 $.ajatus
.preferences
.client
= $.extend({}, $.ajatus
.preferences
.client_defaults
, options
);
503 //Force the system types to load:
504 $.ajatus
.preferences
.client
.types
.system
= $.ajatus
.preferences
.client_defaults
.types
.system
;
506 $.jqCouch
.set_defaults({
507 server_url
: $.ajatus
.preferences
.client
.server_url
510 var a_db_suffix
= $.ajatus
.preferences
.client
.application_database_identifier
!= '' ? '_db' : 'db';
511 $.ajatus
.preferences
.client
.application_database
= 'ajatus_' + $.ajatus
.preferences
.client
.application_database_identifier
+ a_db_suffix
;
512 $.ajatus
.preferences
.client
.content_database
= $.ajatus
.preferences
.client
.application_database
+ '_content';
513 $.ajatus
.preferences
.client
.tags_database
= $.ajatus
.preferences
.client
.application_database
+ '_tags';
517 url
: $.ajatus
.preferences
.client
.server_url
,
523 $('#top #new-item-button', application_element
).bind('click', function(e
){
524 $.ajatus
.views
.system
.create
.render($.ajatus
.active_type
);
527 $.ajatus
.installer
.is_installed();
528 if ($.ajatus
.installer
.installed
== false) {
529 var status
= $.ajatus
.installer
.install();
530 $.ajatus
.debug("Installer finished with status: "+status
);
532 window
.location
= window
.location
+ "#view.preferences";
539 // $.ajatus.installer.uninstall();
543 $.ajatus
.preload = function() {
544 var preference_loader
= new $.ajatus
.preferences
.loader
;
545 preference_loader
.load();
547 $.ajatus
.types
.init(function(){
552 $.ajatus
.start = function() {
553 $.ajatus
.debug('started', 'Ajatus start');
555 $.ajatus
.events
.lock_pool
.increase();
557 if ($.ajatus
.preferences
.client
.language
== null) {
559 if (typeof($.ajatus
.preferences
.local
.localization
) != 'undefined') {
560 lang
= $.ajatus
.preferences
.local
.localization
.language
;
562 $.ajatus
.preferences
.client
.language
= lang
;
564 $.ajatus
.i10n
.init($.ajatus
.preferences
.client
.language
);
566 if ($.ajatus
.preferences
.local
.layout
.theme
!= 'default') {
567 $.ajatus
.preferences
.client
.theme_url
= 'themes/' + $.ajatus
.preferences
.local
.layout
.theme
+ '/';
569 $.ajatus
.layout
.styles
.load($.ajatus
.preferences
.client
.theme_url
+ 'css/structure.css');
570 $.ajatus
.layout
.styles
.load($.ajatus
.preferences
.client
.theme_url
+ 'css/common.css');
571 $.ajatus
.layout
.styles
.load($.ajatus
.preferences
.client
.theme_url
+ 'css/elements.css');
574 $.ajatus
.locker
= new $.ajatus
.events
.lock({
576 validate: function(){return $.ajatus
.events
.lock_pool
.count
== 0;},
580 on_release: function(){
581 $.ajatus
.application_element
.addClass('ajatus_initialized');
583 var show_frontpage
= true;
584 if ( $.ajatus
.history
585 && $.ajatus
.history
.enabled
)
587 show_frontpage
= !$.ajatus
.history
.check();
590 if (show_frontpage
) {
591 $.ajatus
.views
.system
.frontpage
.render();
596 $('#header .app_version', $.ajatus
.application_element
).html($.ajatus
.version
.join('.'));
597 $('#header .tagline', $.ajatus
.application_element
).html($.ajatus
.i10n
.get('Distributed CRM'));
598 $('#new-item-button').text($.ajatus
.i10n
.get('new'));
600 $.ajatus
.toolbar
.init();
601 $.ajatus
.history
.init();
602 $.ajatus
.tags
.init();
603 $.ajatus
.widgets
.init();
604 $.ajatus
.views
.init();
606 $.ajatus
.extensions
.init({
607 on_ready: function(){
608 $.ajatus
.active_type
= $.ajatus
.preferences
.client
.content_types
['note'];
610 if ($.ajatus
.preferences
.modified
) {
611 $.ajatus
.views
.on_change_actions
.add('$.ajatus.preferences.view.save($.ajatus.preferences.local)');
614 // Release the first lock
615 $.ajatus
.events
.lock_pool
.decrease();
619 $.ajatus
.elements
.messages
.set_holder();
621 window
.onbeforeunload = function() {
622 if ($.ajatus
.events
.named_lock_pool
.count('unsaved') > 0) {
623 return $.ajatus
.i10n
.get('You have unsaved changes.');
627 $.ajatus
.debug('ended', 'Ajatus start');
630 $.ajatus
.ajax_error = function(request
, caller
) {
631 $.ajatus
.debug("Ajax error request.status: "+request
.status
);
633 if (typeof caller
!= 'undefined') {
634 $.ajatus
.debug("Caller method: "+caller
.method
);
635 $.ajatus
.debug("Caller action:");
636 $.ajatus
.debug(caller
.action
);
638 if (caller
.args
!= undefined) {
639 $.ajatus
.debug("Caller args:");
640 $.ajatus
.debug(caller
.args
);
644 if (request
.responseText
!= '') {
645 var response
= eval("(" + request
.responseText
+ ")");
646 $.ajatus
.debug('response.error.reason: '+response
.error
.reason
);
649 $.ajatus
.ajax_success = function(data
, caller
) {
650 $.ajatus
.debug("Ajax success");
652 if (typeof caller
!= 'undefined') {
653 $.ajatus
.debug("Caller method: "+caller
.method
);
654 $.ajatus
.debug("Caller action: "+caller
.action
);
656 if (typeof caller
.args
!= 'undefined') {
657 $.ajatus
.debug("Caller args: "+caller
.args
);
660 $.ajatus
.debug("data: "+data
);
665 $.ajatus
.debug = function(msg
, title
, type
) {
666 if ($.ajatus
.preferences
.client
.debug
== true) {
667 if (typeof(console
.log
) != 'undefined') {
668 debug_console(msg
, title
, type
);
670 debug_static(msg
, title
, type
);
674 function debug_console(msg
, title
, type
) {
675 if (typeof type
== 'undefined') {
679 if (typeof(console
[type
]) != 'undefined') {
680 console
.log(format(msg
, title
));
682 console
.log(format(msg
, title
));
686 function debug_static(msg
, title
, type
) {
687 // TODO: Implement Static debug handler
690 function format(msg
, title
) {
692 if (typeof title
!= 'undefined') {
693 string
+= title
+= ': ';
701 $.fn
.initialize_ajatus = function(options
) {
702 if (! $(this).is('.ajatus_initialized')) {
703 return new $.ajatus
.init(this, options
);
709 function initialize_ajatus() {
710 if (typeof ajatus_client_config
== 'undefined') {
711 var ajatus_client_config
= {};
714 jQuery('#application').initialize_ajatus($.extend({
721 // 'note', 'contact', 'event', 'expense', 'hour_report'
724 application_url
: '/_utils/ajatus_dev/', // '/_utils/ajatus/'
725 application_database_identifier
: 'dev' // 'stable'
726 }, ajatus_client_config
));
729 jQuery(document
).ready(function() {
733 alert("could not initialize ajatus! Reason: "+e
);