4 * 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
16 TODO Tag support [Views, service] (Tags are links)
17 TODO Additional fields [widget, support]
18 TODO Skype widget -bergie
19 TODO Formatter service
20 TODO XMMP & Email formatter
21 TODO Hour reporting [Views, widget]
23 TODO Implement arhive view and action
24 TODO Implement delete action
25 TODO Add undelete support
26 TODO Implement file attachments?
27 TODO Documentation (API, Manifesto)
28 TODO GPL Headers (2 copyrights: Nemein & MySelf)
29 TODO Auto-saving to forms (after 5 mins)
30 TODO Context syntax tags (me:, attn:, by:, for:)
33 if (console == undefined) {
35 console.log = function(str){return;};
40 $.ajatus.application_content_area = null;
42 $.ajatus.version = [0, 0, 6];
44 $.ajatus.active_type = null;
46 $.ajatus.converter = {};
47 $.ajatus.converter.parseJSON = function (json_str) {
50 return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
51 json_str.replace(/"(\\.|[^"\\])*"/g, ''))) &&
52 eval('(' + json_str + ')');
59 $.ajatus.converter.toJSON = function (item,item_type) {
71 var a = ['['], b, f, i, l = x.length, v;
72 for (i = 0; i < l; i += 1) {
75 if (typeof v == 'string') {
93 return isFinite(x) ? String(x) : 'null';
97 if (x instanceof Array) {
100 var a = ['{'], b, f, i, v;
104 if (typeof v == 'string') {
108 a.push(s.str(i), ':', v);
118 if (/["\\\x00-\x1f]/.test(x)) {
119 x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
126 Math.floor(c / 16).toString(16) +
127 (c % 16).toString(16);
130 return '"' + x + '"';
133 conv = function (x) {
134 var itemtype = typeof x;
157 var itemtype = item_type || typeof item;
178 throw("Unknown type for $.ajatus.converter.toJSON");
182 $.ajatus.formatter = {};
183 $.ajatus.formatter.date = {};
184 $.ajatus.formatter.date.fix_length = function(number){
185 return ((number < 10) ? '0' : '') + number;
187 $.ajatus.formatter.date.is_iso8601 = function(value) {
188 if (typeof(value) != 'string')
192 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})))?)?)?)?";
193 var isod = value.match(new RegExp(regexp));
200 $.ajatus.formatter.date.js_to_iso8601 = function(date) {
202 str += date.getFullYear();
203 str += "-" + $.ajatus.formatter.date.fix_length(date.getMonth() + 1);
204 str += "-" + $.ajatus.formatter.date.fix_length(date.getDate());
205 str += "T" + $.ajatus.formatter.date.fix_length(date.getHours());
206 str += ":" + $.ajatus.formatter.date.fix_length(date.getMinutes());
207 str += ":" + $.ajatus.formatter.date.fix_length(date.getSeconds());
212 $.ajatus.formatter.date.iso8601_to_js = function(iso_date) {
213 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})))?)?)?)?";
214 var isod = iso_date.match(new RegExp(regexp));
222 var date = new Date(isod[1], 0, 1);
223 date.setMonth(isod[3] - 1);
224 date.setDate(isod[5]);
225 date.setHours(isod[7]);
226 date.setMinutes(isod[8]);
227 date.setSeconds(isod[10]);
231 $.ajatus.formatter.date.caldate_to_iso8601 = function(caldate, format, caltime, time_format) {
233 var format = format || "MDY/";
234 var time_format = time_format || "HMS:";
236 var cdparts = caldate.split(format.charAt(3));
237 var fparts = format.split("");
238 var date = new Date();
240 $.each(cdparts, function(i,v){
242 if (fparts[i] == 'M') {
245 if (fparts[i] == 'D') {
248 if (fparts[i] == 'Y') {
255 var time_separator = time_format.charAt(time_format.length - 1);
256 var tfparts = time_format.split("");
257 var ctparts = caltime.split(time_separator);
259 $.each(ctparts, function(i,v){
261 if (tfparts[i] == 'H') {
264 if (tfparts[i] == 'M') {
267 if (tfparts[i] == 'S') {
279 return $.ajatus.formatter.date.js_to_iso8601(date);
281 $.ajatus.formatter.date.iso8601_to_caldate = function(iso_date, format) {
282 var format = format || "MDY/";
284 var date = $.ajatus.formatter.date.iso8601_to_js(iso_date);
287 var day = date.getDate();
288 var month = date.getMonth();
289 var year = date.getFullYear();
292 for (var i = 0; i < 3; i++) {
293 date_str += format.charAt(3) +
294 (format.charAt(i) == 'D' ? $.ajatus.formatter.date.fix_length(day) :
295 (format.charAt(i) == 'M' ? $.ajatus.formatter.date.fix_length(month) :
296 (format.charAt(i) == 'Y' ? year : '?')));
298 date_str = date_str.substring(format.charAt(3) ? 1 : 0);
302 $.ajatus.formatter.date.iso8601_to_caltime = function(iso_date, format) {
303 var format = format || "HMS:";
305 var date = $.ajatus.formatter.date.iso8601_to_js(iso_date);
309 H: $.ajatus.formatter.date.fix_length(date.getHours()),
310 M: $.ajatus.formatter.date.fix_length(date.getMinutes()),
311 S: $.ajatus.formatter.date.fix_length(date.getSeconds())
313 var separator = format.charAt(format.length - 1);
314 var fparts = format.split("");
315 var utt1_parts = user_test_time1.split(utt1_seprt);
317 $.each(utt1_parts, function(i,v){
320 $.each(fparts, function(i,k){
321 time_str += fparts[k] + separator;
323 time_str = time_str.substring(1);
329 * Following functions are taken from the jquery form plugin.
330 * Plugin can be found from http://www.malsup.com/jquery/form/
332 $.fieldValue = function(el, successful) {
333 var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
334 if (typeof successful == 'undefined') successful = true;
336 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
337 (t == 'checkbox' || t == 'radio') && !el.checked ||
338 (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
339 tag == 'select' && el.selectedIndex == -1))
342 if (tag == 'select') {
343 var index = el.selectedIndex;
344 if (index < 0) return null;
345 var a = [], ops = el.options;
346 var one = (t == 'select-one');
347 var max = (one ? index+1 : ops.length);
348 for(var i=(one ? index : 0); i < max; i++) {
351 // extra pain for IE...
352 var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
361 $.fn.formToArray = function(semantic) {
363 if (this.length == 0) return a;
366 var els = semantic ? form.getElementsByTagName('*') : form.elements;
368 for(var i=0, max=els.length; i < max; i++) {
373 if (semantic && form.clk && el.type == "image") {
374 // handle image inputs on the fly when semantic == true
375 if(!el.disabled && form.clk == el)
376 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
380 var v = $.fieldValue(el, true);
381 if (v && v.constructor == Array) {
382 for(var j=0, jmax=v.length; j < jmax; j++)
383 a.push({name: n, value: v[j]});
385 else if (v !== null && typeof v != 'undefined')
386 a.push({name: n, value: v});
389 if (!semantic && form.clk) {
390 // input type=='image' are not found in elements array! handle them here
391 var inputs = form.getElementsByTagName("input");
392 for(var i=0, max=inputs.length; i < max; i++) {
393 var input = inputs[i];
395 if(n && !input.disabled && input.type == "image" && form.clk == input)
396 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
402 * Form plugin functions end
408 $.extend($.ajatus.tags, {
410 $.ajatus.events.lock_pool.increase();
411 $.ajatus.tags.load();
412 $.ajatus.events.lock_pool.decrease();
415 var jqcouch = $.jqcouch.doc;
416 jqcouch.on_success = function(data, caller)
418 if (data.total_rows <= 0) {
422 $.each(data.rows, function(i,n){
423 $.ajatus.tags.cache.push(n._id);
427 jqcouch.get_all($.ajatus.preferences.client.application_database + '/tags');
428 console.log("All tags:");
429 console.log($.ajatus.tags.cache);
434 exists: function(tag) {
435 var found = $.inArray(tag, $.ajatus.tags.cache);
441 create: function(name, jqc) {
443 if ($.ajatus.tags.exists(name)) {
447 if (jqc == undefined) {
448 var jqc = $.jqcouch.doc;
451 var db_path = $.ajatus.preferences.client.application_database + '/tags/';
466 tag = new $.ajatus.document(tag);
468 var now = $.ajatus.formatter.date.js_to_iso8601(new Date());
471 creator: $.ajatus.preferences.local.user,
473 revisor: $.ajatus.preferences.local.user
475 tag = $.ajatus.document.modify_metadata(tag, new_metadata);
477 console.log("saving tag:");
480 jqc.save(db_path, tag);
484 remove: function(tag, jqc) {
490 $.ajatus.tabs.set_active_by_hash = function(hash) {
491 // console.log('set_active_by_hash: '+hash);
493 var views_tab_holder = $('#tabs-views ul');
494 var app_tab_holder = $('#tabs-application ul');
496 var selected_tab = jQuery('li a[@href$="' + hash + '"]', views_tab_holder).parent();
497 if (selected_tab[0] != undefined) {
498 // console.log('views selected_tab:');
499 // console.log(selected_tab);
500 jQuery('li', views_tab_holder).removeClass('tabs-selected').blur();
501 jQuery('li', app_tab_holder).removeClass('tabs-selected').blur();
502 selected_tab.addClass('tabs-selected').focus();
504 selected_tab = jQuery('li a[@href$="' + hash + '"]', app_tab_holder).parent();
505 // console.log('app selected_tab:');
506 // console.log(selected_tab);
507 if (selected_tab[0] != undefined) {
508 jQuery('li', views_tab_holder).removeClass('tabs-selected').blur();
509 jQuery('li', app_tab_holder).removeClass('tabs-selected').blur();
510 selected_tab.addClass('tabs-selected').focus();
512 jQuery('li', views_tab_holder).removeClass('tabs-selected').blur();
513 jQuery('li', app_tab_holder).removeClass('tabs-selected').blur();
517 $.ajatus.tabs.on_click = function(e) {
518 var trgt = target(e);
519 jQuery("li", parent(e)).removeClass("tabs-selected").index(trgt);
520 jQuery(trgt).addClass("tabs-selected");
522 var new_hash = jQuery('a', trgt)[0].hash;
523 location.hash = new_hash;
524 $.ajatus.history.update(new_hash);
526 function parent(event) {
527 var element = event.target;
530 if (element.tagName == "UL")
535 while(element.tagName != "UL")
537 element = element.parentNode;
543 function target(event) {
544 var element = event.target;
547 if (element.tagName == "UL")
549 element = jQuery(element).find('li').eq(0);
553 while(element.tagName != "LI")
555 element = element.parentNode;
562 $.jqcouch.on_error = function(request,caller) {
563 $.ajatus.ajax_error(request, caller);
565 $.jqcouch.on_success = function(data,caller) {
566 $.ajatus.ajax_success(data, caller);
569 $.ajatus.preferences = $.ajatus.preferences || {};
570 $.ajatus.preferences.local = {};
571 $.ajatus.preferences.client = {};
572 $.ajatus.preferences.client_defaults = {
576 application_url: '/_utils/ajatus/',
577 application_database: 'ajatus_db',
581 extensions: ['history']
584 $.ajatus.preferences.loader = function() {
585 this.jqcouch = $.jqcouch.doc;
588 this.jqcouch.on_error = function(request, caller)
591 $.ajatus.events.lock_pool.decrease();
592 $.ajatus.ajax_error(request, caller);
594 this.jqcouch.on_success = function(data, caller)
596 $.ajatus.events.lock_pool.decrease();
597 $.ajatus.preferences.local = data.value;
600 $.extend($.ajatus.preferences.loader.prototype, {
602 $.ajatus.events.lock_pool.increase();
603 this.jqcouch.get($.ajatus.preferences.client.application_database + '/preferences');
607 $.ajatus.security_pass = function() {
609 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead UniversalBrowserWrite UniversalFileRead");
611 alert("Permission UniversalBrowserRead denied. with error "+e);
615 $.ajatus.init = function(element, options) {
616 //$.ajatus.security_pass();
618 var application_element = jQuery(element);
619 $.ajatus.application_element = application_element;
620 $.ajatus.application_content_area = $('#middle #content', application_element);
622 $('#header .app_version', $.ajatus.application_element).html($.ajatus.version.join('.'));
624 $.ajatus.preferences.client = $.extend($.ajatus.preferences.client_defaults, options);
625 $.jqcouch.server_url = $.ajatus.preferences.client.server_url;
629 url: $.ajatus.preferences.client.server_url,
635 $('#top #new-item-button', application_element).bind('click', function(e){
636 $.ajatus.views.system.create.render($.ajatus.active_type);
639 $.ajatus.installer.is_installed();
640 if ($.ajatus.installer.installed == false) {
641 var status = $.ajatus.installer.install();
642 $.ajatus.debug("Installer finished with status: "+status);
648 // $.ajatus.installer.uninstall();
652 $.ajatus.start = function() {
653 $.ajatus.events.lock_pool.increase();
654 $.ajatus.locker = new $.ajatus.events.lock({
656 validate: function(){return $.ajatus.events.lock_pool.count == 0;},
660 on_release: function(){
661 $.ajatus.application_element.addClass('ajatus_initialized');
663 var show_frontpage = true;
664 if ( $.ajatus.history
665 && $.ajatus.history.enabled)
667 show_frontpage = !$.ajatus.history.check();
670 if (show_frontpage) {
671 $.ajatus.views.system.frontpage.render();
676 var preference_loader = new $.ajatus.preferences.loader;
677 preference_loader.load();
679 $.ajatus.extensions.init({
680 on_ready: function(){
681 $.ajatus.tags.init();
682 $.ajatus.widgets.init();
683 $.ajatus.views.init();
685 $.ajatus.active_type = $.ajatus.preferences.client.content_types['note'];
687 // $.each($.ajatus.preferences.client.content_types, function(i,n){
688 // if ($.ajatus.active_type == null) {
689 // $.ajatus.active_type = n;
694 // Release the first lock
695 $.ajatus.events.lock_pool.decrease();
699 window.onbeforeunload = function() {
700 if ($.ajatus.events.named_lock_pool.count('unsaved') > 0) {
701 return "Reason: You have unsaved changes.";
706 $.ajatus.ajax_error = function(request, caller) {
707 $.ajatus.debug("Ajax error request.status: "+request.status);
708 if (caller != undefined) {
709 $.ajatus.debug("Caller method: "+caller.method);
710 $.ajatus.debug("Caller action:");
711 $.ajatus.debug(caller.action);
712 if (caller.args != undefined) {
713 $.ajatus.debug("Caller args:");
714 $.ajatus.debug(caller.args);
718 if (request.responseText != '')
720 var response = eval("(" + request.responseText + ")");
721 $.ajatus.debug('response.error.reason: '+response.error.reason);
724 $.ajatus.ajax_success = function(data, caller) {
725 $.ajatus.debug("Ajax success");
726 if (caller != undefined)
728 $.ajatus.debug("Caller method: "+caller.method);
729 $.ajatus.debug("Caller action: "+caller.action);
730 if (caller.args != undefined)
732 $.ajatus.debug("Caller args: "+caller.args);
735 $.ajatus.debug("data: "+data);
740 $.ajatus.debug = function(msg, title, type) {
741 if ($.ajatus.preferences.client.debug == true)
747 $.ajatus.register_form = function(form) {
748 $.ajatus.forms.register.normal(form);
749 // jqform = jQuery(form);
751 // jqform.bind('submit',function(e){
755 // $('input[@type=submit]', jqform).bind('click', function(){
756 // $.ajatus.process_form(jqform.formToArray(false));
760 $.ajatus.process_form = function(form_data) {
766 var form_values = {};
768 var doc_type = 'note';
770 $.each(form_data, function(i,row){
771 //console.log('i: '+i+' row.name: '+row.name+' row.value: '+row.value);
773 if ( row.name == '_id'
774 && ( row.value != undefined
777 doc['_id'] = String(row.value);
778 form_id = doc['_id'];
780 else if( row.name == '_rev'
781 && ( row.value != undefined
784 doc['_rev'] = Number(row.value);
786 if (row.name != 'submit') {
787 if (row.name == '_type') {
788 doc_type = row.value;
789 form_values[row.name] = row.value;
791 else if ( row.name.substr(0,6) != "widget"
792 && row.name.substr(0,8) != "metadata")
796 var prev_val = false;
797 $.each(form_data, function(x,r){
798 if (r.name == 'widget['+row.name+':name]') {
799 widget['name'] = r.value;
800 } else if (r.name == 'widget['+row.name+':config]') {
801 widget['config'] = $.ajatus.converter.parseJSON(r.value);
802 } else if (r.name == 'widget['+row.name+':prev_val]') {
803 prev_val = $.ajatus.converter.parseJSON(r.value);
807 var wdgt = new $.ajatus.widget(widget['name'], widget['config']);
808 item['val'] = wdgt.value_on_save(row.value, prev_val);
809 item['widget'] = widget;
810 form_values[row.name] = item;
812 else if (row.name.substr(0,8) == "metadata")
814 if (!form_values['metadata'])
816 form_values['metadata'] = {};
819 var re = /\bmetadata\[([a-z]+)\b/;
820 var results = re.exec(row.name);
821 var key = results[1];
823 form_values['metadata'][key] = {
830 doc['value'] = form_values;
832 doc = new $.ajatus.document(doc);
834 var now = $.ajatus.formatter.date.js_to_iso8601(new Date());
838 revisor: $.ajatus.preferences.local.user
840 if ( doc._id == undefined
843 new_metadata['created'] = now;
844 new_metadata['creator'] = $.ajatus.preferences.local.user;
847 doc = $.ajatus.document.modify_metadata(doc, new_metadata);
849 var jqcouch = $.jqcouch.doc;
850 var db_path = $.ajatus.preferences.client.application_database + '/content';
851 jqcouch.on_success = function(data, caller) {
853 doc['_id'] = data._id;
854 doc['_rev'] = data._rev;
855 doc = new $.ajatus.document(doc);
856 $.ajatus.views.system.item.render(doc);
859 jqcouch.save(db_path, doc);
864 $.fn.initialize_ajatus = function(options) {
865 if (!$(this).is(".ajatus_initialized")) {
866 return new $.ajatus.init(this, options);
872 function initialize_ajatus() {
873 jQuery('#application').initialize_ajatus({
878 server_url: 'http://couchdb_server:8888/'
879 //application_database: 'ajatus_stable_db'
883 jQuery(document).ready(function() {