diff --git a/apps/contacts/ajax/loadintro.php b/apps/contacts/ajax/loadintro.php new file mode 100644 index 0000000000..8e5673655a --- /dev/null +++ b/apps/contacts/ajax/loadintro.php @@ -0,0 +1,62 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +// Init owncloud +require_once('../../../lib/base.php'); +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/loadintro.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/loadintro.php: '.$msg, OC_Log::DEBUG); +} +// foreach ($_POST as $key=>$element) { +// debug('_POST: '.$key.'=>'.$element); +// } + +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +// $addressbooks = OC_Contacts_Addressbook::all(OC_USER::getUser()); +// +// $upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); +// $post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); +// $maxUploadFilesize = min($upload_max_filesize, $post_max_size); +// +// $freeSpace=OC_Filesystem::free_space('/'); +// $freeSpace=max($freeSpace,0); +// $maxUploadFilesize = min($maxUploadFilesize ,$freeSpace); +// $adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); +// $phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); + +$tmpl = new OC_Template('contacts','part.no_contacts'); +// $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); +// $tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); +// $tmpl->assign('adr_types',$adr_types); +// $tmpl->assign('phone_types',$phone_types); +// $tmpl->assign('addressbooks',$addressbooks); +// $tmpl->assign('id',''); +$page = $tmpl->fetchPage(); + +OC_JSON::success(array('data' => array( 'page' => $page ))); diff --git a/apps/contacts/contacts.php b/apps/contacts/contacts.php deleted file mode 100644 index 938a6b13a0..0000000000 --- a/apps/contacts/contacts.php +++ /dev/null @@ -1,62 +0,0 @@ - 0) { - $id = $contacts[0]['id']; -} -if(!is_null($id)) { - $vcard = OC_Contacts_App::getContactVCard($id); - $details = OC_Contacts_VCard::structureContact($vcard); -} -$property_types = OC_Contacts_App::getAddPropertyOptions(); -$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); - -$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); -$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); -$maxUploadFilesize = min($upload_max_filesize, $post_max_size); - -$freeSpace=OC_Filesystem::free_space('/'); -$freeSpace=max($freeSpace,0); -$maxUploadFilesize = min($maxUploadFilesize ,$freeSpace); - -OC_Util::addScript('','jquery.multiselect'); -//OC_Util::addScript('contacts','interface'); -OC_Util::addScript('contacts','contacts'); -OC_Util::addScript('contacts','jquery.combobox'); -OC_Util::addScript('contacts','jquery.inview'); -OC_Util::addScript('contacts','jquery.Jcrop'); -OC_Util::addScript('contacts','jquery.jec-1.3.3'); -OC_Util::addStyle('','jquery.multiselect'); -//OC_Util::addStyle('contacts','styles'); -OC_Util::addStyle('contacts','jquery.combobox'); -OC_Util::addStyle('contacts','jquery.Jcrop'); -OC_Util::addStyle('contacts','contacts'); - -$tmpl = new OC_Template( "contacts", "index2", "user" ); -$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); -$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); -$tmpl->assign('property_types',$property_types); -$tmpl->assign('phone_types',$phone_types); -$tmpl->assign('addressbooks', $addressbooks); -$tmpl->assign('contacts', $contacts); -$tmpl->assign('details', $details ); -$tmpl->assign('id',$id); -$tmpl->printPage(); - -?> diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css index 86322a2cc2..384541f375 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -7,8 +7,8 @@ #chooseaddressbook {margin-right: 170px; float: right;} #contacts_deletecard {position:absolute;top:15px;right:25px;} #contacts_downloadcard {position:absolute;top:15px;right:50px;} -#contacts_propertymenu_button { position:absolute;top:15px;right:150px; height: 20px; width: 150px; background:url('../../../core/img/actions/add.svg') no-repeat center; } -#contacts_propertymenu { position:absolute;top:40px;right:150px; overflow:hidden; text-overflow:ellipsis; /*border: thin solid #1d2d44;*/ -moz-box-shadow:0 0 10px #000; -webkit-box-shadow:0 0 10px #000; box-shadow:0 0 10px #000; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; } +#contacts_propertymenu_button { position:absolute;top:15px;right:150px; background:url('../../../core/img/actions/add.svg') no-repeat center; } +#contacts_propertymenu { background-color: #fff; position:absolute;top:40px;right:150px; overflow:hidden; text-overflow:ellipsis; /*border: thin solid #1d2d44;*/ -moz-box-shadow:0 0 10px #000; -webkit-box-shadow:0 0 10px #000; box-shadow:0 0 10px #000; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; } #contacts_propertymenu li { display: block; font-weight: bold; height: 20px; width: 100px; } /*#contacts_propertymenu li:first-child { border-top: thin solid #1d2d44; -moz-border-radius-topleft:0.5em; -webkit-border-top-left-radius:0.5em; border-top-left-radius:0.5em; -moz-border-radius-topright:0.5em; -webkit-border-top-right-radius:0.5em; border-top-right-radius:0.5em; } #contacts_propertymenu li:last-child { border-bottom: thin solid #1d2d44; -moz-border-radius-bottomleft:0.5em; -webkit-border-bottom-left-radius:0.5em; border-bottom-left-radius:0.5em; -moz-border-radius-bottomright:0.5em; -webkit-border-bottom-right-radius:0.5em; border-bottom-right-radius:0.5em; }*/ @@ -20,6 +20,7 @@ #firstrun { /*border: thin solid lightgray;*/ width: 80%; margin: 5em auto auto auto; text-align: center; font-weight:bold; font-size:1.5em; color:#777;} #firstrun #selections { /*border: thin solid lightgray;*/ font-size:0.8em; width: 100%; margin: 2em auto auto auto; clear: both; } +#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 16em; } #card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select { background-color: #f8f8f8; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; } #card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="tel"]:active, select:hover, select:focus, select:active { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #fff, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; } input[type="text"]:invalid,input[type="email"]:invalid,input[type="tel"]:invalid,input[type="date"]:invalid { background-color: #ffc0c0 !important; } @@ -77,7 +78,8 @@ dl.form .delete { background:url('../../../core/img/actions/delete.svg') no-repeat center; } .edit { background:url('../../../core/img/actions/rename.svg') no-repeat center; } .mail { background:url('../../../core/img/actions/mail.svg') no-repeat center; } -.globe { background:url('../img/globe.svg') no-repeat center; } +/*.globe { background:url('../img/globe.svg') no-repeat center; }*/ +.globe { background:url('../../../core/img/actions/public.svg') no-repeat center; } #messagebox_msg { font-weight: bold; font-size: 1.2em; } @@ -96,21 +98,8 @@ dl.form #edit_address_dialog > input { width: 15em; } -#edit_photo_dialog_img { - display: block; - width: 150; - height: 200; - border: thin solid black; -} -#fn { - float: left; -} -.jecEditableOption { - margin: 2px; - border-radius: 0.5em; - border: thin solid #bbb; - content: 'Custom'; -} +#edit_photo_dialog_img { display: block; width: 150; height: 200; border: thin solid black; } +#fn { float: left; } /** * Create classes form, floateven and floatodd which flows left and right respectively. */ @@ -161,13 +150,8 @@ width:auto; padding:.3em; border:1px solid #ddd; font-weight:bold; cursor:pointe background: url(../../../core/img/loading.gif) no-repeat center center; clear: right; } -#contacts_details_photo:hover { - background: #fff; -} -#contacts_details_photo_progress { - margin: 0.3em 0.3em 0.3em 7em; - clear: left; -} +#contacts_details_photo:hover { background: #fff; } +#contacts_details_photo_progress { margin: 0.3em 0.3em 0.3em 7em; clear: left; } /* Address editor */ #addressdisplay { padding: 0.5em; } dl.addresscard { background-color: #fff; float: left; width: 45%; margin: 0 0.3em 0.3em 0.3em; padding: 0; border: thin solid lightgray; } @@ -187,15 +171,6 @@ dl.addresscard dd > ul { margin: 0.3em; padding: 0.3em; } height: 10px; clear: both; } -.updatebar { - height: 30px; - clear: both; - padding-right: 170px; - border: thin solid lightgray; -} -.updatebar button { - float: left; margin: 1em; -} /*input[type="text"] { float: left; max-width: 15em; } input[type="radio"] { float: left; -khtml-appearance: none; width: 20px; height: 20px; vertical-align: middle; }*/ diff --git a/apps/contacts/index.php b/apps/contacts/index.php index 9012e5d8af..c5115d1607 100644 --- a/apps/contacts/index.php +++ b/apps/contacts/index.php @@ -1,36 +1,15 @@ . - * + * Copyright (c) 2012 Thomas Tanghus + * Copyright (c) 2011 Jakob Sack mail@jakobsack.de + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ - -function contacts_namesort($a,$b){ - return strcmp($a['fullname'],$b['fullname']); -} - -// Init owncloud require_once('../../lib/base.php'); // Check if we are a user OC_Util::checkLoggedIn(); -OC_Util::checkAppEnabled('contacts'); - // Get active address books. This creates a default one if none exists. $ids = OC_Contacts_Addressbook::activeIds(OC_User::getUser()); $contacts = OC_Contacts_VCard::all($ids); @@ -47,33 +26,41 @@ $details = array(); if(is_null($id) && count($contacts) > 0) { $id = $contacts[0]['id']; } -$vcard = null; -$details = null; if(!is_null($id)) { $vcard = OC_Contacts_App::getContactVCard($id); - if(!is_null($vcard)) { - $details = OC_Contacts_VCard::structureContact($vcard); - } + $details = OC_Contacts_VCard::structureContact($vcard); } - -// Include Style and Script -OC_Util::addScript('contacts','interface'); -OC_Util::addScript('contacts','jquery.inview'); -OC_Util::addScript('', 'jquery.multiselect'); -OC_Util::addStyle('contacts','styles'); -//OC_Util::addStyle('contacts','formtastic'); - $property_types = OC_Contacts_App::getAddPropertyOptions(); -$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); $phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); -// Process the template -$tmpl = new OC_Template( 'contacts', 'index', 'user' ); +$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); +$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); +$maxUploadFilesize = min($upload_max_filesize, $post_max_size); + +$freeSpace=OC_Filesystem::free_space('/'); +$freeSpace=max($freeSpace,0); +$maxUploadFilesize = min($maxUploadFilesize ,$freeSpace); + +OC_Util::addScript('','jquery.multiselect'); +OC_Util::addScript('contacts','contacts'); +OC_Util::addScript('contacts','jquery.combobox'); +OC_Util::addScript('contacts','jquery.inview'); +OC_Util::addScript('contacts','jquery.Jcrop'); +OC_Util::addStyle('','jquery.multiselect'); +//OC_Util::addStyle('contacts','styles'); +OC_Util::addStyle('contacts','jquery.combobox'); +OC_Util::addStyle('contacts','jquery.Jcrop'); +OC_Util::addStyle('contacts','contacts'); + +$tmpl = new OC_Template( "contacts", "index", "user" ); +$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); +$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); $tmpl->assign('property_types',$property_types); -$tmpl->assign('adr_types',$adr_types); $tmpl->assign('phone_types',$phone_types); $tmpl->assign('addressbooks', $addressbooks); $tmpl->assign('contacts', $contacts); $tmpl->assign('details', $details ); $tmpl->assign('id',$id); $tmpl->printPage(); + +?> diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 9071038b50..3079362574 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -117,7 +117,10 @@ Contacts={ $('#carddav_url_close').show(); }, messageBox:function(title, msg) { - //alert(msg); + if(msg.toLowerCase().indexOf('auth') > 0) { + // fugly hack, I know + alert(msg); + } if($('#messagebox').dialog('isOpen') == true){ // NOTE: Do we ever get here? $('#messagebox').dialog('moveToTop'); @@ -233,11 +236,93 @@ Contacts={ honpre:'', honsuf:'', data:undefined, + update:function() { + // Make sure proper DOM is loaded. + console.log('Card.update(), #n: ' + $('#n').length); + console.log('Card.update(), #contacts: ' + $('#contacts li').length); + if($('#n').length == 0 && $('#contacts li').length > 0) { + $.getJSON(OC.filePath('contacts', 'ajax', 'loadcard.php'),{},function(jsondata){ + if(jsondata.status == 'success'){ + $('#rightcontent').html(jsondata.data.page); + Contacts.UI.loadHandlers(); + if($('#contacts li').length > 0) { + var firstid = $('#contacts li:first-child').data('id'); + console.log('trying to load: ' + firstid); + $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':firstid},function(jsondata){ + if(jsondata.status == 'success'){ + Contacts.UI.Card.loadContact(jsondata.data); + } else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + }); + } + } else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + }); + } + if($('#contacts li').length == 0) { + // load intro page + $.getJSON(OC.filePath('contacts', 'ajax', 'loadintro.php'),{},function(jsondata){ + if(jsondata.status == 'success'){ + id = ''; + $('#rightcontent').data('id',''); + $('#rightcontent').html(jsondata.data.page); + } else { + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + }); + } + }, export:function() { document.location.href = OC.linkTo('contacts', 'export.php') + '?contactid=' + this.id; //$.get(OC.linkTo('contacts', 'export.php'),{'contactid':this.id},function(jsondata){ //}); }, + import:function(){ + Contacts.UI.notImplemented(); + }, + add:function(n, fn, aid){ // add a new contact + console.log('Add contact: ' + n + ', ' + fn + ' ' + aid); + $.post(OC.filePath('contacts', 'ajax', 'addcontact.php'), { n: n, fn: fn, aid: aid }, + function(jsondata) { + if (jsondata.status == 'success'){ + $('#rightcontent').data('id',jsondata.data.id); + var id = jsondata.data.id; + $.getJSON('ajax/contactdetails.php',{'id':id},function(jsondata){ + if(jsondata.status == 'success'){ + Contacts.UI.loadHandlers(); + Contacts.UI.Card.loadContact(jsondata.data); + $('#leftcontent .active').removeClass('active'); + var item = '
  • '+Contacts.UI.Card.fn+'
  • '; + var added = false; + $('#leftcontent ul li').each(function(){ + if ($(this).text().toLowerCase() > Contacts.UI.Card.fn.toLowerCase()) { + $(this).before(item).fadeIn('fast'); + added = true; + return false; + } + }); + if(!added) { + $('#leftcontent ul').append(item); + } + + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + //alert(jsondata.data.message); + } + }); + $('#contact_identity').show(); + $('#actionbar').show(); + // TODO: Add to contacts list. + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + //alert(jsondata.data.message); + } + }); + }, delete:function() { $('#contacts_deletecard').tipsy('hide'); $.getJSON('ajax/deletecard.php',{'id':this.id},function(jsondata){ @@ -247,17 +332,33 @@ Contacts={ //$('#rightcontent').empty(); this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = ''; this.data = undefined; - // Load empty page. - var firstid = $('#contacts li:first-child').data('id'); - console.log('trying to load: ' + firstid); - $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':firstid},function(jsondata){ - if(jsondata.status == 'success'){ - Contacts.UI.Card.loadContact(jsondata.data); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - } - }); + // Load first in list. + if($('#contacts li').length > 0) { + Contacts.UI.Card.update(); + /* + var firstid = $('#contacts li:first-child').data('id'); + console.log('trying to load: ' + firstid); + $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':firstid},function(jsondata){ + if(jsondata.status == 'success'){ + Contacts.UI.Card.loadContact(jsondata.data); + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + });*/ + } else { + // load intro page + $.getJSON('ajax/loadintro.php',{},function(jsondata){ + if(jsondata.status == 'success'){ + id = ''; + $('#rightcontent').data('id',''); + $('#rightcontent').html(jsondata.data.page); + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + }); + } } else{ Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); @@ -270,6 +371,7 @@ Contacts={ $('#contact_communication').hide(); this.data = jsondata; this.id = this.data.id; + $('#rightcontent').data('id',this.id); //console.log('loaded: ' + this.data.FN[0]['value']); this.populateNameFields(); this.loadPhoto(); @@ -370,6 +472,7 @@ Contacts={ $('#reverse_comma').text(this.famname + ', ' + this.givname);*/ $('#contact_identity').find('*[data-element="N"]').data('checksum', this.data.N[0]['checksum']); $('#contact_identity').find('*[data-element="FN"]').data('checksum', this.data.FN[0]['checksum']); + $('#contact_identity').show(); }, editNew:function(){ // add a new contact //Contacts.UI.notImplemented(); @@ -382,47 +485,6 @@ Contacts={ $('#rightcontent').html(jsondata.data.page); Contacts.UI.Card.editName(); } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - alert(jsondata.data.message); - } - }); - }, - add:function(n, fn, aid){ // add a new contact - console.log('Add contact: ' + n + ', ' + fn + ' ' + aid); - $.post(OC.filePath('contacts', 'ajax', 'addcontact.php'), { n: n, fn: fn, aid: aid }, - function(jsondata) { - if (jsondata.status == 'success'){ - $('#rightcontent').data('id',jsondata.data.id); - var id = jsondata.data.id; - $.getJSON('ajax/contactdetails.php',{'id':id},function(jsondata){ - if(jsondata.status == 'success'){ - Contacts.UI.loadHandlers(); - Contacts.UI.Card.loadContact(jsondata.data); - $('#leftcontent .active').removeClass('active'); - var item = '
  • '+Contacts.UI.Card.fn+'
  • '; - var added = false; - $('#leftcontent ul li').each(function(){ - if ($(this).text().toLowerCase() > Contacts.UI.Card.fn.toLowerCase()) { - $(this).before(item).fadeIn('fast'); - added = true; - return false; - } - }); - if(!added) { - $('#leftcontent ul').append(item); - } - - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - //alert(jsondata.data.message); - } - }); - $('#contact_identity').show(); - $('#actionbar').show(); - // TODO: Add to contacts list. - } else{ Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); //alert(jsondata.data.message); @@ -1043,9 +1105,11 @@ Contacts={ * Reload the contacts list. */ update:function(){ + console.log('Contacts.update, start'); $.getJSON('ajax/contacts.php',{},function(jsondata){ if(jsondata.status == 'success'){ $('#contacts').html(jsondata.data.page); + Contacts.UI.Card.update(); } else{ Contacts.UI.messageBox(t('contacts', 'Error'),jsondata.data.message); @@ -1258,7 +1322,7 @@ $(document).ready(function(){ } $('#contacts_propertymenu_button').live('click',function(){ - $('#contacts_propertymenu').is(':hidden') && $('#contacts_propertymenu').show() || $('#contacts_propertymenu').hide(); + $('#contacts_propertymenu').is(':hidden') && $('#contacts_propertymenu').slideDown() || $('#contacts_propertymenu').slideUp(); }); $('#contacts_propertymenu a').live('click',function(){ Contacts.UI.Card.addProperty(this); diff --git a/apps/contacts/js/jquery.jec-1.3.3.js b/apps/contacts/js/jquery.jec-1.3.3.js deleted file mode 100644 index a0367dac2a..0000000000 --- a/apps/contacts/js/jquery.jec-1.3.3.js +++ /dev/null @@ -1,863 +0,0 @@ -/** - * jQuery jEC (jQuery Editable Combobox) 1.3.3 - * http://code.google.com/p/jquery-jec - * - * Copyright (c) 2008-2009 Lukasz Rajchel (lukasz@rajchel.pl | http://rajchel.pl) - * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) - * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. - * - * Documentation : http://code.google.com/p/jquery-jec/wiki/Documentation - * Changelog : http://code.google.com/p/jquery-jec/wiki/Changelog - * - * Contributors : Lukasz Rajchel, Artem Orlov - */ - -/*jslint maxerr: 50, indent: 4, maxlen: 120*/ -/*global Array, Math, String, clearInterval, document, jQuery, setInterval*/ -/*members ':', Handle, Remove, Set, acceptedKeys, addClass, all, append, appendTo, array, attr, before, bind, -blinkingCursor, blinkingCursorInterval, blur, bool, browser, ceil, change, charCode, classes, clearCursor, click, css, -cursorState, data, destroy, disable, each, editable, enable, eq, expr, extend, filter, find, floor, fn, focus, -focusOnNewOption, fromCharCode, get, getId, handleCursor, ignoredKeys, ignoreOptGroups, inArray, init, initJS, integer, -isArray, isPlainObject, jEC, jECTimer, jec, jecKill, jecOff, jecOn, jecPref, jecValue, keyCode, keyDown, keyPress, -keyRange, keyUp, keys, length, max, maxLength, min, msie, object, openedState, optionClasses, optionStyles, parent, -position, pref, prop, push, random, remove, removeAttr, removeClass, removeData, removeProp, safari, setEditableOption, -styles, substring, text, trigger, triggerChangeEvent, unbind, uneditable, useExistingOptions, val, value, -valueIsEditable, which*/ -(function ($) { - 'use strict'; - - $.jEC = (function () { - var pluginClass = 'jecEditableOption', cursorClass = 'hasCursor', options = {}, values = {}, lastKeyCode, - defaults, Validators, EventHandlers, Combobox, activeCombobox; - - if ($.fn.prop === undefined) { - $.fn.extend({ - 'prop': function (key, valueSet) { - if (valueSet) { - $(this).attr(key, key); - } else { - $(this).removeAttr(key); - } - }, - 'removeProp': function (key) { - $(this).removeAttr(key); - } - }); - } - - defaults = { - position: 0, - ignoreOptGroups: false, - maxLength: 255, - classes: [], - styles: {}, - optionClasses: [], - optionStyles: {}, - triggerChangeEvent: false, - focusOnNewOption: false, - useExistingOptions: false, - blinkingCursor: false, - blinkingCursorInterval: 1000, - ignoredKeys: [], - acceptedKeys: [[32, 126], [191, 382]] - }; - - Validators = (function () { - return { - integer: function (value) { - return typeof value === 'number' && Math.ceil(value) === Math.floor(value); - }, - - keyRange: function (value) { - var min, max; - if ($.isPlainObject(value)) { - min = value.min; - max = value.max; - } else if ($.isArray(value) && value.length === 2) { - min = value[0]; - max = value[1]; - } - return Validators.integer(min) && Validators.integer(max) && min <= max; - } - }; - }()); - - EventHandlers = (function () { - var getKeyCode; - - getKeyCode = function (event) { - var charCode = event.charCode; - if (charCode !== undefined && charCode !== 0) { - return charCode; - } else { - return event.keyCode; - } - }; - - return { - // focus event handler - // enables blinking cursor - focus: function () { - var opt = options[Combobox.getId($(this))]; - if (opt.blinkingCursor && $.jECTimer === undefined) { - activeCombobox = $(this); - $.jECTimer = setInterval($.jEC.handleCursor, opt.blinkingCursorInterval); - } - }, - - // blur event handler - // disables blinking cursor - blur: function () { - if ($.jECTimer !== undefined) { - clearInterval($.jECTimer); - $.jECTimer = undefined; - activeCombobox = undefined; - Combobox.clearCursor($(this)); - } - Combobox.openedState($(this), false); - }, - - // keydown event handler - // handles keys pressed on select (backspace and delete must be handled - // in keydown event in order to work in IE) - keyDown: function (event) { - var keyCode = getKeyCode(event), option, value; - - lastKeyCode = keyCode; - - switch (keyCode) { - case 8: // backspace - case 46: // delete - option = $(this).find('option.' + pluginClass); - if (option.val().length >= 1) { - value = option.text().substring(0, option.text().length - 1); - option.val(value).text(value).prop('selected', true); - } - return (keyCode !== 8); - default: - break; - } - }, - - // keypress event handler - // handles the rest of the keys (keypress event gives more informations - // about pressed keys) - keyPress: function (event) { - var keyCode = getKeyCode(event), opt = options[Combobox.getId($(this))], - option, value, specialKeys, exit = false, text; - - Combobox.clearCursor($(this)); - if (keyCode !== 9 && keyCode !== 13 && keyCode !== 27) { - // special keys codes - specialKeys = [37, 38, 39, 40, 46]; - // handle special keys - $.each(specialKeys, function (i, val) { - if (keyCode === val && keyCode === lastKeyCode) { - exit = true; - } - }); - - // don't handle ignored keys - if (!exit && $.inArray(keyCode, opt.ignoredKeys) === -1) { - // remove selection from all options - $(this).find('option:selected').removeProp('selected'); - - if ($.inArray(keyCode, opt.acceptedKeys) !== -1) { - option = $(this).find('option.' + pluginClass); - text = option.text(); - - if (text.length < opt.maxLength) { - value = text + String.fromCharCode(getKeyCode(event)); - option.val(value).text(value); - } - - option.prop('selected', true); - } - } - - return false; - } - }, - - keyUp: function () { - var opt = options[Combobox.getId($(this))]; - if (opt.triggerChangeEvent) { - $(this).trigger('change'); - } - }, - - // change event handler - // handles editable option changing based on a pre-existing values - change: function () { - var opt = options[Combobox.getId($(this))]; - if (opt.useExistingOptions) { - Combobox.setEditableOption($(this)); - } - }, - - click: function () { - if (!$.browser.safari) { - Combobox.openedState($(this), !Combobox.openedState($(this))); - } - } - }; - }()); - - // Combobox - Combobox = (function () { - var Parameters, EditableOption, generateId, setup; - - // validates and set combobox parameters - Parameters = (function () { - var Set, Remove, Handle; - - Set = (function () { - var parseKeys, Handles; - - parseKeys = function (value) { - var keys = []; - if ($.isArray(value)) { - $.each(value, function (i, val) { - var j, min, max; - if (Validators.keyRange(val)) { - if ($.isArray(val)) { - min = val[0]; - max = val[1]; - } else { - min = val.min; - max = val.max; - } - for (j = min; j <= max; j += 1) { - keys.push(j); - } - } else if (typeof val === 'number' && Validators.integer(val)) { - keys.push(val); - } - }); - } - return keys; - }; - - Handles = (function () { - return { - integer: function (elem, name, value) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined && Validators.integer(value)) { - opt[name] = value; - return true; - } - return false; - }, - bool: function (elem, name, value) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined && typeof value === 'boolean') { - opt[name] = value; - return true; - } - return false; - }, - array: function (elem, name, value) { - if (typeof value === 'string') { - value = [value]; - } - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined && $.isArray(value)) { - opt[name] = value; - return true; - } - return false; - }, - object: function (elem, name, value) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined && value !== null && $.isPlainObject(value)) { - opt[name] = value; - } - }, - keys: function (elem, name, value) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined && $.isArray(value)) { - opt[name] = parseKeys(value); - } - } - }; - }()); - - return { - position: function (elem, value) { - if (Handles.integer(elem, 'position', value)) { - var id = Combobox.getId(elem), opt = options[id], optionsCount; - optionsCount = - elem.find('option:not(.' + pluginClass + ')').length; - if (value > optionsCount) { - opt.position = optionsCount; - } - } - }, - - ignoreOptGroups: function (elem, value) { - Handles.bool(elem, 'ignoreOptGroups', value); - }, - - maxLength: function (elem, value) { - if (Handles.integer(elem, 'maxLength', value)) { - var id = Combobox.getId(elem), opt = options[id]; - if (value < 0 || value > 255) { - opt.maxLength = 255; - } - } - }, - - classes: function (elem, value) { - Handles.array(elem, 'classes', value); - }, - - optionClasses: function (elem, value) { - Handles.array(elem, 'optionClasses', value); - }, - - styles: function (elem, value) { - Handles.object(elem, 'styles', value); - }, - - optionStyles: function (elem, value) { - Handles.object(elem, 'optionStyles', value); - }, - - triggerChangeEvent: function (elem, value) { - Handles.bool(elem, 'triggerChangeEvent', value); - }, - - focusOnNewOption: function (elem, value) { - Handles.bool(elem, 'focusOnNewOption', value); - }, - - useExistingOptions: function (elem, value) { - Handles.bool(elem, 'useExistingOptions', value); - }, - - blinkingCursor: function (elem, value) { - Handles.bool(elem, 'blinkingCursor', value); - }, - - blinkingCursorInterval: function (elem, value) { - Handles.integer(elem, 'blinkingCursorInterval', value); - }, - - ignoredKeys: function (elem, value) { - Handles.keys(elem, 'ignoredKeys', value); - }, - - acceptedKeys: function (elem, value) { - Handles.keys(elem, 'acceptedKeys', value); - } - }; - }()); - - Remove = (function () { - var removeClasses, removeStyles; - - removeClasses = function (elem, classes) { - $.each(classes, function (i, val) { - elem.removeClass(val); - }); - }; - - removeStyles = function (elem, styles) { - $.each(styles, function (key) { - elem.css(key, ''); - }); - }; - - return { - classes: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined) { - removeClasses(elem, opt.classes); - } - }, - - optionClasses: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined) { - removeClasses(elem.find('option.' + pluginClass), - opt.optionClasses); - } - }, - - styles: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined) { - removeStyles(elem, opt.styles); - } - }, - - optionStyles: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined) { - removeStyles(elem.find('option.' + pluginClass), - opt.optionStyles); - } - }, - - all: function (elem) { - Remove.classes(elem); - Remove.optionClasses(elem); - Remove.styles(elem); - Remove.optionStyles(elem); - } - }; - }()); - - Handle = (function () { - var setClasses, setStyles; - - setClasses = function (elem, classes) { - $.each(classes, function (i, val) { - elem.addClass(String(val)); - }); - }; - - setStyles = function (elem, styles) { - $.each(styles, function (key, val) { - elem.css(key, val); - }); - }; - - return { - position: function (elem) { - var opt = options[Combobox.getId(elem)], option, uneditableOptions, container; - option = elem.find('option.' + pluginClass); - - uneditableOptions = elem.find('option:not(.' + pluginClass + ')'); - if (opt.position < uneditableOptions.length) { - container = uneditableOptions.eq(opt.position); - - if (!opt.ignoreOptGroups && container.parent('optgroup').length > 0) { - uneditableOptions.eq(opt.position).parent().before(option); - } else { - uneditableOptions.eq(opt.position).before(option); - } - } else { - elem.append(option); - } - }, - - classes: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined) { - setClasses(elem, opt.classes); - } - }, - - optionClasses: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined) { - setClasses(elem.find('option.' + pluginClass), opt.optionClasses); - } - }, - - styles: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined) { - setStyles(elem, opt.styles); - } - }, - - optionStyles: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined) { - setStyles(elem.find('option.' + pluginClass), opt.optionStyles); - } - }, - - focusOnNewOption: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined && opt.focusOnNewOption) { - elem.find(':not(option.' + pluginClass + ')').removeProp('selected'); - elem.find('option.' + pluginClass).prop('selected', true); - } - }, - - useExistingOptions: function (elem) { - var id = Combobox.getId(elem), opt = options[id]; - if (opt !== undefined && opt.useExistingOptions) { - Combobox.setEditableOption(elem); - } - }, - - all: function (elem) { - Handle.position(elem); - Handle.classes(elem); - Handle.optionClasses(elem); - Handle.styles(elem); - Handle.optionStyles(elem); - Handle.focusOnNewOption(elem); - Handle.useExistingOptions(elem); - } - }; - }()); - - return { - Set: Set, - Remove: Remove, - Handle: Handle - }; - }()); - - EditableOption = (function () { - return { - init: function (elem) { - if (!elem.find('option.' + pluginClass).length) { - var editableOption = $('