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, 0, 9];
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 return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
55 json_str.replace(/"(\\.|[^"\\])*"/g, ''))) &&
56 eval('(' + json_str + ')');
63 * Parses Javascript to JSON
64 * @param {Mixed} item Javascript to be parsed
65 * @param {String} type of the Javascript item to be parsed (Optional)
66 * @returns JSON string
69 $.ajatus.converter.toJSON = function (item,item_type) {
81 var a = ['['], b, f, i, l = x.length, v;
82 for (i = 0; i < l; i += 1) {
85 if (typeof v == 'string') {
103 return isFinite(x) ? String(x) : 'null';
107 if (x instanceof Array) {
110 var a = ['{'], b, f, i, v;
114 if (typeof v == 'string') {
118 a.push(s.str(i), ':', v);
128 if (/["\\\x00-\x1f]/.test(x)) {
129 x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
136 Math.floor(c / 16).toString(16) +
137 (c % 16).toString(16);
140 return '"' + x + '"';
143 conv = function (x) {
144 var itemtype = typeof x;
167 var itemtype = item_type || typeof item;
188 throw("Unknown type for $.ajatus.converter.toJSON");
193 * Holds all formatters available in Ajatus.
196 $.ajatus.formatter = {};
199 * Holds all date formatters available in Ajatus.
202 $.ajatus.formatter.date = {};
205 * Formats numbers < 10 to two digit numbers
206 * @param {Number} number Number to format
207 * @returns Formatted number
210 $.ajatus.formatter.date.fix_length = function(number){
211 return ((number < 10) ? '0' : '') + number;
215 * Checks if given value is ISO8601 Formatted Date
216 * @param {String} value Value to check
217 * @returns True, False if value not string or ISO8601 formatted
220 $.ajatus.formatter.date.is_iso8601 = function(value) {
221 if ( typeof value != 'string'
227 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})))?)?)?)?";
228 var isod = value.match(new RegExp(regexp));
230 if ( typeof isod == 'object'
231 && typeof isod[10] != 'undefined')
240 * Converts JS Date to ISO8601 Formatted JS Date
241 * @param {Date} date Javascript date to convert
242 * @returns ISO8601 formatted Date
245 $.ajatus.formatter.date.js_to_iso8601 = function(date) {
247 str += date.getFullYear();
248 str += "-" + $.ajatus.formatter.date.fix_length(date.getMonth() + 1);
249 str += "-" + $.ajatus.formatter.date.fix_length(date.getDate());
250 str += "T" + $.ajatus.formatter.date.fix_length(date.getHours());
251 str += ":" + $.ajatus.formatter.date.fix_length(date.getMinutes());
252 str += ":" + $.ajatus.formatter.date.fix_length(date.getSeconds());
259 * Converts ISO8601 Formatted JS Date to JS Date
260 * @param {Date} iso_date ISO8601 formatted date to convert
261 * @returns Javascript Date
264 $.ajatus.formatter.date.iso8601_to_js = function(iso_date) {
265 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})))?)?)?)?";
266 var isod = iso_date.match(new RegExp(regexp));
274 var date = new Date(isod[1], 0, 1);
275 date.setMonth(isod[3] - 1);
276 date.setDate(isod[5]);
277 date.setHours(isod[7]);
278 date.setMinutes(isod[8]);
279 date.setSeconds(isod[10]);
285 * Converts Date string from calendar widget to ISO8601 Formatted JS Date
286 * @param {String} caldate Date value from calendar widget
287 * @param {String} format Format used in conversion (Default: "MDY/")
288 * @param {String} caltime Time value from calendar widget
289 * @param {String} time_format Format used in conversion (Default: "HMS:")
290 * @returns ISO8601 formatted Javascript Date
293 $.ajatus.formatter.date.caldate_to_iso8601 = function(caldate, format, caltime, time_format) {
295 var format = format || ($.ajatus.i10n.datetime.date || "MDY/");
296 var time_format = time_format || ($.ajatus.i10n.datetime.time || "HMS:");
298 var cdparts = caldate.split(format.charAt(3));
299 var fparts = format.split("");
300 var date = new Date();
302 $.each(cdparts, function(i,v){
304 if (fparts[i] == 'M') {
307 if (fparts[i] == 'D') {
310 if (fparts[i] == 'Y') {
316 var time_separator = time_format.charAt(time_format.length - 1);
317 var tfparts = time_format.split("");
318 var ctparts = caltime.split(time_separator);
320 $.each(ctparts, function(i,v){
322 if (tfparts[i] == 'H') {
325 if (tfparts[i] == 'M') {
328 if (tfparts[i] == 'S') {
338 return $.ajatus.formatter.date.js_to_iso8601(date);
342 * Converts ISO8601 Formatted JS Date to calendar widget date string
343 * @param {Date} iso_date ISO8601 Formatted Date
344 * @param {String} format Format used in conversion (Default: "MDY/")
345 * @returns Calendar widget supported value
348 $.ajatus.formatter.date.iso8601_to_caldate = function(iso_date, format) {
349 var format = format || ($.ajatus.i10n.datetime.date || "MDY/");
351 var date = $.ajatus.formatter.date.iso8601_to_js(iso_date);
354 var day = date.getDate();
355 var month = date.getMonth();
356 var year = date.getFullYear();
359 for (var i = 0; i < 3; i++) {
360 date_str += format.charAt(3) +
361 (format.charAt(i) == 'D' ? $.ajatus.formatter.date.fix_length(day) :
362 (format.charAt(i) == 'M' ? $.ajatus.formatter.date.fix_length(month) :
363 (format.charAt(i) == 'Y' ? year : '?')));
365 date_str = date_str.substring(format.charAt(3) ? 1 : 0);
371 * Converts ISO8601 Formatted JS Date to calendar widget time string
372 * @param {Date} iso_date ISO8601 Formatted Date
373 * @param {String} format Format used in conversion (Default: "HMS:")
374 * @returns Calendar widget supported value
377 $.ajatus.formatter.date.iso8601_to_caltime = function(iso_date, format) {
378 var format = format || ($.ajatus.i10n.datetime.time || "HMS:");
380 var date = $.ajatus.formatter.date.iso8601_to_js(iso_date);
384 H: $.ajatus.formatter.date.fix_length(date.getHours()),
385 M: $.ajatus.formatter.date.fix_length(date.getMinutes()),
386 S: $.ajatus.formatter.date.fix_length(date.getSeconds())
389 var separator = format.charAt(format.length - 1);
390 var fparts = format.split("");
392 $.each(fparts, function(i,k){
393 if (typeof idparts[k] != 'undefined') {
394 time_str += idparts[k] + separator;
397 time_str = time_str.substring((time_str.length-1), -1);
403 $.ajatus.tabs.prepare = function(tab) {
404 tab.bind('mouseover', function(e){
405 tab.addClass('tabs-hover');
407 tab.bind('mouseout', function(e){
408 tab.removeClass('tabs-hover');
411 $.ajatus.tabs.set_active_by_hash = function(hash) {
412 // $.ajatus.debug('$.ajatus.tabs.set_active_by_hash('+hash+')');
414 var views_tab_holder = $('#tabs-views ul');
415 var app_tab_holder = $('#tabs-application ul');
417 var selected_tab = $('li a[@href$="' + hash + '"]', views_tab_holder).parent();
418 if (selected_tab[0] != undefined) {
419 // $.ajatus.debug('views selected_tab:');
420 // $.ajatus.debug(selected_tab);
421 $('li', views_tab_holder).removeClass('tabs-selected').blur();
422 $('li', app_tab_holder).removeClass('tabs-selected').blur();
423 selected_tab.addClass('tabs-selected').focus();
425 selected_tab = $('li a[@href$="' + hash + '"]', app_tab_holder).parent();
426 // $.ajatus.debug('app selected_tab:');
427 // $.ajatus.debug(selected_tab);
428 if (selected_tab[0] != undefined) {
429 $('li', views_tab_holder).removeClass('tabs-selected').blur();
430 $('li', app_tab_holder).removeClass('tabs-selected').blur();
431 selected_tab.addClass('tabs-selected').focus();
433 $('li', views_tab_holder).removeClass('tabs-selected').blur();
434 $('li', app_tab_holder).removeClass('tabs-selected').blur();
438 $.ajatus.tabs.on_click = function(e) {
439 var trgt = target(e);
440 $("li", parent(e)).removeClass("tabs-selected").index(trgt);
441 $(trgt).addClass("tabs-selected");
443 var new_hash = $('a', trgt)[0].hash;
444 location.hash = new_hash;
446 if ( $.ajatus.history
447 && $.ajatus.history.enabled)
449 $.ajatus.history.update(new_hash);
452 $.ajatus.views.on_change(new_hash);
454 function parent(event) {
455 var element = event.target;
458 if (element.tagName == "UL")
463 while(element.tagName != "UL")
465 element = element.parentNode;
471 function target(event) {
472 var element = event.target;
475 if (element.tagName == "UL")
477 element = $(element).find('li').eq(0);
481 while(element.tagName != "LI")
483 element = element.parentNode;
490 $.ajatus.security_pass = function() {
492 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead UniversalBrowserWrite UniversalFileRead");
494 alert("Permission UniversalBrowserRead denied. with error "+e);
498 $.ajatus.init = function(element, options) {
499 //$.ajatus.security_pass();
501 var application_element = $(element);
502 $.ajatus.application_element = application_element;
503 $.ajatus.application_content_area = $('#middle #content', $.ajatus.application_element);
504 $.ajatus.application_dynamic_elements = $('#dynamic-elements', $.ajatus.application_element);
506 $.ajatus.preferences.client.server_url = window.location.protocol + '//' + document.hostname + (window.location.port != '' ? ':'+window.location.port : '') + '/';
508 $.ajatus.preferences.client = $.extend({}, $.ajatus.preferences.client_defaults, options);
509 //Force the system types to load:
510 $.ajatus.preferences.client.types.system = $.ajatus.preferences.client_defaults.types.system;
512 $.jqCouch.set_defaults({
513 server_url: $.ajatus.preferences.client.server_url
516 var a_db_suffix = $.ajatus.preferences.client.application_database_identifier != '' ? '_db' : 'db';
517 $.ajatus.preferences.client.application_database = 'ajatus_' + $.ajatus.preferences.client.application_database_identifier + a_db_suffix;
518 $.ajatus.preferences.client.content_database = $.ajatus.preferences.client.application_database + '_content';
519 $.ajatus.preferences.client.tags_database = $.ajatus.preferences.client.application_database + '_tags';
523 url: $.ajatus.preferences.client.server_url,
529 $('#top #new-item-button', application_element).bind('click', function(e){
530 $.ajatus.views.system.create.render($.ajatus.active_type);
533 $.ajatus.installer.is_installed();
534 if ($.ajatus.installer.installed == false) {
536 if ($.ajatus.preferences.client.language == null) {
538 $.ajatus.preferences.client.language = 'en_GB';
540 $.ajatus.i10n.init($.ajatus.preferences.client.language, function(){
541 var status = $.ajatus.installer.install();
542 $.ajatus.debug("Installer finished with status: "+status);
544 window.location = window.location + "#view.preferences";
552 // $.ajatus.installer.uninstall();
556 $.ajatus.preload = function() {
557 var preference_loader = new $.ajatus.preferences.loader;
558 preference_loader.load();
560 if ($.ajatus.preferences.client.language == null) {
562 if (typeof($.ajatus.preferences.local.localization) != 'undefined') {
563 lang = $.ajatus.preferences.local.localization.language;
565 $.ajatus.preferences.client.language = lang;
567 $.ajatus.i10n.init($.ajatus.preferences.client.language, function(){
568 $.ajatus.types.init(function(){
574 $.ajatus.start = function() {
575 $.ajatus.debug('started', 'Ajatus start');
577 $.ajatus.events.lock_pool.increase();
579 if ($.ajatus.preferences.local.layout.theme_name != 'default') {
580 $.ajatus.preferences.client.theme_url = 'themes/' + $.ajatus.preferences.local.layout.theme_name + '/';
581 $.ajatus.preferences.client.theme_icons_url = 'themes/' + $.ajatus.preferences.local.layout.icon_set + '/images/icons/';
583 $.ajatus.layout.styles.load($.ajatus.preferences.client.theme_url + 'css/structure.css');
584 $.ajatus.layout.styles.load($.ajatus.preferences.client.theme_url + 'css/common.css');
585 $.ajatus.layout.styles.load($.ajatus.preferences.client.theme_url + 'css/elements.css');
588 $.ajatus.locker = new $.ajatus.events.lock({
590 validate: function(){return $.ajatus.events.lock_pool.count == 0;},
594 on_release: function(){
595 $.ajatus.application_element.addClass('ajatus_initialized');
597 var show_frontpage = true;
598 if ( $.ajatus.history
599 && $.ajatus.history.enabled)
601 show_frontpage = !$.ajatus.history.check();
604 if (show_frontpage) {
605 $.ajatus.views.system.frontpage.render();
610 $('#header .app_version', $.ajatus.application_element).html($.ajatus.version.join('.'));
611 $('#header .tagline', $.ajatus.application_element).html($.ajatus.i10n.get('Distributed CRM'));
612 $('#new-item-button').text($.ajatus.i10n.get('new'));
614 $.ajatus.toolbar.init();
615 $.ajatus.history.init();
616 $.ajatus.tags.init();
617 $.ajatus.widgets.init();
618 $.ajatus.views.init();
620 $.ajatus.extensions.init({
621 on_ready: function(){
622 $.ajatus.active_type = $.ajatus.preferences.client.content_types['note'];
624 if ($.ajatus.preferences.modified) {
625 $.ajatus.views.on_change_actions.add('$.ajatus.preferences.view.save($.ajatus.preferences.local)');
628 // Release the first lock
629 $.ajatus.events.lock_pool.decrease();
633 $.ajatus.elements.messages.set_holder();
635 window.onbeforeunload = function() {
636 if ($.ajatus.events.named_lock_pool.count('unsaved') > 0) {
637 return $.ajatus.i10n.get('You have unsaved changes.');
641 $.ajatus.debug('ended', 'Ajatus start');
644 $.ajatus.ajax_error = function(request, caller) {
645 $.ajatus.debug("Ajax error request.status: "+request.status);
647 if (typeof caller != 'undefined') {
648 $.ajatus.debug("Caller method: "+caller.method);
649 $.ajatus.debug("Caller action:");
650 $.ajatus.debug(caller.action);
652 if (caller.args != undefined) {
653 $.ajatus.debug("Caller args:");
654 $.ajatus.debug(caller.args);
658 if (request.responseText != '') {
659 var response = eval("(" + request.responseText + ")");
660 $.ajatus.debug('response.error.reason: '+response.error.reason);
663 $.ajatus.ajax_success = function(data, caller) {
664 $.ajatus.debug("Ajax success");
666 if (typeof caller != 'undefined') {
667 $.ajatus.debug("Caller method: "+caller.method);
668 $.ajatus.debug("Caller action: "+caller.action);
670 if (typeof caller.args != 'undefined') {
671 $.ajatus.debug("Caller args: "+caller.args);
674 $.ajatus.debug("data: "+data);
679 $.ajatus.debug = function(msg, title, type) {
680 if ($.ajatus.preferences.client.debug == true) {
681 if (typeof(console.log) != 'undefined') {
682 debug_console(msg, title, type);
684 debug_static(msg, title, type);
688 function debug_console(msg, title, type) {
689 if (typeof type == 'undefined') {
693 if (typeof(console[type]) != 'undefined') {
694 console.log(format(msg, title));
696 console.log(format(msg, title));
700 function debug_static(msg, title, type) {
701 // TODO: Implement Static debug handler
704 function format(msg, title) {
707 if (typeof title != 'undefined') {
708 string += title += ': ';
711 if (typeof msg != 'string') {
712 string += $.ajatus.utils.pretty_print(msg);
721 $.fn.initialize_ajatus = function(options) {
722 if (! $(this).is('.ajatus_initialized')) {
723 return new $.ajatus.init(this, options);
729 function initialize_ajatus() {
730 if (typeof ajatus_client_config == 'undefined') {
731 var ajatus_client_config = {};
734 jQuery('#application').initialize_ajatus($.extend({
741 // 'note', 'contact', 'event', 'expense', 'hour_report'
744 application_url: '/_utils/ajatus_dev/', // '/_utils/ajatus/'
745 application_database_identifier: 'dev' // 'stable'
746 }, ajatus_client_config));
749 $(document).ready(function() {
753 alert("could not initialize ajatus! Reason: "+e);