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]
18 TODO Skype widget -bergie
19 TODO Formatter service
20 TODO XMMP & Email formatter
22 TODO Implement arhive view
23 TODO Implement file attachments
24 TODO Documentation (API)
27 if (typeof console == 'undefined') {
29 console.log = function() {
36 $.ajatus.application_content_area = null;
38 $.ajatus.version = [0, 6, 0];
40 $.ajatus.active_type = null;
43 * Holds all converters available in Ajatus.
45 $.ajatus.converter = {};
48 * Parses and evaluates JSON string to Javascript
49 * @param {String} json_str JSON String
50 * @returns Parsed JSON string or false on failure
52 $.ajatus.converter.parseJSON = function (json_str) {
54 var re = new RegExp('[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]');
55 return !(re.test(json_str.replace(/"(\\.|[^"\\])*"/g, ''))) && eval('(' + json_str + ')');
62 * Parses Javascript to JSON
63 * @param {Mixed} item Javascript to be parsed
64 * @param {String} type of the Javascript item to be parsed (Optional)
65 * @returns JSON string
68 $.ajatus.converter.toJSON = function (item,item_type) {
80 var a = ['['], b, f, i, l = x.length, v;
81 for (i = 0; i < l; i += 1) {
84 if (typeof v == 'string') {
102 return isFinite(x) ? String(x) : 'null';
106 if (x instanceof Array) {
109 var a = ['{'], b, f, i, v;
113 if (typeof v == 'string') {
117 a.push(s.str(i), ':', v);
127 if (/["\\\x00-\x1f]/.test(x)) {
128 x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
135 Math.floor(c / 16).toString(16) +
136 (c % 16).toString(16);
139 return '"' + x + '"';
142 conv = function (x) {
143 var itemtype = typeof x;
166 var itemtype = item_type || typeof item;
187 throw("Unknown type for $.ajatus.converter.toJSON");
192 * Holds all formatters available in Ajatus.
195 $.ajatus.formatter = {};
198 * Holds all date formatters available in Ajatus.
201 $.ajatus.formatter.date = {};
204 * Formats numbers < 10 to two digit numbers
205 * @param {Number} number Number to format
206 * @returns Formatted number
209 $.ajatus.formatter.date.fix_length = function(number){
210 return ((number < 10) ? '0' : '') + number;
214 * Checks if given value is ISO8601 Formatted Date
215 * @param {String} value Value to check
216 * @returns True, False if value not string or ISO8601 formatted
219 $.ajatus.formatter.date.is_iso8601 = function(value) {
220 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));
229 if ( typeof isod == 'object'
230 && typeof isod[10] != 'undefined')
239 * Converts JS Date to ISO8601 Formatted JS Date
240 * @param {Date} date Javascript date to convert
241 * @returns ISO8601 formatted Date
244 $.ajatus.formatter.date.js_to_iso8601 = function(date) {
246 str += date.getFullYear();
247 str += "-" + $.ajatus.formatter.date.fix_length(date.getMonth() + 1);
248 str += "-" + $.ajatus.formatter.date.fix_length(date.getDate());
249 str += "T" + $.ajatus.formatter.date.fix_length(date.getHours());
250 str += ":" + $.ajatus.formatter.date.fix_length(date.getMinutes());
251 str += ":" + $.ajatus.formatter.date.fix_length(date.getSeconds());
258 * Converts ISO8601 Formatted JS Date to JS Date
259 * @param {Date} iso_date ISO8601 formatted date to convert
260 * @returns Javascript Date
263 $.ajatus.formatter.date.iso8601_to_js = function(iso_date) {
264 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})))?)?)?)?";
265 var isod = iso_date.match(new RegExp(regexp));
273 var date = new Date(isod[1], 0, 1);
274 date.setMonth(isod[3] - 1);
275 date.setDate(isod[5]);
276 date.setHours(isod[7]);
277 date.setMinutes(isod[8]);
278 date.setSeconds(isod[10]);
284 * Converts Date string from calendar widget to ISO8601 Formatted JS Date
285 * @param {String} caldate Date value from calendar widget
286 * @param {String} format Format used in conversion (Default: "MDY/")
287 * @param {String} caltime Time value from calendar widget
288 * @param {String} time_format Format used in conversion (Default: "HMS:")
289 * @returns ISO8601 formatted Javascript Date
292 $.ajatus.formatter.date.caldate_to_iso8601 = function(caldate, format, caltime, time_format) {
294 var format = format || ($.ajatus.i10n.datetime.date || "MDY/");
295 var time_format = time_format || ($.ajatus.i10n.datetime.time || "HMS:");
297 var cdparts = caldate.split(format.charAt(3));
298 var fparts = format.split("");
299 var date = new Date();
301 $.each(cdparts, function(i,v){
303 if (fparts[i] == 'M') {
306 if (fparts[i] == 'D') {
309 if (fparts[i] == 'Y') {
315 var time_separator = time_format.charAt(time_format.length - 1);
316 var tfparts = time_format.split("");
317 var ctparts = caltime.split(time_separator);
319 $.each(ctparts, function(i,v){
321 if (tfparts[i] == 'H') {
324 if (tfparts[i] == 'M') {
327 if (tfparts[i] == 'S') {
337 return $.ajatus.formatter.date.js_to_iso8601(date);
341 * Converts ISO8601 Formatted JS Date to calendar widget date string
342 * @param {Date} iso_date ISO8601 Formatted Date
343 * @param {String} format Format used in conversion (Default: "MDY/")
344 * @returns Calendar widget supported value
347 $.ajatus.formatter.date.iso8601_to_caldate = function(iso_date, format) {
348 var format = format || ($.ajatus.i10n.datetime.date || "MDY/");
350 var date = $.ajatus.formatter.date.iso8601_to_js(iso_date);
353 var day = date.getDate();
354 var month = date.getMonth();
355 var year = date.getFullYear();
358 for (var i = 0; i < 3; i++) {
359 date_str += format.charAt(3) +
360 (format.charAt(i) == 'D' ? $.ajatus.formatter.date.fix_length(day) :
361 (format.charAt(i) == 'M' ? $.ajatus.formatter.date.fix_length(month) :
362 (format.charAt(i) == 'Y' ? year : '?')));
364 date_str = date_str.substring(format.charAt(3) ? 1 : 0);
370 * Converts ISO8601 Formatted JS Date to calendar widget time string
371 * @param {Date} iso_date ISO8601 Formatted Date
372 * @param {String} format Format used in conversion (Default: "HMS:")
373 * @returns Calendar widget supported value
376 $.ajatus.formatter.date.iso8601_to_caltime = function(iso_date, format) {
377 var format = format || ($.ajatus.i10n.datetime.time || "HMS:");
379 var date = $.ajatus.formatter.date.iso8601_to_js(iso_date);
383 H: $.ajatus.formatter.date.fix_length(date.getHours()),
384 M: $.ajatus.formatter.date.fix_length(date.getMinutes()),
385 S: $.ajatus.formatter.date.fix_length(date.getSeconds())
388 var separator = format.charAt(format.length - 1);
389 var fparts = format.split("");
391 $.each(fparts, function(i,k){
392 if (typeof idparts[k] != 'undefined') {
393 time_str += idparts[k] + separator;
396 time_str = time_str.substring((time_str.length-1), -1);
402 $.ajatus.tabs.prepare = function(tab) {
403 tab.bind('mouseover', function(e){
404 tab.addClass('tabs-hover');
406 tab.bind('mouseout', function(e){
407 tab.removeClass('tabs-hover');
410 $.ajatus.tabs.set_active_by_hash = function(hash) {
411 // $.ajatus.debug('$.ajatus.tabs.set_active_by_hash('+hash+')');
413 var views_tab_holder = $('#tabs-views ul');
414 var app_tab_holder = $('#tabs-application ul');
416 var selected_tab = $('li a[@href$="' + hash + '"]', views_tab_holder).parent();
417 if (typeof selected_tab[0] != 'undefined') {
418 // $.ajatus.debug('views selected_tab:');
419 // $.ajatus.debug(selected_tab);
420 $('li', views_tab_holder).removeClass('tabs-selected').blur();
421 $('li', app_tab_holder).removeClass('tabs-selected').blur();
422 selected_tab.addClass('tabs-selected').focus();
424 selected_tab = $('li a[@href$="' + hash + '"]', app_tab_holder).parent();
425 // $.ajatus.debug('app selected_tab:');
426 // $.ajatus.debug(selected_tab);
427 if (typeof selected_tab[0] != 'undefined') {
428 $('li', views_tab_holder).removeClass('tabs-selected').blur();
429 $('li', app_tab_holder).removeClass('tabs-selected').blur();
430 selected_tab.addClass('tabs-selected').focus();
432 $('li', views_tab_holder).removeClass('tabs-selected').blur();
433 $('li', app_tab_holder).removeClass('tabs-selected').blur();
437 $.ajatus.tabs.on_click = function(e) {
438 var trgt = target(e);
439 $("li", parent(e)).removeClass("tabs-selected").index(trgt);
440 $(trgt).addClass("tabs-selected");
442 var new_hash = $('a', trgt)[0].hash;
443 location.hash = new_hash;
445 $.ajatus.history.update(new_hash);
447 $.ajatus.views.on_change(new_hash);
449 function parent(event) {
450 var element = event.target;
453 if (element.tagName == "UL")
458 while(element.tagName != "UL")
460 element = element.parentNode;
466 function target(event) {
467 var element = event.target;
470 if (element.tagName == "UL")
472 element = $(element).find('li').eq(0);
476 while(element.tagName != "LI")
478 element = element.parentNode;
485 $.ajatus.security_pass = function() {
487 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead UniversalBrowserWrite UniversalFileRead");
489 alert("Permission UniversalBrowserRead denied. with error "+e);
493 $.ajatus.init = function(element, options) {
494 //$.ajatus.security_pass();
496 var application_element = $(element);
497 $.ajatus.application_element = application_element;
498 $.ajatus.application_content_area = $('#middle #content', $.ajatus.application_element);
499 $.ajatus.application_dynamic_elements = $('#dynamic-elements', $.ajatus.application_element);
501 $.ajatus.preferences.client.server_url = window.location.protocol + '//' + document.hostname + (window.location.port != '' ? ':'+window.location.port : '') + '/';
503 $.ajatus.preferences.client = $.extend({}, $.ajatus.preferences.client_defaults, options);
504 //Force the system types to load:
505 $.ajatus.preferences.client.types.system = $.ajatus.preferences.client_defaults.types.system;
507 $.jqCouch.set_defaults({
508 server_url: $.ajatus.preferences.client.server_url
511 var a_db_suffix = $.ajatus.preferences.client.application_database_identifier != '' ? '_db' : 'db';
512 $.ajatus.preferences.client.application_database = 'ajatus_' + $.ajatus.preferences.client.application_database_identifier + a_db_suffix;
513 $.ajatus.preferences.client.content_database = $.ajatus.preferences.client.application_database + '_content';
517 url: $.ajatus.preferences.client.server_url,
523 $.ajatus.installer.is_installed();
524 if ($.ajatus.installer.installed == false) {
526 if ($.ajatus.preferences.client.language == null) {
528 $.ajatus.preferences.client.language = 'en_GB';
530 $.ajatus.i10n.init($.ajatus.preferences.client.language, function(){
531 var status = $.ajatus.installer.install();
532 $.ajatus.debug("Installer finished with status: "+status);
534 window.location = window.location + "#view.preferences";
542 // $.ajatus.installer.uninstall();
546 $.ajatus.preload = function() {
547 var preference_loader = new $.ajatus.preferences.loader;
548 preference_loader.load();
550 if ($.ajatus.preferences.client.language == null) {
552 if (typeof($.ajatus.preferences.local.localization) != 'undefined') {
553 lang = $.ajatus.preferences.local.localization.language;
555 $.ajatus.preferences.client.language = lang;
557 $.ajatus.i10n.init($.ajatus.preferences.client.language, function(){
558 $.ajatus.types.init(function(){
564 $.ajatus.start = function() {
565 $.ajatus.debug('started', 'Ajatus start');
567 $.ajatus.events.lock_pool.increase();
569 // $.ajatus.cookies.init();
571 if ($.ajatus.preferences.local.layout.theme_name != 'default') {
572 $.ajatus.preferences.client.theme_url = 'themes/' + $.ajatus.preferences.local.layout.theme_name + '/';
573 $.ajatus.preferences.client.theme_icons_url = 'themes/' + $.ajatus.preferences.local.layout.icon_set + '/images/icons/';
575 $.ajatus.layout.styles.load($.ajatus.preferences.client.theme_url + 'css/structure.css');
576 $.ajatus.layout.styles.load($.ajatus.preferences.client.theme_url + 'css/common.css');
577 $.ajatus.layout.styles.load($.ajatus.preferences.client.theme_url + 'css/elements.css');
580 $.ajatus.locker = new $.ajatus.events.lock({
582 validate: function(){return $.ajatus.events.lock_pool.count == 0;},
586 on_release: function(){
587 $.ajatus.application_element.addClass('ajatus_initialized');
589 var show_frontpage = !$.ajatus.history.check();
591 if (show_frontpage) {
592 $.ajatus.views.system.frontpage.render();
597 if (! $.jqCouch.connection('doc').get($.ajatus.preferences.client.application_database + '/version')._id) {
598 $.jqCouch.connection('doc').put($.ajatus.preferences.client.application_database + '/version', {value: $.ajatus.version});
601 $('#header .app_version', $.ajatus.application_element).html($.ajatus.version.join('.'));
602 $('#header .tagline', $.ajatus.application_element).html($.ajatus.i10n.get('Distributed CRM'));
603 $('#new-item-button').text($.ajatus.i10n.get('new'));
605 $.ajatus.toolbar.init();
606 $.ajatus.history.init();
607 $.ajatus.tags.init();
608 $.ajatus.widgets.init();
609 $.ajatus.views.init();
611 $.ajatus.extensions.init({
612 on_ready: function(){
613 $.ajatus.active_type = $.ajatus.preferences.client.content_types['note'];
615 if ($.ajatus.preferences.modified) {
616 $.ajatus.views.on_change_actions.add('$.ajatus.preferences.view.save($.ajatus.preferences.local)');
619 // var gen_docs = $.ajatus.utils.doc_generator('notes', 200);
620 // $.jqCouch.connection('doc').bulk_save($.ajatus.preferences.client.content_database, gen_docs);
622 // Release the first lock
623 $.ajatus.events.lock_pool.decrease();
627 $.ajatus.elements.messages.set_holder();
629 window.onbeforeunload = function() {
630 if ($.ajatus.events.named_lock_pool.count('unsaved') > 0) {
631 return $.ajatus.i10n.get('You have unsaved changes.');
635 $.ajatus.debug('ended', 'Ajatus start');
638 $.ajatus.ajax_error = function(request, caller) {
639 $.ajatus.debug("Ajax error request.status: "+request.status);
641 if (typeof caller != 'undefined') {
642 $.ajatus.debug("Caller method: "+caller.method);
643 $.ajatus.debug("Caller action:");
644 $.ajatus.debug(caller.action);
646 if (caller.args != undefined) {
647 $.ajatus.debug("Caller args:");
648 $.ajatus.debug(caller.args);
652 if (request.responseText != '') {
653 var response = eval("(" + request.responseText + ")");
654 $.ajatus.debug('response.error.reason: '+response.error.reason);
657 $.ajatus.ajax_success = function(data, caller) {
658 $.ajatus.debug("Ajax success");
660 if (typeof caller != 'undefined') {
661 $.ajatus.debug("Caller method: "+caller.method);
662 $.ajatus.debug("Caller action: "+caller.action);
664 if (typeof caller.args != 'undefined') {
665 $.ajatus.debug("Caller args: "+caller.args);
668 $.ajatus.debug("data: "+data);
673 $.ajatus.debug = function(msg, title, type) {
674 if ($.ajatus.preferences.client.debug == true) {
675 if (typeof(console.log) != 'undefined') {
676 debug_console(msg, title, type);
678 debug_static(msg, title, type);
682 function debug_console(msg, title, type) {
683 if (typeof type == 'undefined') {
687 if (typeof(console[type]) != 'undefined') {
688 console.log(format(msg, title));
690 console.log(format(msg, title));
694 function debug_static(msg, title, type) {
695 // TODO: Implement Static debug handler
698 function format(msg, title) {
701 if (typeof title != 'undefined') {
702 string += title += ': ';
705 if (typeof msg != 'string') {
706 string += $.ajatus.utils.pretty_print(msg);
715 $.fn.initialize_ajatus = function(options) {
716 if (! $(this).is('.ajatus_initialized')) {
717 return new $.ajatus.init(this, options);
723 function initialize_ajatus() {
724 if (typeof ajatus_client_config == 'undefined') {
725 var ajatus_client_config = {};
728 jQuery('#application').initialize_ajatus($.extend({
735 // 'note', 'contact', 'event', 'expense', 'hour_report'
738 application_url: '/_utils/ajatus_dev/', // '/_utils/ajatus/'
739 application_database_identifier: 'dev' // ''
740 }, ajatus_client_config));
743 $(document).ready(function() {
747 alert("could not initialize ajatus! Reason: "+e);