Commit dbce5577cb0dc28eacd0f67382d6bb1940b9d43b

Authored by Jarrett Jordaan
2 parents 12fbdcf4 ef7aa073

Merge branch 'edge' of git@github.com:ktgit/knowledgetree into edge

lib/browse/Criteria.inc
... ... @@ -621,12 +621,69 @@ class GenericMetadataCriterion extends BrowseCriterion {
621 621 }
622 622  
623 623 // If there's no lookup, just use the standard text input
624   - if ($this->oField->getHasLookup() == false) {
  624 + if ($this->oField->getHasLookup() == false && $this->oField->getHasInetLookup() == false) {
625 625 $this->bContains = true; // contains
626 626 return parent::searchWidget($aRequest, $aPreValue);
627 627 }
  628 +
  629 + if($this->oField->getHasInetLookup() == true)
  630 + {
  631 +
  632 + //$this->bContains = true;
  633 + $this->bString = false;
  634 + $sRet = $this->getNotWidget($aPreValue);
  635 +
  636 + $innerJoin = $aPreValue[$this->getWidgetBase()."_join"];
  637 +
  638 + $andSelected = "";
  639 + $orSelected = "";
  640 + if($innerJoin == "AND")
  641 + {
  642 + $andSelected = "selected=\"selected\"";
  643 + }
  644 + elseif($innerJoin == "OR")
  645 + {
  646 + $orSelected = "selected=\"selected\"";
  647 + }
  648 +
  649 + $sRet .= "<select size=\"1\" name=\"".$this->getWidgetBase()."_join\">\n";
  650 + $sRet .= "<option value=\"AND\" ".$andSelected.">all</option>\n";
  651 + $sRet .= "<option value=\"OR\" ".$orSelected.">any</option>\n";
  652 + $sRet .= "</select>\n";
  653 +
  654 + if($this->oField->getInetLookupType() == "multiwithlist")
  655 + {
  656 + $sRet .= "<select size=\"4\" name=\"" . $this->getWidgetBase() . "\" multiple=\"multiple\">\n";
  657 + $aSearch = array('document_field_id = ?', $this->getID());
  658 + $aMetaData = MetaData::getByDocumentField(DocumentField::get($this->getID()));/*ok*/
  659 +
  660 + foreach ($aMetaData as $oMetaData) {
  661 +
  662 + $sSelStr = '';
  663 + if (in_array($oMetaData->getName(), $preval)) { $sSelStr = ' selected="true"'; }
  664 + $sRet .= "<option value=\"" . $oMetaData->getName() . "\" " . $sSelStr . ">" . $oMetaData->getName() . "</option>\n";
  665 + }
  666 + $sRet .= "</select>\n";
  667 + }
  668 + elseif($this->oField->getInetLookupType() == "multiwithcheckboxes")
  669 + {
  670 + $sRet .= "<div style=\"float:right;\">";
  671 + $aSearch = array('document_field_id = ?', $this->getID());
  672 + $aMetaData = MetaData::getByDocumentField(DocumentField::get($this->getID()));/*ok*/
  673 +
  674 + foreach ($aMetaData as $oMetaData) {
  675 + $sSelStr = '';
  676 + if (in_array($oMetaData->getName(), $preval)) { $sSelStr = ' checked="true"'; }
  677 + $sRet .= "<input type=\"checkbox\" name=\"" . $this->getWidgetBase() . "\" class=\"multiple\" value=\"" . $oMetaData->getName() . "\"" . $sSelStr . " /> ". $oMetaData->getName()."<br />";
  678 + }
  679 + $sRet .= "</div>";
  680 + }
  681 + return $sRet;
  682 + }
  683 +
628 684 $this->bContains = false; // is
629 685 $sRet = $this->getNotWidget($aPreValue);
  686 +
630 687 $sRet .= "<select size=\"1\" name=\"" . $this->getWidgetBase() . "\">\n";
631 688 $aSearch = array('document_field_id = ?', $this->getID());
632 689 $aMetaData = MetaData::getByDocumentField(DocumentField::get($this->getID()));/*ok*/
... ...
lib/documentmanagement/DocumentField.inc
... ... @@ -72,11 +72,13 @@ class DocumentField extends KTEntity {
72 72 var $iPosition;
73 73 var $bIsHTML;
74 74 var $iMax;
  75 + var $bHasInetLookup;
  76 + var $sInetLookupType;
75 77  
76 78 var $_aFieldToSelect = array(
77 79 'iId' => 'id',
78 80 'sName' => 'name',
79   - 'sDescription' => 'description',
  81 + 'sDescription' => 'description',
80 82 'sDataType' => 'data_type',
81 83 'bIsGeneric' => 'is_generic',
82 84 'bHasLookup' => 'has_lookup',
... ... @@ -86,53 +88,83 @@ class DocumentField extends KTEntity {
86 88 'iPosition' => 'position',
87 89 'bIsHTML' => 'is_html',
88 90 'iMax' => 'max_length',
  91 + 'bHasInetLookup' => 'has_inetlookup',
  92 + 'sInetLookupType' => 'inetlookup_type',
89 93 );
90 94  
91 95 // FIXME deprecate constructor use. Use DocumentField::createFromArray instead.
92   - function DocumentField($sNewName = null, $sNewDataType = null, $bNewIsGeneric = null, $bNewHasLookup = null, $iParentFieldset = null, $bHasLookupTree = null, $bNewIsHTML = null, $iNewMaxLength = null) {
93   -
94   - $this->iId = -1;
95   - $this->sName = $sNewName;
96   - $this->sDataType = $sNewDataType;
97   - $this->bIsGeneric = $bNewIsGeneric;
98   - $this->bHasLookup = $bNewHasLookup;
99   - $this->iParentFieldset = $iParentFieldset;
100   - $this->bHasLookupTree = $bHasLookupTree;
101   - $this->iPosition = $this->getNextFieldPosition($iParentFieldset);
102   - $this->bIsHTML = $bNewIsHTML;
103   - $this->iMax = $iNewMaxLength;
104   - }
105   -
106   - function getID() { return $this->iId; }
107   - function getName() { return $this->sName; }
108   - function setName($sNewValue) { $this->sName = $sNewValue; }
109   - function setDescription($sNewValue) { $this->sDescription = $sNewValue; }
110   - function getDescription() { return $this->sDescription; }
111   - function getDataType() { return $this->sDataType; }
  96 + function DocumentField($sNewName = null, $sNewDataType = null, $bNewIsGeneric = null, $bNewHasLookup = null, $iParentFieldset = null, $bHasLookupTree = null, $bNewIsHTML = null, $iNewMaxLength = null, $bHasNewInetLookup = null, $sNewInetLookupType = null) {
  97 +
  98 + $this->iId = -1;
  99 + $this->sName = $sNewName;
  100 + $this->sDataType = $sNewDataType;
  101 + $this->bIsGeneric = $bNewIsGeneric;
  102 + $this->bHasLookup = $bNewHasLookup;
  103 + $this->iParentFieldset = $iParentFieldset;
  104 + $this->bHasLookupTree = $bHasLookupTree;
  105 + $this->iPosition = $this->getNextFieldPosition($iParentFieldset);
  106 + $this->bIsHTML = $bNewIsHTML;
  107 + $this->iMax = $iNewMaxLength;
  108 + $this->sInetLookupType = $bHasNewInetLookup;
  109 + $this->sInetLookupType = $sNewInetLookupType;
  110 + }
  111 +
  112 + function getID() { return $this->iId; }
  113 + function getName() { return $this->sName; }
  114 + function setName($sNewValue) { $this->sName = $sNewValue; }
  115 + function setDescription($sNewValue) { $this->sDescription = $sNewValue; }
  116 + function getDescription() { return $this->sDescription; }
  117 + function getDataType() { return $this->sDataType; }
112 118 function setDataType($sNewValue) { $this->sDataType = $sNewValue; }
113   - function getIsGeneric() { return $this->bIsGeneric; }
114   - function setIsGeneric($sNewValue) { $this->bIsGeneric = $sNewValue; }
  119 + function getIsGeneric() { return $this->bIsGeneric; }
  120 + function setIsGeneric($sNewValue) { $this->bIsGeneric = $sNewValue; }
115 121 function getHasLookup() { return $this->bHasLookup; }
116   - function setHasLookup($iNewValue) { $this->bHasLookup = $iNewValue; }
  122 + function setHasLookup($iNewValue) { $this->bHasLookup = $iNewValue; }
117 123 function getParentFieldset() { return $this->iParentFieldset; }
118   - function setParentFieldset($iNewValue) { $this->iParentFieldset = $iNewValue; }
  124 + function setParentFieldset($iNewValue) { $this->iParentFieldset = $iNewValue; }
119 125 function getParentFieldsetId() { return $this->iParentFieldset; }
120   - function setParentFieldsetId($iNewValue) { $this->iParentFieldset = $iNewValue; }
  126 + function setParentFieldsetId($iNewValue) { $this->iParentFieldset = $iNewValue; }
121 127 function getHasLookupTree() { return $this->bHasLookupTree; }
122   - function setHasLookupTree($iNewValue) { $this->bHasLookupTree = KTUtil::anyToBool($iNewValue); }
  128 + function setHasLookupTree($iNewValue) { $this->bHasLookupTree = KTUtil::anyToBool($iNewValue); }
123 129 function getIsMandatory() { return $this->bIsMandatory; }
124   - function setIsMandatory($iNewValue) { $this->bIsMandatory = KTUtil::anyToBool($iNewValue); }
  130 + function setIsMandatory($iNewValue) { $this->bIsMandatory = KTUtil::anyToBool($iNewValue); }
125 131 function getPosition() { return $this->iPosition; }
126   - function setPosition($iNewValue) { $this->iPosition = $iNewValue; }
  132 + function setPosition($iNewValue) { $this->iPosition = $iNewValue; }
127 133 function getIsHTML() { return $this->bIsHTML; }
128   - function setIsHTML($iNewValue) { $this->bIsHTML = $iNewValue; }
129   - function getMaxLength() { return $this->iMax; }
130   - function setMaxLength($iNewValue) { $this->iMax = $iNewValue; }
  134 + function setIsHTML($iNewValue) { $this->bIsHTML = $iNewValue; }
  135 + function getMaxLength() { return $this->iMax; }
  136 + function setMaxLength($iNewValue) { $this->iMax = $iNewValue; }
  137 + function getHasInetLookup() { return $this->bHasInetLookup; }
  138 + function setHasInetLookup($iNewValue) { $this->bHasInetLookup = $iNewValue; }
  139 + function getInetLookupType() { return $this->sInetLookupType; }
  140 + function setInetLookupType($sNewValue) { $this->sInetLookupType = $sNewValue; }
  141 + function getInetLookupTypeFriendlyName()
  142 + {
  143 + $aDescriptors = array();
  144 + if($this->getInetLookupType() == "multiwithlist")
  145 + {
  146 + $aDescriptors[] = _kt("Multiselect with a list");
  147 + }
  148 + elseif($this->getInetLookupType() == "multiwithcheckboxes")
  149 + {
  150 + $aDescriptors[] = _kt("Multiselect with checkboxes");
  151 + }
  152 +
  153 + // required
  154 + if ($this->getIsMandatory()) {
  155 + $aDescriptors[] = _kt("Required");
  156 + } else {
  157 + $aDescriptors[] = _kt("Not Required");
  158 + }
  159 +
  160 + return implode(', ', $aDescriptors);
  161 + }
  162 +
131 163  
132 164 function _fieldValues () {
133 165 return array(
134 166 'name' => $this->sName,
135   - 'description' => $this->sDescription,
  167 + 'description' => $this->sDescription,
136 168 'data_type' => $this->sDataType,
137 169 'is_generic' => KTUtil::anyToBool($this->bIsGeneric),
138 170 'has_lookup' => KTUtil::anyToBool($this->bHasLookup),
... ... @@ -141,7 +173,9 @@ class DocumentField extends KTEntity {
141 173 'is_mandatory' => KTUtil::anyToBool($this->bIsMandatory),
142 174 'position' => $this->iPosition,
143 175 'is_html' => KTUtil::anyToBool($this->bIsHTML),
144   - 'max_length' => $this->iMax,
  176 + 'max_length' => $this->iMax,
  177 + 'has_inetlookup' => $this->bHasInetLookup,
  178 + 'inetlookup_type' => $this->sInetLookupType,
145 179 );
146 180 }
147 181  
... ... @@ -151,7 +185,7 @@ class DocumentField extends KTEntity {
151 185 }
152 186  
153 187 function &getList($sWhereClause = null) {
154   - return KTEntityUtil::getList2('DocumentField', $sWhereClause);
  188 + return KTEntityUtil::getList2('DocumentField', $sWhereClause);
155 189 }
156 190  
157 191 function &createFromArray($aOptions) {
... ... @@ -192,24 +226,27 @@ class DocumentField extends KTEntity {
192 226 return KTEntityUtil::get('DocumentField', $iId);
193 227 }
194 228  
195   - // FIXME: add a data type class!
196   - /* Static function. Given a documenttype...will find all fields belongin to it
197   - *
198   - * @return DocumentFieldLink populated DocumentFieldLink object on success, false otherwise and set $_SESSION["errorMessage"]
199   - */
200   - function getLookupCount($iDocumentFieldID){
201   - $sTable = 'metadata';
202   - $sQuery = "SELECT COUNT(*) AS count FROM " . $sTable . " WHERE document_field_id = ?";
203   - $aParams = array($iDocumentFieldID);
  229 + // FIXME: add a data type class!
  230 + /* Static function. Given a documenttype...will find all fields belongin to it
  231 + *
  232 + * @return DocumentFieldLink populated DocumentFieldLink object on success, false otherwise and set $_SESSION["errorMessage"]
  233 + */
  234 + function getLookupCount($iDocumentFieldID){
  235 + $sTable = 'metadata';
  236 + $sQuery = "SELECT COUNT(*) AS count FROM " . $sTable . " WHERE document_field_id = ?";
  237 + $aParams = array($iDocumentFieldID);
204 238  
205 239 $res = DBUtil::getOneResultKey(array($sQuery, $aParams), 'count');
206 240 if (PEAR::isError($res)) {
207 241 return false; // return $res;
208 242 }
209 243 return $res;
210   - }
  244 + }
211 245  
212 246 function getType() {
  247 + if($this->bHasInetLookup){
  248 + return _kt('Multiselect');
  249 + }
213 250 if (empty($this->bHasLookup)) {
214 251 return _kt("Normal");
215 252 }
... ... @@ -275,148 +312,148 @@ class DocumentField extends KTEntity {
275 312 function reorderFields($iFieldsetId) {
276 313 // Get the fields in the order they'll appear - first by position then by id
277 314 $sql = "SELECT id, position FROM document_fields
278   - WHERE parent_fieldset = ?
279   - ORDER BY position, id ASC";
280   - $aParams = array($iFieldsetId);
  315 + WHERE parent_fieldset = ?
  316 + ORDER BY position, id ASC";
  317 + $aParams = array($iFieldsetId);
  318 +
  319 + $result = DBUtil::getResultArray(array($sql, $aParams));
  320 +
  321 + if(PEAR::isError($result) || empty($result)){
  322 + return false;
  323 + }
  324 +
  325 + // Set all positions to be unique and in order
  326 + foreach($result as $key => $field){
  327 + $position = $field['position'];
  328 +
  329 + // If the fields position is correct in the order, continue
  330 + if($position == $key){
  331 + continue;
  332 + }
  333 +
  334 + // Reset the position
  335 + $aFields = array();
  336 + $aFields['position'] = $key;
  337 +
  338 + $res = DBUtil::autoUpdate('document_fields', $aFields, $field['id']);
  339 + }
  340 + return true;
  341 + }
  342 +
  343 + /**
  344 + * Get the postion of the last field
  345 + */
  346 + function getNextFieldPosition($iFieldsetId){
  347 + $sql = "SELECT position FROM document_fields
  348 + WHERE parent_fieldset = ?
  349 + ORDER BY position DESC LIMIT 1";
  350 + $aParams = array($iFieldsetId);
  351 +
  352 + $result = DBUtil::getResultArray(array($sql, $aParams));
  353 +
  354 + if(PEAR::isError($result) || empty($result)){
  355 + return 0;
  356 + }
  357 + return $result[0]['position'] + 1;
  358 + }
  359 +
  360 + /**
  361 + * Get the next postion up / down
  362 + */
  363 + function getNextPosition($iFieldsetId, $iId, $position, $dir = 'up') {
  364 + switch($dir){
  365 + case 'down':
  366 + $comp = '>';
  367 + $order = 'ASC';
  368 + break;
  369 + default:
  370 + $comp = '<';
  371 + $order = 'DESC';
  372 + }
281 373  
282   - $result = DBUtil::getResultArray(array($sql, $aParams));
  374 + // Get the column above / below to swop position
  375 + $sql = "SELECT id, position FROM document_fields
  376 + WHERE parent_fieldset = ? AND (position {$comp} ? || (position = ? AND id {$comp} ?))
  377 + ORDER BY position {$order} LIMIT 1";
  378 + $aParams = array($iFieldsetId, $position, $position, $iId);
283 379  
284   - if(PEAR::isError($result) || empty($result)){
285   - return false;
286   - }
  380 + $result = DBUtil::getOneResult(array($sql, $aParams));
287 381  
288   - // Set all positions to be unique and in order
289   - foreach($result as $key => $field){
290   - $position = $field['position'];
  382 + if(PEAR::isError($result) || empty($result)){
  383 + return false;
  384 + }
  385 + return $result;
  386 + }
291 387  
292   - // If the fields position is correct in the order, continue
293   - if($position == $key){
294   - continue;
295   - }
  388 + /**
  389 + * Get the updated position of the field
  390 + *
  391 + * @param int $iId
  392 + * @return int
  393 + */
  394 + function getNewPosition($iId){
  395 + // Get the new position
  396 + $sql = "SELECT id, position FROM document_fields
  397 + WHERE id = ?";
  398 + $aParams = array($iId);
  399 + $result = DBUtil::getOneResult(array($sql, $aParams));
296 400  
297   - // Reset the position
298   - $aFields = array();
299   - $aFields['position'] = $key;
  401 + if(PEAR::isError($result) || empty($result)){
  402 + return false;
  403 + }
  404 + return $result['position'];
  405 + }
300 406  
301   - $res = DBUtil::autoUpdate('document_fields', $aFields, $field['id']);
302   - }
303   - return true;
  407 + /**
  408 + * Update the position of a field
  409 + */
  410 + function updatePosition($iId, $position) {
  411 + $aFields = array('position' => $position);
  412 + DBUtil::autoUpdate('document_fields', $aFields, $iId);
304 413 }
305 414  
306   - /**
307   - * Get the postion of the last field
308   - */
309   - function getNextFieldPosition($iFieldsetId){
310   - $sql = "SELECT position FROM document_fields
311   - WHERE parent_fieldset = ?
312   - ORDER BY position DESC LIMIT 1";
313   - $aParams = array($iFieldsetId);
314   -
315   - $result = DBUtil::getResultArray(array($sql, $aParams));
316   -
317   - if(PEAR::isError($result) || empty($result)){
318   - return 0;
319   - }
320   - return $result[0]['position'] + 1;
321   - }
322   -
323   - /**
324   - * Get the next postion up / down
325   - */
326   - function getNextPosition($iFieldsetId, $iId, $position, $dir = 'up') {
327   - switch($dir){
328   - case 'down':
329   - $comp = '>';
330   - $order = 'ASC';
331   - break;
332   - default:
333   - $comp = '<';
334   - $order = 'DESC';
335   - }
336   -
337   - // Get the column above / below to swop position
338   - $sql = "SELECT id, position FROM document_fields
339   - WHERE parent_fieldset = ? AND (position {$comp} ? || (position = ? AND id {$comp} ?))
340   - ORDER BY position {$order} LIMIT 1";
341   - $aParams = array($iFieldsetId, $position, $position, $iId);
342   -
343   - $result = DBUtil::getOneResult(array($sql, $aParams));
344   -
345   - if(PEAR::isError($result) || empty($result)){
346   - return false;
347   - }
348   - return $result;
349   - }
350   -
351   - /**
352   - * Get the updated position of the field
353   - *
354   - * @param int $iId
355   - * @return int
356   - */
357   - function getNewPosition($iId){
358   - // Get the new position
359   - $sql = "SELECT id, position FROM document_fields
360   - WHERE id = ?";
361   - $aParams = array($iId);
362   - $result = DBUtil::getOneResult(array($sql, $aParams));
363   -
364   - if(PEAR::isError($result) || empty($result)){
365   - return false;
366   - }
367   - return $result['position'];
368   - }
369   -
370   - /**
371   - * Update the position of a field
372   - */
373   - function updatePosition($iId, $position) {
374   - $aFields = array('position' => $position);
375   - DBUtil::autoUpdate('document_fields', $aFields, $iId);
376   - }
377   -
378   - /**
379   - * Move the display position of the field up
380   - */
381   - function movePosition($iFieldsetId, $iId, $dir = 'up') {
382   - $position = $this->getPosition();
383   -
384   - // Get the field to swop position with
385   - $next = $this->getNextPosition($iFieldsetId, $iId, $position, $dir);
386   - if($next === false){
387   - return false;
388   - }
389   -
390   - // Get position of the next field up / down
391   - $newPos = $next['position'];
392   - $iNextId = $next['id'];
393   -
394   - if($newPos == $position){
395   - // 2 fields have the same position - reorder them
396   - $res = $this->reorderFields($iFieldsetId);
397   - if($res === false){
398   - return false;
399   - }
400   -
401   - $position = $this->getNewPosition($iId);
402   - if($position === false){
403   - return false;
404   - }
405   -
406   - // Get the field to swop with
407   - $next = $this->getNextPosition($iFieldsetId, $iId, $position, $dir);
408   - if($next === false){
409   - return false;
410   - }
411   - $newPos = $next['position'];
412   - $iNextId = $next['id'];
413   - }
414   -
415   - // update the fields
416   - $this->updatePosition($iId, $newPos);
417   - $this->updatePosition($iNextId, $position);
418   - return true;
419   - }
  415 + /**
  416 + * Move the display position of the field up
  417 + */
  418 + function movePosition($iFieldsetId, $iId, $dir = 'up') {
  419 + $position = $this->getPosition();
  420 +
  421 + // Get the field to swop position with
  422 + $next = $this->getNextPosition($iFieldsetId, $iId, $position, $dir);
  423 + if($next === false){
  424 + return false;
  425 + }
  426 +
  427 + // Get position of the next field up / down
  428 + $newPos = $next['position'];
  429 + $iNextId = $next['id'];
  430 +
  431 + if($newPos == $position){
  432 + // 2 fields have the same position - reorder them
  433 + $res = $this->reorderFields($iFieldsetId);
  434 + if($res === false){
  435 + return false;
  436 + }
  437 +
  438 + $position = $this->getNewPosition($iId);
  439 + if($position === false){
  440 + return false;
  441 + }
  442 +
  443 + // Get the field to swop with
  444 + $next = $this->getNextPosition($iFieldsetId, $iId, $position, $dir);
  445 + if($next === false){
  446 + return false;
  447 + }
  448 + $newPos = $next['position'];
  449 + $iNextId = $next['id'];
  450 + }
  451 +
  452 + // update the fields
  453 + $this->updatePosition($iId, $newPos);
  454 + $this->updatePosition($iNextId, $position);
  455 + return true;
  456 + }
420 457 }
421 458  
422 459 /**
... ... @@ -424,13 +461,13 @@ class DocumentField extends KTEntity {
424 461 *
425 462 * Creates a document type object from an array
426 463 *
427   -* @param Array Array of parameters. Must match order of parameters in constructor
  464 +* @param Array Array of parameters. Must match order of parameters in constructor
428 465 *
429 466 * @return User user object
430 467 */
431 468 function & documentfieldCreateFromArray($aParameters) {
432   - $oDocField = new DocumentField($aParameters[0], $aParameters[1], $aParameters[2], $aParameters[3], $aParameters[4], $aParameters[5], $aParameters[6], $aParameters[7], $aParameters[8], $aParameters[9], $aParameters[10]);
433   - return $oDocField;
  469 + $oDocField = new DocumentField($aParameters[0], $aParameters[1], $aParameters[2], $aParameters[3], $aParameters[4], $aParameters[5], $aParameters[6], $aParameters[7], $aParameters[8], $aParameters[9], $aParameters[10]);
  470 + return $oDocField;
434 471 }
435 472  
436 473  
... ...
lib/metadata/fieldsetregistry.inc.php
... ... @@ -102,19 +102,19 @@ class KTFieldsetRegistry {
102 102 $widgets = array();
103 103 $fields = $oFieldset->getFields();
104 104  
105   - if ($oFieldset->getIsConditional()) {
106   - $iMasterId = $oFieldset->getMasterFieldId();
107   -
108   - $oMasterField = DocumentField::get($iMasterId);
109   -
110   - $newfields = array();
111   - $newfields[] = $oMasterField;
112   - foreach($fields as $oField) {
113   - if($oField->getId() != $iMasterId) {
114   - $newfields[] = $oField;
115   - }
116   - }
117   -
  105 + if ($oFieldset->getIsConditional()) {
  106 + $iMasterId = $oFieldset->getMasterFieldId();
  107 +
  108 + $oMasterField = DocumentField::get($iMasterId);
  109 +
  110 + $newfields = array();
  111 + $newfields[] = $oMasterField;
  112 + foreach($fields as $oField) {
  113 + if($oField->getId() != $iMasterId) {
  114 + $newfields[] = $oField;
  115 + }
  116 + }
  117 +
118 118 foreach ($newfields as $oField) {
119 119 $fname = 'metadata_' . $oField->getId();
120 120 $value = null;
... ... @@ -126,23 +126,23 @@ class KTFieldsetRegistry {
126 126 }
127 127 }
128 128  
129   - $widgets[] = $this->oWF->get('ktcore.widgets.conditionalselection',
130   - array(
131   - 'label' => $oField->getName(),
132   - 'required' => $oField->getIsMandatory(),
133   - 'name' => $fname,
134   - 'value' => $value,
135   - 'description' => $oField->getDescription(),
136   - 'vocab' => MetaData::getEnabledByDocumentField($oField),
137   - 'id_method' => 'getName',
138   - 'label_method' => 'getName',
139   - 'unselected_label' => _kt("No selection."),
140   - 'simple_select' => false,
141   - 'master' => ($oField->getId() == $iMasterId),
142   - 'masterid' => $iMasterId,
143   - 'fieldset' => $oFieldset->getId(),
144   - 'field' => $oField->getId(),
145   - ));
  129 + $widgets[] = $this->oWF->get('ktcore.widgets.conditionalselection',
  130 + array(
  131 + 'label' => $oField->getName(),
  132 + 'required' => $oField->getIsMandatory(),
  133 + 'name' => $fname,
  134 + 'value' => $value,
  135 + 'description' => $oField->getDescription(),
  136 + 'vocab' => MetaData::getEnabledByDocumentField($oField),
  137 + 'id_method' => 'getName',
  138 + 'label_method' => 'getName',
  139 + 'unselected_label' => _kt("No selection."),
  140 + 'simple_select' => false,
  141 + 'master' => ($oField->getId() == $iMasterId),
  142 + 'masterid' => $iMasterId,
  143 + 'fieldset' => $oFieldset->getId(),
  144 + 'field' => $oField->getId(),
  145 + ));
146 146 }
147 147 } else {
148 148 foreach ($fields as $oField) {
... ... @@ -169,16 +169,14 @@ class KTFieldsetRegistry {
169 169 } else {
170 170 $type = 'ktcore.fields.lookup';
171 171 }
172   - } else {
  172 + } else if($oField->getHasInetLookup()) {
  173 + $type = 'ktcore.fields.multiselect';
  174 + } else {
173 175 $type = 'ktcore.fields.string';
174 176 }
175 177  
176   - /* ------------------------------------
177   - ---- Changes for Custom Fields -----
178   - ------------------------------------ */
179   -
180 178 if ($oField->getDataType() == 'LARGE TEXT') {
181   - $type = 'ktcore.fields.largetext';
  179 + $type = 'ktcore.fields.largetext';
182 180 } else if ($oField->getDataType() == 'DATE') {
183 181 $type = 'ktcore.fields.date';
184 182 }
... ... @@ -214,10 +212,7 @@ class KTFieldsetRegistry {
214 212 'vocab' => MetaData::getEnabledByDocumentField($oField),
215 213 'field_id' => $oField->getId(),
216 214 ));
217   - } else if ($type == 'ktcore.fields.largetext') {
218   - /* ------------------------------------
219   - ---- Changes for Custom Fields -----
220   - ------------------------------------ */
  215 + } else if ($type == 'ktcore.fields.largetext') {
221 216 $widgets[] = $this->oWF->get('ktcore.widgets.textarea', array(
222 217 'label' => $oField->getName(),
223 218 'required' => $oField->getIsMandatory(),
... ... @@ -226,10 +221,7 @@ class KTFieldsetRegistry {
226 221 'description' => $oField->getDescription(),
227 222 'field' => $oField,
228 223 ));
229   - } else if ($type == 'ktcore.fields.date') {
230   - /* ------------------------------------
231   - ---- Changes for Custom Fields -----
232   - ------------------------------------ */
  224 + } else if ($type == 'ktcore.fields.date') {
233 225 $widgets[] = $this->oWF->get('ktcore.widgets.date', array(
234 226 'label' => $oField->getName(),
235 227 'required' => $oField->getIsMandatory(),
... ... @@ -237,20 +229,76 @@ class KTFieldsetRegistry {
237 229 'value' => $value,
238 230 'description' => $oField->getDescription(),
239 231 ));
  232 + } else if ($type == 'ktcore.fields.multiselect') {
  233 + if($oField->getInetLookupType() == "multiwithlist") {
  234 + $widgets[] = $this->oWF->get('ktcore.widgets.entityselection', array(
  235 + 'label' => $oField->getName(),
  236 + 'required' => $oField->getIsMandatory(),
  237 + 'name' => $fname,
  238 + 'value' => explode(", ",$value),
  239 + 'description' => $oField->getDescription(),
  240 + 'vocab' => MetaData::getEnabledByDocumentField($oField),
  241 + 'id_method' => 'getName',
  242 + 'label_method' => 'getName',
  243 + 'unselected_label' => false,
  244 + 'simple_select' => false,
  245 + 'multi'=> true,
  246 + ));
  247 + } else if($oField->getInetLookupType() == "multiwithcheckboxes") {
  248 + $widgets[] = $this->oWF->get('ktcore.widgets.entityselection', array(
  249 + 'label' => $oField->getName(),
  250 + 'required' => $oField->getIsMandatory(),
  251 + 'name' => $fname,
  252 + 'value' => explode(", ",$value),
  253 + 'description' => $oField->getDescription(),
  254 + 'vocab' => MetaData::getEnabledByDocumentField($oField),
  255 + 'field_id' => $oField->getId(),
  256 + 'id_method' => 'getName',
  257 + 'label_method' => 'getName',
  258 + 'unselected_label' => false,
  259 + 'simple_select' => true,
  260 + 'multi'=> true,
  261 + ));
  262 + } else {
  263 + $widgets[] = $this->oWF->get('ktcore.widgets.entityselection', array(
  264 + 'label' => $oField->getName(),
  265 + 'required' => $oField->getIsMandatory(),
  266 + 'name' => $fname,
  267 + 'value' => $value,
  268 + 'description' => $oField->getDescription(),
  269 + 'field' => $oField,
  270 + 'vocab' => MetaData::getEnabledByDocumentField($oField),
  271 + 'id_method' => 'getName',
  272 + 'label_method' => 'getName',
  273 + 'unselected_label' => _kt("No selection."),
  274 + 'simple_select' => false,
  275 + ));
  276 + }
  277 +
  278 + } else if ($type == 'ktcore.fields.tree') {
  279 + $widgets[] = $this->oWF->get('ktcore.widgets.treemetadata', array(
  280 + 'label' => $oField->getName(),
  281 + 'required' => $oField->getIsMandatory(),
  282 + 'name' => $fname,
  283 + 'value' => $value,
  284 + 'description' => $oField->getDescription(),
  285 + 'vocab' => MetaData::getEnabledByDocumentField($oField),
  286 + 'field_id' => $oField->getId(),
  287 + ));
240 288 }
241 289 }
242 290  
243 291  
244 292 }
245   -
246   - return array($this->oWF->get('ktcore.widgets.fieldset',
247   - array(
  293 +
  294 + return array($this->oWF->get('ktcore.widgets.fieldset',
  295 + array(
248 296 'label' => $oFieldset->getName(),
249 297 'description' => $oFieldset->getDescription(),
250 298 'name' => $sContainerName,
251 299 'widgets' => $widgets,
252 300 )));
253   -
  301 +
254 302 }
255 303  
256 304  
... ... @@ -274,15 +322,15 @@ class KTFieldsetRegistry {
274 322 foreach ($fields as $oField) {
275 323 $fname = 'metadata_' . $oField->getId();
276 324  
277   - // Change back to 'membership'
278   - $validators[] = $this->oVF->get('ktcore.validators.membership',
279   - array(
280   - 'test' => $fname,
281   - 'output' => $fname,
282   - 'vocab' => MetaData::getEnabledValuesByDocumentField($oField),
283   - 'id_method' => 'getName',
284   - ));
285   - }
  325 + // Change back to 'membership'
  326 + $validators[] = $this->oVF->get('ktcore.validators.membership',
  327 + array(
  328 + 'test' => $fname,
  329 + 'output' => $fname,
  330 + 'vocab' => MetaData::getEnabledValuesByDocumentField($oField),
  331 + 'id_method' => 'getName',
  332 + ));
  333 + }
286 334 } else {
287 335 $validators = array();
288 336 $fields = $oFieldset->getFields();
... ... @@ -310,7 +358,9 @@ class KTFieldsetRegistry {
310 358 } else {
311 359 $type = 'ktcore.fields.lookup';
312 360 }
313   - } else {
  361 + } else if($oField->getHasInetLookup()) {
  362 + $type = 'ktcore.fields.multiselect';
  363 + } else {
314 364 $type = 'ktcore.fields.string';
315 365 }
316 366  
... ... @@ -336,14 +386,45 @@ class KTFieldsetRegistry {
336 386 'vocab' => MetaData::getEnabledValuesByDocumentField($oField),
337 387 'id_method' => 'getName',
338 388 ));
  389 + } else if ($type == 'ktcore.fields.multiselect') {
  390 + if($oField->getInetLookupType() == "multiwithlist")
  391 + {
  392 + $validators[] = $this->oVF->get('ktcore.validators.membership',array(
  393 + 'test' => $fname,
  394 + 'output' => $fname,
  395 + 'vocab' => MetaData::getEnabledValuesByDocumentField($oField),
  396 + 'id_method' => 'getName',
  397 + 'multi' => true,
  398 + ));
  399 + }
  400 + else if($oField->getInetLookupType() == "multiwithcheckboxes")
  401 + {
  402 + $validators[] = $this->oVF->get('ktcore.validators.membership',array(
  403 + 'test' => $fname,
  404 + 'output' => $fname,
  405 + 'vocab' => MetaData::getEnabledValuesByDocumentField($oField),
  406 + 'id_method' => 'getName',
  407 + 'multi' => true,
  408 + ));
  409 + }
  410 + else
  411 + {
  412 + $validators[] = $this->oVF->get('ktcore.validators.membership',array(
  413 + 'test' => $fname,
  414 + 'output' => $fname,
  415 + 'vocab' => MetaData::getEnabledValuesByDocumentField($oField),
  416 + 'id_method' => 'getName',
  417 + ));
  418 + }
  419 +
339 420 } else {
340 421 $validators[] = PEAR::raiseError(sprintf(_kt("Unable to deal with field: id %d"), $oField->getId()));
341 422 }
342 423 }
343 424  
344 425 }
345   - return array($this->oVF->get('ktcore.validators.fieldset',
346   - array(
  426 + return array($this->oVF->get('ktcore.validators.fieldset',
  427 + array(
347 428 'test' => $sContainerName,
348 429 'output' => $sContainerName,
349 430 'validators' => $validators,
... ...
lib/search/searchutil.inc.php
... ... @@ -63,7 +63,7 @@ class KTSearchUtil {
63 63 $type = KTUtil::arrayGet($dataset, "type");
64 64 $sql = KTUtil::arrayGet($dataset, "sql");
65 65 if (!empty($type)) {
66   - $oCriteriaRegistry =& KTCriteriaRegistry::getSingleton();
  66 + $oCriteriaRegistry =& KTCriteriaRegistry::getSingleton();
67 67 $oCriterion = $oCriteriaRegistry->getCriterion($dataset['type']);
68 68 if (PEAR::isError($oCriterion)) {
69 69 return PEAR::raiseError(_kt('Invalid criteria specified.'));
... ... @@ -84,13 +84,45 @@ class KTSearchUtil {
84 84 $aReq = $oCriterionPair[1];
85 85  
86 86 if (is_object($oCriterion)) {
87   - $res = $oCriterion->searchSQL($aReq);
88   - if (!is_null($res)) {
89   - $aSQL[] = $res;
  87 + if(is_array($aReq[$oCriterion->sNamespace]) && KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin'))
  88 + {
  89 + //$newAReq = $aReq;
  90 + $aNewSQL = array();
  91 + foreach($aReq[$oCriterion->sNamespace] as $kkey => $vval)
  92 + {
  93 + $newAReq = $aReq;
  94 + $newAReq[$oCriterion->sNamespace] = $vval;
  95 + $res = $oCriterion->searchSQL($newAReq);
  96 + if (!is_null($res)) {
  97 + $aNewSQL[] = $res;
  98 + }
  99 + }
  100 +
  101 + $aNewSQL0 = array();
  102 + $aNewSQL1 = array();
  103 + foreach($aNewSQL as $ind=>$sQ)
  104 + {
  105 + $aNewSQL0[] = $sQ[0];
  106 + $aNewSQL1 = array_merge($aNewSQL1,$sQ[1]);
  107 + }
  108 +
  109 + $aSQL[] = array(" ( ".join(" ) ".$aReq[$oCriterion->sNamespace."_join"]." ( ", $aNewSQL0)." ) ",$aNewSQL1 );
  110 +
  111 + $res = $oCriterion->searchJoinSQL();
  112 + if (!is_null($res)) {
  113 + $aJoinSQL[] = $res;
  114 + }
90 115 }
91   - $res = $oCriterion->searchJoinSQL();
92   - if (!is_null($res)) {
93   - $aJoinSQL[] = $res;
  116 + else
  117 + {
  118 + $res = $oCriterion->searchSQL($aReq);
  119 + if (!is_null($res)) {
  120 + $aSQL[] = $res;
  121 + }
  122 + $res = $oCriterion->searchJoinSQL();
  123 + if (!is_null($res)) {
  124 + $aJoinSQL[] = $res;
  125 + }
94 126 }
95 127 } else {
96 128 $aSQL[] = array($oCriterion, $aReq);
... ... @@ -120,6 +152,300 @@ class KTSearchUtil {
120 152 }
121 153 // }}}
122 154  
  155 + /**
  156 + * All for folders only
  157 + * Handles leaf criteria set (ie, no subgroups), generating SQL for
  158 + * the values in the criteria.
  159 + *
  160 + * (This would be the place to extend criteria to support contains,
  161 + * starts with, ends with, greater than, and so forth.)
  162 + */
  163 + function _oneCriteriaFolderSetToSQL($aOneCriteriaSet) {
  164 + $aSQL = array();
  165 + $aJoinSQL = array();
  166 + $criteria_set = array();
  167 +
  168 + /*
  169 + * First phase: get criterion object for search or the direct
  170 + * SQL to use.
  171 + *
  172 + * XXX: Why is there $order there?
  173 + */
  174 + foreach ($aOneCriteriaSet as $order => $dataset) {
  175 + $type = KTUtil::arrayGet($dataset, "type");
  176 + $sql = KTUtil::arrayGet($dataset, "sql");
  177 + if (!empty($type)) {
  178 + $oCriteriaRegistry =& KTCriteriaRegistry::getSingleton();
  179 + $oCriterion = $oCriteriaRegistry->getCriterion($dataset['type']);
  180 +
  181 + if (PEAR::isError($oCriterion)) {
  182 + return PEAR::raiseError(_kt('Invalid criteria specified.'));
  183 + }
  184 + $criteria_set[] = array($oCriterion, $dataset["data"]);
  185 + } else if (!empty($sql)) {
  186 + $criteria_set[] = $sql;
  187 + } else {
  188 + return PEAR::raiseError(_kt('Invalid criteria specified.'));
  189 + }
  190 + }
  191 +
  192 + /*
  193 + * Second phase: Create an individual SQL query per criteria.
  194 + */
  195 + foreach ($criteria_set as $oCriterionPair) {
  196 + $oCriterion->aLookup[table]='folder_field_links';
  197 +
  198 + $oCriterion = $oCriterionPair[0];
  199 + $aReq = $oCriterionPair[1];
  200 +
  201 +
  202 +
  203 +
  204 + if (is_object($oCriterion)) {
  205 + // changed by dp start // for multiselect search for folders
  206 + if(is_array($aReq[$oCriterion->sNamespace]) && KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin'))
  207 + {
  208 + $aNewSQL = array();
  209 + foreach($aReq[$oCriterion->sNamespace] as $kkey => $vval)
  210 + {
  211 + $newAReq = $aReq;
  212 + $newAReq[$oCriterion->sNamespace] = $vval;
  213 + $res = $oCriterion->searchSQL($newAReq);
  214 + if (!is_null($res)) {
  215 + $aNewSQL[] = $res;
  216 + }
  217 + }
  218 +
  219 + $aNewSQL0 = array();
  220 + $aNewSQL1 = array();
  221 + foreach($aNewSQL as $ind=>$sQ)
  222 + {
  223 + $aNewSQL0[] = $sQ[0];
  224 + $aNewSQL1 = array_merge($aNewSQL1,$sQ[1]);
  225 + }
  226 + $aSQL[] = array(" ( ".join(" ) ".$aReq[$oCriterion->sNamespace."_join"]." ( ", $aNewSQL0)." ) ",$aNewSQL1 );
  227 + $res = $oCriterion->searchJoinSQL();
  228 + if (!is_null($res)) {
  229 + if(strstr($res,'D.metadata_version_id')){
  230 + $res=str_replace('D.metadata_version_id','F.metadata_version_id',$res);
  231 + }
  232 + if(strstr($res,'document_fields_link')){
  233 + $res=str_replace('document_fields_link','folder_fields_link',$res);
  234 + }
  235 + $aJoinSQL[] = $res;
  236 + }
  237 + }// changed by dp end // for multiselect search for folders
  238 + else
  239 + {
  240 + $res = $oCriterion->searchSQL($aReq);
  241 + if (!is_null($res)) {
  242 + $aSQL[] = $res;
  243 + }
  244 + $res = $oCriterion->searchJoinSQL();
  245 + if (!is_null($res)) {
  246 +
  247 + if(strstr($res,'D.metadata_version_id')){
  248 + $res=str_replace('D.metadata_version_id','F.metadata_version_id',$res);
  249 + }
  250 + if(strstr($res,'document_fields_link')){
  251 + $res=str_replace('document_fields_link','folder_fields_link',$res);
  252 + }
  253 + $aJoinSQL[] = $res;
  254 + }
  255 + }
  256 +
  257 + } else {
  258 + $aSQL[] = array($oCriterion, $aReq);
  259 + }
  260 + }
  261 +
  262 + /*
  263 + * Third phase: build up $aCritQueries and $aCritParams, and put
  264 + * parentheses around them.
  265 + */
  266 + $aCritParams = array();
  267 + $aCritQueries = array();
  268 + foreach ($aSQL as $sSQL) {
  269 + if (is_array($sSQL)) {
  270 + $aCritQueries[] = '('.$sSQL[0].')';
  271 + $aCritParams = kt_array_merge($aCritParams , $sSQL[1]);
  272 + } else {
  273 + $aCritQueries[] = '('.$sSQL.')';
  274 + }
  275 + }
  276 +
  277 +
  278 + if (count($aCritQueries) == 0) {
  279 + return PEAR::raiseError(_kt("No search criteria were specified"));
  280 + }
  281 +
  282 + return array($aCritQueries, $aCritParams, $aJoinSQL);
  283 + }
  284 + /**
  285 + * All for folders
  286 + * Converts a criteria set to the SQL joins, where clause, and
  287 + * parameters necessary to ensure that the criteria listed restrict
  288 + * the folders returned to those that match the criteria.
  289 + *
  290 + * Perhaps poorly called recursively to handle criteria that involve
  291 + * subgroups to allow infinitely nested criteria.
  292 + *
  293 + * Returns a list of the following elements:
  294 + * - String representing the where clause
  295 + * - Array of parameters that go with the where clause
  296 + * - String with the SQL necessary to join with the tables in the
  297 + * where clause
  298 + */
  299 + function criteriaFolderSetToSQL($aCriteriaSet, $iRecurseLevel = 0) {
  300 + $aJoinSQL = array();
  301 + $aSearchStrings = array();
  302 + $aParams = array();
  303 + /*
  304 + * XXX: We unnecessarily force the base criteria to have
  305 + * subgroups at the top level, even though we most often only
  306 + * have a single "subgroup".
  307 + */
  308 +
  309 + foreach ($aCriteriaSet["subgroup"] as $k => $aOneCriteriaSet) {
  310 + /*
  311 + * Each subgroup will either have values or it will have
  312 + * subgroups. They can't be mixed.
  313 + */
  314 + $aValues = KTUtil::arrayGet($aOneCriteriaSet, "values");
  315 + $aSubgroup = KTUtil::arrayGet($aOneCriteriaSet, "subgroup");
  316 + if (!empty($aValues)) {
  317 +
  318 + $res = KTSearchUtil::_oneCriteriaFolderSetToSQL($aOneCriteriaSet["values"]);
  319 +
  320 + if(PEAR::isError($res)) {
  321 + return $res;
  322 + }
  323 + list($aThisCritQueries, $aThisParams, $aThisJoinSQL) = $res;
  324 + $aJoinSQL = kt_array_merge($aJoinSQL, $aThisJoinSQL);
  325 + $aParams = kt_array_merge($aParams, $aThisParams);
  326 + $tabs = str_repeat("\t", ($iRecurseLevel + 2));
  327 + $aSearchStrings[] = "\n$tabs(\n$tabs\t" . join("\n " . KTUtil::arrayGet($aOneCriteriaSet, 'join', "AND") . " ", $aThisCritQueries) . "\n$tabs)";
  328 + } else if (!empty($aSubgroup)) {
  329 +
  330 + /*
  331 + * Recurse if we have a criteria set with subgroups.
  332 + * Recurselevel makes the tabs increase as we recurse so
  333 + * that the SQL statement is somewhat understandable.
  334 + */
  335 + list($sThisSearchString, $aThisParams, $sThisJoinSQL) =
  336 + KTSearchUtil::criteriaFolderSetToSQL($aOneCriteriaSet, $iRecurseLevel + 1);
  337 + $aJoinSQL[] = $sThisJoinSQL;
  338 + $aParams = kt_array_merge($aParams, $aThisParams);
  339 + $aSearchStrings[] = $sThisSearchString;
  340 + }
  341 + }
  342 + $aJoinSQL = array_unique($aJoinSQL);
  343 + $sJoinSQL = join(" ", $aJoinSQL);
  344 + $tabs = str_repeat("\t", $iRecurseLevel + 1);
  345 + $sSearchString = "\n$tabs(" . join("\n$tabs\t" . $aCriteriaSet['join'] . " ", $aSearchStrings) . "\n$tabs)";
  346 +
  347 + return array($sSearchString, $aParams, $sJoinSQL);
  348 + }
  349 +
  350 + /**
  351 + * All for folders
  352 + * Converts a criteria set into a SQL query that (by default)
  353 + * returns the ids of documents that fulfil the criteria.
  354 + *
  355 + * $aOptions is a dictionary that can contain:
  356 + * - select - a string that contains the list of columns
  357 + * selected in the query
  358 + * - join - a string that contains join conditions to satisfy
  359 + * the select string passed or limit the documents included
  360 + *
  361 + * A list with the following elements is returned:
  362 + * - String containing the parameterised SQL query
  363 + * - Array containing the parameters for the SQL query
  364 + */
  365 + function criteriaToFolderQuery($aCriteriaSet, $oUser, $sPermissionName, $aOptions = null) {
  366 + global $default;
  367 + $sSelect = KTUtil::arrayGet($aOptions, 'select', 'F.id AS folder_id');
  368 + $sInitialJoin = KTUtil::arrayGet($aOptions, 'join', '');
  369 + if (is_array($sInitialJoin)) {
  370 + $aInitialJoinParams = $sInitialJoin[1];
  371 + $sInitialJoin = $sInitialJoin[0];
  372 + }
  373 +
  374 + $res = KTSearchUtil::criteriaFolderSetToSQL($aCriteriaSet);
  375 +
  376 + if(PEAR::isError($res)) return $res;
  377 + list($sSQLSearchString, $aCritParams, $sCritJoinSQL) = $res;
  378 +
  379 + $sToSearch = KTUtil::arrayGet($aOrigReq, 'fToSearch', 'Live'); // actually never present in this version.
  380 +
  381 + $res = KTSearchUtil::permissionToSQL($oUser, $sPermissionName);
  382 +
  383 + if (PEAR::isError($res)) { // only occurs if the group has no permissions.
  384 + return $res;
  385 + } else {
  386 + list ($sPermissionString, $aPermissionParams, $sPermissionJoin) = $res;
  387 + }
  388 +
  389 + /*
  390 + * This is to overcome the problem where $sPermissionString (or
  391 + * even $sSQLSearchString) is empty, leading to leading or
  392 + * trailing ANDs.
  393 + */
  394 + $aPotentialWhere = array($sPermissionString,"($sSQLSearchString)");
  395 +
  396 + $aWhere = array();
  397 + foreach ($aPotentialWhere as $sWhere) {
  398 + if (empty($sWhere)) {
  399 + continue;
  400 + }
  401 + if ($sWhere == "()") {
  402 + continue;
  403 + }
  404 + $aWhere[] = $sWhere;
  405 +
  406 + }
  407 + $sWhere = "";
  408 + if ($aWhere) {
  409 + $sWhere = "\tWHERE " . join(" AND ", $aWhere);
  410 + }
  411 +
  412 + //$sQuery = DBUtil::compactQuery("
  413 + $sQuery = sprintf("
  414 + SELECT
  415 + %s
  416 + FROM
  417 + %s AS F
  418 + LEFT JOIN %s AS DM ON F.metadata_version_id = DM.id
  419 + %s
  420 + %s
  421 + %s
  422 + %s", $sSelect, KTUtil::getTableName('folders'),
  423 + KTUtil::getTableName('folder_metadata_version'),
  424 +
  425 + $sInitialJoin,
  426 + $sCritJoinSQL,
  427 + $sPermissionJoin,
  428 + $sWhere
  429 + );
  430 + // GROUP BY D.id
  431 +
  432 + $aParams = array();
  433 + $aParams = kt_array_merge($aParams, $aInitialJoinParams);
  434 + $aParams = kt_array_merge($aParams, $aPermissionParams);
  435 +
  436 + if($sToSearch!='Live')
  437 + $aParams[] = $sToSearch;
  438 + $aParams = kt_array_merge($aParams, $aCritParams);
  439 +
  440 +
  441 + if(strstr($sQuery,'document_field_id')){
  442 + $sQuery=str_replace('document_field_id','folder_field_id',$sQuery);
  443 + }
  444 + if(strstr($sQuery,'D.creator_id')){
  445 + $sQuery=str_replace('D.creator_id','F.creator_id',$sQuery);
  446 + }
  447 + return array($sQuery, $aParams);
  448 + }
123 449 // {{{ criteriaSetToSQL
124 450 /**
125 451 * Converts a criteria set to the SQL joins, where clause, and
... ... @@ -153,15 +479,15 @@ class KTSearchUtil {
153 479 $aValues = KTUtil::arrayGet($aOneCriteriaSet, "values");
154 480 $aSubgroup = KTUtil::arrayGet($aOneCriteriaSet, "subgroup");
155 481 if (!empty($aValues)) {
156   - $res = KTSearchUtil::_oneCriteriaSetToSQL($aOneCriteriaSet["values"]);
157   - if(PEAR::isError($res)) {
158   - return $res;
159   - }
160   - list($aThisCritQueries, $aThisParams, $aThisJoinSQL) = $res;
161   - $aJoinSQL = kt_array_merge($aJoinSQL, $aThisJoinSQL);
162   - $aParams = kt_array_merge($aParams, $aThisParams);
163   - $tabs = str_repeat("\t", ($iRecurseLevel + 2));
164   - $aSearchStrings[] = "\n$tabs(\n$tabs\t" . join("\n " . KTUtil::arrayGet($aOneCriteriaSet, 'join', "AND") . " ", $aThisCritQueries) . "\n$tabs)";
  482 + $res = KTSearchUtil::_oneCriteriaSetToSQL($aOneCriteriaSet["values"]);
  483 + if(PEAR::isError($res)) {
  484 + return $res;
  485 + }
  486 + list($aThisCritQueries, $aThisParams, $aThisJoinSQL) = $res;
  487 + $aJoinSQL = kt_array_merge($aJoinSQL, $aThisJoinSQL);
  488 + $aParams = kt_array_merge($aParams, $aThisParams);
  489 + $tabs = str_repeat("\t", ($iRecurseLevel + 2));
  490 + $aSearchStrings[] = "\n$tabs(\n$tabs\t" . join("\n " . KTUtil::arrayGet($aOneCriteriaSet, 'join', "AND") . " ", $aThisCritQueries) . "\n$tabs)";
165 491 } else if (!empty($aSubgroup)) {
166 492 /*
167 493 * Recurse if we have a criteria set with subgroups.
... ... @@ -269,15 +595,15 @@ class KTSearchUtil {
269 595 $sInitialJoin = $sInitialJoin[0];
270 596 }
271 597  
272   - $res = KTSearchUtil::criteriaSetToSQL($aCriteriaSet);
  598 + $res = KTSearchUtil::criteriaSetToSQL($aCriteriaSet);
273 599  
274   - if(PEAR::isError($res)) return $res;
  600 + if(PEAR::isError($res)) return $res;
275 601 list($sSQLSearchString, $aCritParams, $sCritJoinSQL) = $res;
276 602  
277 603 $sToSearch = KTUtil::arrayGet($aOrigReq, 'fToSearch', 'Live'); // actually never present in this version.
278 604  
279 605 $res = KTSearchUtil::permissionToSQL($oUser, $sPermissionName);
280   -
  606 +
281 607 if (PEAR::isError($res)) { // only occurs if the group has no permissions.
282 608 return $res;
283 609 } else {
... ... @@ -389,5 +715,52 @@ class KTSearchUtil {
389 715 return $cnt > 0;
390 716 }
391 717 // }}}
392   -}
  718 +
  719 +
  720 +function testConditionOnFolder($oSearch, $oFolder) {
  721 + $oSearch =& KTUtil::getObject('KTSavedSearch', $oSearch);
  722 + $iFolderId = KTUtil::getId($oFolder);
393 723  
  724 + /*
  725 + * Make a new criteria set, an AND of the existing criteria set
  726 + * and the sql statement requiring that D.id be the document id
  727 + * given to us.
  728 + */
  729 + $aCriteriaSet = array(
  730 + "join" => "AND",
  731 + "subgroup" => array(
  732 + $oSearch->getSearch(),
  733 + array(
  734 + "join" => "AND",
  735 + "values" => array(
  736 + array(
  737 + "sql" => array("F.id = ?", array($iFolderId)),
  738 + ),
  739 + ),
  740 + ),
  741 + ),
  742 + );
  743 + $aOptions = array('select' => 'COUNT(DISTINCT(F.id)) AS cnt');
  744 + $aQuery = KTSearchUtil::criteriaToFolderQuery($aCriteriaSet, null, null, $aOptions);
  745 +
  746 +
  747 +
  748 + if (PEAR::isError($aQuery)) { // caused by no permissions being set.
  749 + return false;
  750 + }
  751 + $cnt = DBUtil::getOneResultKey($aQuery, 'cnt');
  752 +
  753 + if (PEAR::isError($cnt)) {
  754 + return $cnt;
  755 + }
  756 + if (is_null($cnt)) {
  757 + return false;
  758 + }
  759 + if (!is_numeric($cnt)) {
  760 + return PEAR::raiseError(_kt("Non-integer returned when looking for count"));
  761 + }
  762 +
  763 + return $cnt > 0;
  764 + }
  765 +
  766 +}
394 767 \ No newline at end of file
... ...
lib/widgets/fieldsetDisplay.inc.php
... ... @@ -108,10 +108,24 @@ function getWidgetForMetadataField($field, $current_value, $page, $errors = null
108 108 $fieldTree = new MDTree();
109 109 $fieldTree->buildForField($field->getId());
110 110 $fieldTree->setActiveItem($current_value);
111   - $fieldOptions['tree'] = $fieldTree->_evilTreeRenderer($fieldTree, $fieldName);
  111 + $fieldOptions['tree'] = $fieldTree->_evilTreeRenderer($fieldTree, $fieldName);
112 112  
113 113 $oField = new KTTreeWidget($fieldLabel, $fieldDescription, $fieldName, $fieldValue, $page, $fieldRequired, null, $fieldErrors, $fieldOptions);
114 114 }
  115 + } else if(KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin') && $field->getHasInetLookup()){
  116 + require_once(KT_DIR."/plugins/multiselect/InetWidgets.php");
  117 + if ($vocab === null) { // allow override
  118 + $lookups = MetaData::getEnabledByDocumentField($field);
  119 + $fieldOptions['vocab'] = array(); // FIXME handle lookups
  120 + foreach ($lookups as $md) {
  121 + $fieldOptions['vocab'][$md->getName()] = $md->getName();
  122 + }
  123 + } else {
  124 + $fieldOptions['vocab'] = $vocab;
  125 + }
  126 + $fieldOptions['multi'] = true;
  127 + $fieldOptions['lookup_type'] = $field->getInetLookupType();
  128 + $oField = new InetMultiselectWidget($fieldLabel, $fieldDescription, $fieldName, $fieldValue, $page, $fieldRequired, null, $fieldErrors, $fieldOptions);
115 129 } else {
116 130 $oField = new KTBaseWidget($fieldLabel, $fieldDescription, $fieldName, $fieldValue, $page, $fieldRequired, null, $fieldErrors, $fieldOptions);
117 131 }
... ... @@ -170,8 +184,8 @@ class KTFieldsetDisplay {
170 184 if (!empty($res['friendly_name'])) {
171 185 return _kt($res['friendly_name']);
172 186 } else {
173   - return sprintf(_kt('%s File'), strtoupper($res['filetypes']));
174   - }
  187 + return sprintf(_kt('%s File'), strtoupper($res['filetypes']));
  188 + }
175 189  
176 190 }
177 191  
... ... @@ -247,7 +261,7 @@ class GenericFieldsetDisplay extends KTFieldsetDisplay {
247 261 'document_data' => $aDocumentData,
248 262 'document' => $aDocumentData['document'],
249 263  
250   - 'filename' => $document->getFileName(),
  264 + 'filename' => $document->getFileName(),
251 265  
252 266 'creator' => $creator_name,
253 267 'owner' => $owner_name,
... ... @@ -323,11 +337,11 @@ class GenericFieldsetDisplay extends KTFieldsetDisplay {
323 337 'document_data' => $aDocumentData,
324 338 'document' => $aDocumentData['document'],
325 339  
326   - 'title' => $document->getName(),
327   - 'comparison_title' => $comparison_document->getName(),
  340 + 'title' => $document->getName(),
  341 + 'comparison_title' => $comparison_document->getName(),
328 342  
329   - 'filename' => $document->getFileName(),
330   - 'comparison_filename' => $comparison_document->getFileName(),
  343 + 'filename' => $document->getFileName(),
  344 + 'comparison_filename' => $comparison_document->getFileName(),
331 345  
332 346 'creator' => $creator,
333 347 'creation_date' => $creation_date,
... ... @@ -410,7 +424,7 @@ class SimpleFieldsetDisplay extends KTFieldsetDisplay {
410 424 'document' => $aDocumentData['document'],
411 425 'fieldset' => $this->fieldset,
412 426 'fieldset_values' => $fieldset_values,
413   - 'description' => $this->fieldset->getDescription(),
  427 + 'description' => $this->fieldset->getDescription(),
414 428 );
415 429 return $oTemplate->render($aTemplateData);
416 430 }
... ... @@ -519,25 +533,25 @@ class ConditionalFieldsetDisplay extends SimpleFieldsetDisplay {
519 533 // how?
520 534  
521 535 $fieldset_name = $this->fieldset->getName();
522   - $fieldset_description = _kt($this->fieldset->getDescription()); // need a better approach. how do we handle database-resident translations?
  536 + $fieldset_description = _kt($this->fieldset->getDescription()); // need a better approach. how do we handle database-resident translations?
523 537 $fieldset_description .= _kt('Note that the options which are available depends on previous choices within this fieldset.');
524 538  
525 539 // FIXME handle the editable case _with_ values.
526 540  
527 541 if ($have_values) {
528   - $oTemplating =& KTTemplating::getSingleton();
529   - $oTemplate = $oTemplating->loadTemplate('kt3/fieldsets/conditional_editable_values');
530   - $aTemplateData = array(
531   - 'context' => $this,
532   - 'fields' => $fields =& $this->fieldset->getFields(),
533   - 'fieldset_id' => $this->fieldset->getId(),
534   - 'title' => $fieldset_name,
535   - 'description' => $fieldset_description,
536   - 'values' => $values,
  542 + $oTemplating =& KTTemplating::getSingleton();
  543 + $oTemplate = $oTemplating->loadTemplate('kt3/fieldsets/conditional_editable_values');
  544 + $aTemplateData = array(
  545 + 'context' => $this,
  546 + 'fields' => $fields =& $this->fieldset->getFields(),
  547 + 'fieldset_id' => $this->fieldset->getId(),
  548 + 'title' => $fieldset_name,
  549 + 'description' => $fieldset_description,
  550 + 'values' => $values,
537 551 'errors' => $errors,
538   - );
  552 + );
539 553  
540   - return $oTemplate->render($aTemplateData);
  554 + return $oTemplate->render($aTemplateData);
541 555 } // else {
542 556  
543 557 $oTemplating =& KTTemplating::getSingleton();
... ...
plugins/ktcore/document/edit.php
... ... @@ -219,14 +219,17 @@ class KTDocumentEditAction extends KTDocumentAction {
219 219  
220 220 if($oField->getDataType() == "LARGE TEXT")
221 221 {
222   - if(strlen(strip_tags($val)) > $oField->getMaxLength())
223   - {
224   - $oForm->handleError(sprintf(_kt("Value exceeds max allowed length of %d characters for %s. Current value is %d characters."), $oField->getMaxLength(), $oField->getName(), strlen(strip_tags($val))));
225   - }
  222 + if(strlen(strip_tags($val)) > $oField->getMaxLength())
  223 + {
  224 + $oForm->handleError(sprintf(_kt("Value exceeds max allowed length of %d characters for %s. Current value is %d characters."), $oField->getMaxLength(), $oField->getName(), strlen(strip_tags($val))));
  225 + }
226 226 }
227 227  
228 228 // FIXME "null" has strange meanings here.
229 229 if (!is_null($val)) {
  230 + if(KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin') && is_array($val) && $oField->getHasInetLookup()) {
  231 + $val = join(", ",$val);
  232 + }
230 233 $MDPack[] = array(
231 234 $oField,
232 235 $val
... ...
plugins/multiselect/BulkImport.php 0 โ†’ 100644
  1 +<?php
  2 +/**
  3 + * $Id$
  4 + *
  5 + * KnowledgeTree Community Edition
  6 + * Document Management Made Simple
  7 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  8 + * Portions copyright The Jam Warehouse Software (Pty) Limited
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify it under
  11 + * the terms of the GNU General Public License version 3 as published by the
  12 + * Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but WITHOUT
  15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  17 + * details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  23 + * California 94120-7775, or email info@knowledgetree.com.
  24 + *
  25 + * The interactive user interfaces in modified source and object code versions
  26 + * of this program must display Appropriate Legal Notices, as required under
  27 + * Section 5 of the GNU General Public License version 3.
  28 + *
  29 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  30 + * these Appropriate Legal Notices must retain the display of the "Powered by
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
  35 + * Contributor( s): ______________________________________
  36 + *
  37 + */
  38 +
  39 +require_once(KT_LIB_DIR . "/actions/folderaction.inc.php");
  40 +require_once(KT_LIB_DIR . "/import/fsimportstorage.inc.php");
  41 +require_once(KT_LIB_DIR . "/import/bulkimport.inc.php");
  42 +require_once(KT_LIB_DIR . "/documentmanagement/observers.inc.php");
  43 +
  44 +
  45 +require_once(KT_LIB_DIR . "/widgets/FieldsetDisplayRegistry.inc.php");
  46 +require_once(KT_LIB_DIR . "/widgets/fieldWidgets.php");
  47 +require_once(KT_LIB_DIR . "/widgets/fieldsetDisplay.inc.php");
  48 +
  49 +require_once(KT_LIB_DIR . "/validation/dispatchervalidation.inc.php");
  50 +
  51 +class InetBulkImportFolderMultiSelectAction extends KTFolderAction {
  52 + var $sName = 'inet.actions.folder.bulkImport.multiselect';
  53 +
  54 + var $_sShowPermission = "ktcore.permissions.write";
  55 + var $bAutomaticTransaction = false;
  56 +
  57 + /**
  58 + * hide existing url and return name to new url | iNET Process
  59 + * @Return string.
  60 + * @param.
  61 + */
  62 + function getDisplayName() {
  63 + if(!KTPluginUtil::pluginIsActive('inet.foldermetadata.plugin'))
  64 + {
  65 + $js = "<script src='plugins/multiselect/js/jquery-1.2.6.js' type='text/javascript'></script>";
  66 + $js .= "<script src='plugins/multiselect/js/hidelink.js' type='text/javascript'></script>";
  67 + return $js._kt('Import from Server Location');
  68 + }
  69 + else
  70 + {
  71 + return null;
  72 + }
  73 + }
  74 +
  75 + /**
  76 + * check for permissions | iNET Process
  77 + * @Return unknown.
  78 + * @param.
  79 + */
  80 + function getInfo() {
  81 + global $default;
  82 + if($default->disableBulkImport){
  83 + return null;
  84 + }
  85 +
  86 + if (!Permission::userIsSystemAdministrator($this->oUser->getId())) {
  87 + return null;
  88 +
  89 + }
  90 + return parent::getInfo();
  91 + }
  92 +
  93 + /**
  94 + * This is Default function to be called load template for import action. | iNET Process
  95 + * @Return template.
  96 + * @param.
  97 + */
  98 + function do_main() {
  99 + $this->oPage->setBreadcrumbDetails(_kt("bulk import"));
  100 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/folder/bulkImport');
  101 + $add_fields = array();
  102 + $add_fields[] = new KTStringWidget(_kt('Path'), _kt('The path containing the documents to be added to the document management system.'), 'path', "", $this->oPage, true);
  103 +
  104 + $aVocab = array('' => _kt('- Please select a document type -'));
  105 + foreach (DocumentType::getListForUserAndFolder($this->oUser, $this->oFolder) as $oDocumentType) {
  106 + if(!$oDocumentType->getDisabled()) {
  107 + $aVocab[$oDocumentType->getId()] = $oDocumentType->getName();
  108 + }
  109 + }
  110 +
  111 + $fieldOptions = array("vocab" => $aVocab);
  112 + $add_fields[] = new KTLookupWidget(_kt('Document Type'), _kt('Document Types, defined by the administrator, are used to categorise documents. Please select a Document Type from the list below.'), 'fDocumentTypeId', null, $this->oPage, true, "add-document-type", $fieldErrors, $fieldOptions);
  113 +
  114 + $fieldsets = array();
  115 + $fieldsetDisplayReg =& KTFieldsetDisplayRegistry::getSingleton();
  116 + $activesets = KTFieldset::getGenericFieldsets();
  117 + foreach ($activesets as $oFieldset) {
  118 + $displayClass = $fieldsetDisplayReg->getHandler($oFieldset->getNamespace());
  119 + array_push($fieldsets, new $displayClass($oFieldset));
  120 + }
  121 +
  122 + // Implement an electronic signature for accessing the admin section, it will appear every 10 minutes
  123 + global $default;
  124 + $iFolderId = $this->oFolder->getId();
  125 + if($default->enableESignatures){
  126 + $sUrl = KTPluginUtil::getPluginPath('electronic.signatures.plugin', true);
  127 + $heading = _kt('You are attempting to perform a bulk import');
  128 + $submit['type'] = 'button';
  129 + $submit['onclick'] = "javascript: showSignatureForm('{$sUrl}', '{$heading}', 'ktcore.transactions.bulk_import', 'bulk', 'bulk_import_form', 'submit', {$iFolderId});";
  130 + }else{
  131 + $submit['type'] = 'submit';
  132 + $submit['onclick'] = '';
  133 + }
  134 +
  135 + $oTemplate->setData(array(
  136 + 'context' => &$this,
  137 + 'submit' => $submit,
  138 + 'add_fields' => $add_fields,
  139 + 'generic_fieldsets' => $fieldsets,
  140 + ));
  141 + return $oTemplate->render();
  142 + }
  143 +
  144 + /**
  145 + * Performs actual import action. | iNET Process
  146 + * @Return.
  147 + * @param.
  148 + */
  149 + function do_import() {
  150 +
  151 + set_time_limit(0);
  152 +
  153 + $aErrorOptions = array(
  154 + 'redirect_to' => array('main', sprintf('fFolderId=%d', $this->oFolder->getId())),
  155 + );
  156 +
  157 + $aErrorOptions['message'] = _kt('Invalid document type provided');
  158 + $oDocumentType = $this->oValidator->validateDocumentType($_REQUEST['fDocumentTypeId'], $aErrorOptions);
  159 +
  160 + $aErrorOptions['message'] = _kt('Invalid path provided');
  161 + $sPath = $this->oValidator->validateString($_REQUEST['path'], $aErrorOptions);
  162 +
  163 + $matches = array();
  164 + $aFields = array();
  165 + foreach ($_REQUEST as $k => $v) {
  166 + if (preg_match('/^metadata_(\d+)$/', $k, $matches)) {
  167 +
  168 + // multiselect change start
  169 + $oDocField = DocumentField::get($matches[1]);
  170 + if(KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin') && $oDocField->getHasInetLookup() && is_array($v))
  171 + {
  172 + $v = join(", ", $v);
  173 + }
  174 + $aFields[] = array($oDocField, $v);
  175 +
  176 + // previously it was just one line which is commented, just above line
  177 + // multiselect change end
  178 + }
  179 + }
  180 +
  181 + $aOptions = array(
  182 + 'documenttype' => $oDocumentType,
  183 + 'metadata' => $aFields,
  184 + 'copy_upload' => 'true',
  185 + );
  186 +
  187 + $po =& new JavascriptObserver($this);
  188 + $po->start();
  189 + $oUploadChannel =& KTUploadChannel::getSingleton();
  190 + $oUploadChannel->addObserver($po);
  191 +
  192 + $fs =& new KTFSImportStorage($sPath);
  193 + $bm =& new KTBulkImportManager($this->oFolder, $fs, $this->oUser, $aOptions);
  194 + if(KTPluginUtil::pluginIsActive('inet.foldermetadata.plugin'))
  195 + {
  196 + require_once(KT_DIR . "/plugins/foldermetadata/import/bulkimport.inc.php");
  197 + $bm =& new KTINETBulkImportManager($this->oFolder, $fs, $this->oUser, $aOptions);
  198 + }
  199 + else
  200 + {
  201 + $bm =& new KTBulkImportManager($this->oFolder, $fs, $this->oUser, $aOptions);
  202 + }
  203 + DBUtil::startTransaction();
  204 + $res = $bm->import();
  205 + if (PEAR::isError($res)) {
  206 + DBUtil::rollback();
  207 + $_SESSION["KTErrorMessage"][] = _kt("Bulk import failed") . ": " . $res->getMessage();
  208 + } else {
  209 + DBUtil::commit();
  210 + $this->addInfoMessage(_kt("Bulk import succeeded"));
  211 + }
  212 +
  213 + $po->redirectToFolder($this->oFolder->getId());
  214 + exit(0);
  215 + }
  216 +}
... ...
plugins/multiselect/BulkUpload.php 0 โ†’ 100644
  1 +<?php
  2 +/**
  3 + * $Id$
  4 + *
  5 + * KnowledgeTree Community Edition
  6 + * Document Management Made Simple
  7 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  8 + * Portions copyright The Jam Warehouse Software (Pty) Limited
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify it under
  11 + * the terms of the GNU General Public License version 3 as published by the
  12 + * Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but WITHOUT
  15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  17 + * details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  23 + * California 94120-7775, or email info@knowledgetree.com.
  24 + *
  25 + * The interactive user interfaces in modified source and object code versions
  26 + * of this program must display Appropriate Legal Notices, as required under
  27 + * Section 5 of the GNU General Public License version 3.
  28 + *
  29 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  30 + * these Appropriate Legal Notices must retain the display of the "Powered by
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
  35 + * Contributor( s): ______________________________________
  36 + *
  37 + */
  38 +
  39 +require_once(KT_LIB_DIR . "/actions/folderaction.inc.php");
  40 +require_once(KT_LIB_DIR . "/import/zipimportstorage.inc.php");
  41 +require_once(KT_LIB_DIR . "/import/bulkimport.inc.php");
  42 +
  43 +require_once(KT_LIB_DIR . "/widgets/FieldsetDisplayRegistry.inc.php");
  44 +require_once(KT_LIB_DIR . "/widgets/fieldWidgets.php");
  45 +require_once(KT_LIB_DIR . "/widgets/fieldsetDisplay.inc.php");
  46 +
  47 +require_once(KT_LIB_DIR . "/validation/dispatchervalidation.inc.php");
  48 +
  49 +class InetBulkUploadFolderAction extends KTFolderAction {
  50 + var $sName = 'inet.actions.folder.bulkUpload';
  51 +
  52 + var $_sShowPermission = "ktcore.permissions.write";
  53 + var $bAutomaticTransaction = false;
  54 + /**
  55 + * returns the string
  56 + * @return
  57 + * loads the necessary javascripts too.
  58 + *
  59 + * iNET Process
  60 + */
  61 + function getDisplayName() {
  62 + if(!KTPluginUtil::pluginIsActive('inet.foldermetadata.plugin'))
  63 + {
  64 + $js = "<script src='plugins/multiselect/js/jquery-1.2.6.js' type='text/javascript'></script>";
  65 + $js .= "<script src='plugins/multiselect/js/hidelink.js' type='text/javascript'></script>";
  66 + return $js._kt('Bulk Upload');
  67 + }
  68 + else
  69 + {
  70 + return null;
  71 + }
  72 + }
  73 + /**
  74 + * Checks for bulk uploads
  75 + * @return
  76 + *
  77 + * iNET Process
  78 + */
  79 + function check() {
  80 + $res = parent::check();
  81 + if (empty($res)) {
  82 + return $res;
  83 + }
  84 + $postExpected = KTUtil::arrayGet($_REQUEST, "postExpected");
  85 + $postReceived = KTUtil::arrayGet($_REQUEST, "postReceived");
  86 + if (!empty($postExpected)) {
  87 + $aErrorOptions = array(
  88 + 'redirect_to' => array('main', sprintf('fFolderId=%d', $this->oFolder->getId())),
  89 + 'message' => _kt('Upload larger than maximum POST size (post_max_size variable in .htaccess or php.ini)'),
  90 + );
  91 + $this->oValidator->notEmpty($postReceived, $aErrorOptions);
  92 + }
  93 + return true;
  94 + }
  95 + /**
  96 + * default and basic function
  97 + * @return template
  98 + * @param.
  99 + * iNET Process
  100 + */
  101 + function do_main() {
  102 + $this->oPage->setBreadcrumbDetails(_kt("bulk upload"));
  103 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/folder/bulkUpload');
  104 + $add_fields = array();
  105 + $add_fields[] = new KTFileUploadWidget(_kt('Archive file'), _kt('The archive file containing the documents you wish to add to the document management system.'), 'file', "", $this->oPage, true, "file");
  106 +
  107 + $aVocab = array('' => _kt('- Please select a document type -'));
  108 + foreach (DocumentType::getListForUserAndFolder($this->oUser, $this->oFolder) as $oDocumentType) {
  109 + if(!$oDocumentType->getDisabled()) {
  110 + $aVocab[$oDocumentType->getId()] = $oDocumentType->getName();
  111 + }
  112 + }
  113 + $fieldOptions = array("vocab" => $aVocab);
  114 + $add_fields[] = new KTLookupWidget(_kt('Document Type'), _kt('Document Types, defined by the administrator, are used to categorise documents. Please select a Document Type from the list below.'), 'fDocumentTypeId', null, $this->oPage, true, "add-document-type", $fieldErrors, $fieldOptions);
  115 +
  116 + $fieldsets = array();
  117 + $fieldsetDisplayReg =& KTFieldsetDisplayRegistry::getSingleton();
  118 + $activesets = KTFieldset::getGenericFieldsets();
  119 + foreach ($activesets as $oFieldset) {
  120 + $displayClass = $fieldsetDisplayReg->getHandler($oFieldset->getNamespace());
  121 + array_push($fieldsets, new $displayClass($oFieldset));
  122 + }
  123 +
  124 + // Implement an electronic signature for accessing the admin section, it will appear every 10 minutes
  125 + global $default;
  126 + $iFolderId = $this->oFolder->getId();
  127 + if($default->enableESignatures){
  128 + $sUrl = KTPluginUtil::getPluginPath('electronic.signatures.plugin', true);
  129 + $heading = _kt('You are attempting to perform a bulk upload');
  130 + $submit['type'] = 'button';
  131 + $submit['onclick'] = "javascript: showSignatureForm('{$sUrl}', '{$heading}', 'ktcore.transactions.bulk_upload', 'bulk', 'bulk_upload_form', 'submit', {$iFolderId});";
  132 + }else{
  133 + $submit['type'] = 'submit';
  134 + $submit['onclick'] = '';
  135 + }
  136 +
  137 + $oTemplate->setData(array(
  138 + 'context' => &$this,
  139 + 'submit' => $submit,
  140 + 'add_fields' => $add_fields,
  141 + 'generic_fieldsets' => $fieldsets,
  142 + ));
  143 + return $oTemplate->render();
  144 + }
  145 + /**
  146 + * make uploads
  147 + * @return
  148 + *
  149 + * iNET Process
  150 + */
  151 + function do_upload() {
  152 + set_time_limit(0);
  153 + $aErrorOptions = array(
  154 + 'redirect_to' => array('main', sprintf('fFolderId=%d', $this->oFolder->getId())),
  155 + );
  156 +
  157 + $aErrorOptions['message'] = _kt('Invalid document type provided');
  158 + $oDocumentType = $this->oValidator->validateDocumentType($_REQUEST['fDocumentTypeId'], $aErrorOptions);
  159 +
  160 + unset($aErrorOptions['message']);
  161 + $aFile = $this->oValidator->validateFile($_FILES['file'], $aErrorOptions);
  162 +
  163 + $matches = array();
  164 + $aFields = array();
  165 + foreach ($_REQUEST as $k => $v) {
  166 + if (preg_match('/^metadata_(\d+)$/', $k, $matches)) {
  167 + // multiselect change start
  168 + $oDocField = DocumentField::get($matches[1]);
  169 + if(KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin') && $oDocField->getHasInetLookup() && is_array($v))
  170 + {
  171 + $v = join(", ", $v);
  172 + }
  173 + $aFields[] = array($oDocField, $v);
  174 +
  175 + // previously it was just one line which is commented, just above line
  176 + // multiselect change end
  177 + }
  178 + }
  179 +
  180 + $aOptions = array(
  181 + 'documenttype' => $oDocumentType,
  182 + 'metadata' => $aFields,
  183 + );
  184 +
  185 + $fs =& new KTZipImportStorage('file');
  186 + if(!$fs->CheckFormat()){
  187 + $sFormats = $fs->getFormats();
  188 + $this->addErrorMessage(_kt("Bulk Upload failed. Archive is not an accepted format. Accepted formats are: ".$sFormats));
  189 + controllerRedirect("browse", 'fFolderId=' . $this->oFolder->getID());
  190 + exit;
  191 + }
  192 +
  193 + if(KTPluginUtil::pluginIsActive('inet.foldermetadata.plugin'))
  194 + {
  195 + require_once(KT_DIR . "/plugins/foldermetadata/import/bulkimport.inc.php");
  196 + $bm =& new KTINETBulkImportManager($this->oFolder, $fs, $this->oUser, $aOptions);
  197 + }
  198 + else
  199 + {
  200 + $bm =& new KTBulkImportManager($this->oFolder, $fs, $this->oUser, $aOptions);
  201 + }
  202 +
  203 + $this->startTransaction();
  204 + $res = $bm->import();
  205 +
  206 + $aErrorOptions['message'] = _kt("Bulk Upload failed");
  207 + $this->oValidator->notError($res, $aErrorOptions);
  208 +
  209 + $this->addInfoMessage(_kt("Bulk Upload successful"));
  210 + $this->commitTransaction();
  211 + controllerRedirect("browse", 'fFolderId=' . $this->oFolder->getID());
  212 + exit(0);
  213 + }
  214 +}
  215 +?>
... ...
plugins/multiselect/InetWidgets.php 0 โ†’ 100644
  1 +<?php
  2 +/**
  3 + * $Id$
  4 + *
  5 + * KnowledgeTree Community Edition
  6 + * Document Management Made Simple
  7 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  8 + * Portions copyright The Jam Warehouse Software (Pty) Limited
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify it under
  11 + * the terms of the GNU General Public License version 3 as published by the
  12 + * Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but WITHOUT
  15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  17 + * details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  23 + * California 94120-7775, or email info@knowledgetree.com.
  24 + *
  25 + * The interactive user interfaces in modified source and object code versions
  26 + * of this program must display Appropriate Legal Notices, as required under
  27 + * Section 5 of the GNU General Public License version 3.
  28 + *
  29 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  30 + * these Appropriate Legal Notices must retain the display of the "Powered by
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
  35 + * Contributor( s): ______________________________________
  36 + *
  37 + */
  38 +
  39 +require_once(KT_LIB_DIR . '/widgets/fieldWidgets.php');
  40 +require_once(KT_LIB_DIR . '/widgets/basewidget.inc.php');
  41 +require_once(KT_LIB_DIR . '/templating/templating.inc.php');
  42 +require_once(KT_LIB_DIR . '/browse/DocumentCollection.inc.php');
  43 +
  44 +class InetMultiselectWidget extends KTBaseWidget
  45 +{
  46 + var $sTemplate = "multiselect/selection";
  47 +
  48 +
  49 + /**
  50 + * assign the class variables
  51 + * @return
  52 + * @param $sLabel Object
  53 + * @param $sDescription Object
  54 + * @param $sName Object
  55 + * @param $value Object
  56 + * @param $oPage Object
  57 + * @param $bRequired Object[optional]
  58 + * @param $sId Object[optional]
  59 + * @param $aErrors Object[optional]
  60 + * @param $aOptions Object[optional]
  61 + *
  62 + * iNET Process
  63 + */
  64 + function InetMultiselectWidget($sLabel, $sDescription, $sName, $value, &$oPage, $bRequired = false, $sId = null, $aErrors = null, $aOptions = null)
  65 + {
  66 + $this->sLabel = $sLabel;
  67 + $this->sDescription = $sDescription;
  68 + $this->sName = $sName;
  69 + $this->value = $value;
  70 + $this->oPage =& $oPage;
  71 + $this->bRequired = $bRequired;
  72 + $this->sId = $sId;
  73 + $this->aOptions = $aOptions;
  74 + $this->aErrors = $aErrors;
  75 +
  76 + if (is_null($this->aOptions)) { $this->aOptions = array(); }
  77 + // default to being a bit bigger.
  78 + $this->aOptions['width'] = KTUtil::arrayGet($this->aOptions, 'width', '45');
  79 + if($this->aOptions['lookup_type'] == "multiwithcheckboxes")
  80 + {
  81 + $this->sTemplate = "multiselect/simple_selection";
  82 + }
  83 +
  84 + }
  85 +
  86 +
  87 + /**
  88 + * returns the rendered templates
  89 + * @return
  90 + *
  91 + * iNET Process
  92 + */
  93 + function render() {
  94 + // very simple, general purpose passthrough. Chances are this is sufficient,
  95 + // just override the template being used.
  96 + $bHasErrors = false;
  97 + if (count($this->aErrors) != 0) { $bHasErrors = true; }
  98 +
  99 + $oTemplating =& KTTemplating::getSingleton();
  100 + $oTemplate = $oTemplating->loadTemplate($this->sTemplate);
  101 +
  102 + $aTemplateData = array(
  103 + "context" => $this,
  104 + "label" => $this->sLabel,
  105 + "description" => $this->sDescription,
  106 + "name" => $this->sName,
  107 + "required" => $this->bRequired,
  108 + "page" => $this->oPage,
  109 + "has_id" => ($this->sId !== null),
  110 + "id" => $this->sId,
  111 + "has_value" => ($this->value !== null),
  112 + "value" => $this->value,
  113 + "has_errors" => $bHasErrors,
  114 + "errors" => $this->aErrors,
  115 + "options" => $this->aOptions,
  116 + "vocab" => $this->aOptions['vocab'],
  117 + );
  118 + return $oTemplate->render($aTemplateData);
  119 + }
  120 +
  121 +
  122 + /**
  123 + * returns the selected lookup value
  124 + * @return
  125 + * @param $lookup Object
  126 + *
  127 + * iNET Process
  128 + */
  129 + function selected($lookup) {
  130 + if ($this->bMulti) {
  131 + return $this->_valuesearch[$lookup];
  132 + } else {
  133 + return ($this->value == $lookup);
  134 + }
  135 + }
  136 +
  137 + /**
  138 + *
  139 + * @return array
  140 + * @param $raw_data array
  141 + *
  142 + * iNET Process
  143 + */
  144 + function process($raw_data) {
  145 + return array($this->sBasename => $raw_data[$this->sBasename]);
  146 + }
  147 +}
  148 +
  149 +?>
0 150 \ No newline at end of file
... ...
plugins/multiselect/InetdocumentFieldsv2.php 0 โ†’ 100644
  1 +<?php
  2 +/**
  3 + * $Id$
  4 + *
  5 + * KnowledgeTree Community Edition
  6 + * Document Management Made Simple
  7 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  8 + * Portions copyright The Jam Warehouse Software (Pty) Limited
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify it under
  11 + * the terms of the GNU General Public License version 3 as published by the
  12 + * Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but WITHOUT
  15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  17 + * details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  23 + * California 94120-7775, or email info@knowledgetree.com.
  24 + *
  25 + * The interactive user interfaces in modified source and object code versions
  26 + * of this program must display Appropriate Legal Notices, as required under
  27 + * Section 5 of the GNU General Public License version 3.
  28 + *
  29 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  30 + * these Appropriate Legal Notices must retain the display of the "Powered by
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
  35 + * Contributor( s): ______________________________________
  36 + *
  37 + */
  38 +
  39 +require_once(KT_LIB_DIR . '/dispatcher.inc.php');
  40 +require_once(KT_LIB_DIR . '/metadata/fieldset.inc.php');
  41 +require_once(KT_LIB_DIR . '/widgets/forms.inc.php');
  42 +require_once(KT_LIB_DIR . '/plugins/pluginutil.inc.php');
  43 +
  44 +class InetDocumentFieldDispatcher extends KTAdminDispatcher {
  45 + var $bAutomaticTransaction = true;
  46 + var $bHaveConditional = null;
  47 + var $sHelpPage = 'ktcore/admin/document fieldsets.html';
  48 +
  49 + /**
  50 + *
  51 + * @return.
  52 + * @param.
  53 + *
  54 + * iNET Process
  55 + */
  56 + function predispatch() {
  57 + $this->aBreadcrumbs[] = array('url' => $_SERVER['PHP_SELF'], 'name' => _kt('Document Field Management'));
  58 + $this->persistParams(array('fFieldsetId'));
  59 +
  60 + $this->oFieldset = KTFieldset::get(KTUtil::arrayGet($_REQUEST, 'fFieldsetId'));
  61 + if (PEAR::isError($this->oFieldset)) {
  62 + $this->oFieldset = null;
  63 + unset($_REQUEST['fFieldset']); // prevent further attacks.
  64 + } else {
  65 + $this->aBreadcrumbs[] = array('url' => KTUtil::addQueryStringSelf($this->meldPersistQuery("","edit")), 'name' => $this->oFieldset->getName());
  66 + }
  67 + $this->bHaveConditional = KTPluginUtil::pluginIsActive('ktextra.conditionalmetadata.plugin');
  68 + }
  69 +
  70 + /**
  71 + * create template
  72 + * @Param.
  73 + * @return template.
  74 + *
  75 + * iNET Process
  76 + */
  77 + function do_main () {
  78 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/metadata/admin/list');
  79 +
  80 + $oTemplate->setData(array(
  81 + 'context' => $this,
  82 + 'fieldsets' => KTFieldset::getList("disabled != true AND namespace != 'tagcloud'"),
  83 + ));
  84 + return $oTemplate;
  85 + }
  86 +
  87 + /**
  88 + * form for creating new fieldset.
  89 + * @Param.
  90 + * @return form.
  91 + *
  92 + * iNET Process
  93 + */
  94 + function form_create() {
  95 + $oForm = new KTForm;
  96 + $oForm->setOptions(array(
  97 + 'identifier' => 'ktcore.fieldsets.create',
  98 + 'label' => _kt("Create New Fieldset"),
  99 + 'submit_label' => _kt('Create Fieldset'),
  100 + 'cancel_action' => 'main',
  101 + 'fail_action' => 'newfieldset',
  102 + 'action' => 'create',
  103 + 'context' => $this,
  104 + ));
  105 +
  106 +
  107 + // construct the widget set.
  108 + // we use a slight variation here, because "type" is only present in certain circumstances.
  109 + $widgets = array(
  110 + array('ktcore.widgets.string',array(
  111 + 'label' => _kt("Fieldset Name"),
  112 + 'name' => 'name',
  113 + 'required' => true,
  114 + 'description' => _kt("Each fieldset needs a unique name."),
  115 + )),
  116 + array('ktcore.widgets.text',array(
  117 + 'label' => _kt("Description"),
  118 + 'name' => 'description',
  119 + 'required' => true,
  120 + 'description' => _kt("In order to ensure that the data that users enter is useful, it is essential that you provide a good example."),
  121 + )),
  122 + );
  123 + if ($this->bHaveConditional) {
  124 +
  125 + // FIXME get this from some external source.
  126 + $type_vocab = array(
  127 + 'normal' => _kt("Normal"),
  128 + 'conditional' => _kt("Conditional"),
  129 + );
  130 +
  131 + $widgets[] = array('ktcore.widgets.selection', array(
  132 + 'label' => _kt("Fieldset Type"),
  133 + 'use_simple' => false,
  134 + 'description' => _kt("It is possibler to create different types of fieldsets. The most common kind is a \"normal\" fieldset, which can be configured to have different kinds of fields. The administrator may have installed additional plugins which provide different types of fieldsets."),
  135 + 'important_description' => _kt('Note that it is not possible to convert between different types of fieldsets, so please choose carefully.'),
  136 + 'name' => 'fieldset_type',
  137 + 'required' => true,
  138 + 'value' => 'normal',
  139 + 'vocab' => $type_vocab,
  140 + ));
  141 + }
  142 +
  143 + $widgets[] = array('ktcore.widgets.boolean',array(
  144 + 'label' => _kt("Generic"),
  145 + 'name' => 'generic',
  146 + 'description' => _kt("A generic fieldset is one that is available for every document by default. These fieldsets will be available for users to edit and add for every document in the document management system."),
  147 + ));
  148 +
  149 + $oForm->setWidgets($widgets);
  150 +
  151 + // similarly, we construct validators here.
  152 + $validators = array(
  153 + array('ktcore.validators.string', array(
  154 + 'test' => 'name',
  155 + 'output' => 'name',
  156 + )),
  157 + array('ktcore.validators.string', array(
  158 + 'test' => 'description',
  159 + 'output' => 'description',
  160 + )),
  161 + array('ktcore.validators.boolean', array(
  162 + 'test' => 'generic',
  163 + 'output' => 'generic',
  164 + )),
  165 + );
  166 +
  167 + if ($this->bHaveConditional) {
  168 + $validators[] = array('ktcore.validators.string', array(
  169 + 'test' => 'fieldset_type',
  170 + 'output' => 'fieldset_type',
  171 + ));
  172 + }
  173 +
  174 + $oForm->setValidators($validators);
  175 +
  176 + return $oForm;
  177 + }
  178 + /**
  179 + * Creates a new page
  180 + * @return form
  181 + *
  182 + * iNET Process
  183 + */
  184 + function do_newfieldset() {
  185 + $this->oPage->setBreadcrumbDetails(_kt("Create New Fieldset"));
  186 + $oForm = $this->form_create();
  187 +
  188 + return $oForm->render();
  189 + }
  190 + /**
  191 + * Creates a fieldsets
  192 + * @return
  193 + *
  194 + * iNET Process
  195 + */
  196 + function do_create() {
  197 + $oForm = $this->form_create();
  198 + $res = $oForm->validate();
  199 +
  200 + $data = $res['results'];
  201 + $errors = $res['errors'];
  202 + $extra_errors = array();
  203 +
  204 + if (!empty($data['name'])) {
  205 + $oFieldset = KTFieldset::getByName($data['name']);
  206 + if (!PEAR::isError($oFieldset)) {
  207 + // means we're looking at an existing name
  208 + $extra_errors['name'] = _kt("There is already a fieldset with that name.");
  209 + }
  210 + }
  211 +
  212 + $is_conditional = false;
  213 + // FIXME this is inelegant. get it from somewhere else.
  214 + if ($this->bHaveConditional && ($data['fieldset_type'] == 'conditional')) {
  215 + $is_conditional = true;
  216 + }
  217 +
  218 +
  219 + if (!empty($errors) || !empty($extra_errors)) {
  220 + return $oForm->handleError(null, $extra_errors);
  221 + }
  222 +
  223 + // we also need a namespace.
  224 + $temp_name = $data['name'];
  225 + $namespace = KTUtil::nameToLocalNamespace('fieldsets', $temp_name);
  226 + $oOldFieldset = KTFieldset::getByNamespace($namespace);
  227 +
  228 + while (!PEAR::isError($oOldFieldset)) {
  229 + $temp_name .= '_';
  230 + $namespace = KTUtil::nameToLocalNamespace('fieldsets', $temp_name);
  231 + $oOldFieldset = KTFieldset::getByNamespace($namespace);
  232 + }
  233 +
  234 + // we now know its a non-conflicting one.
  235 + // FIXME handle conditional fieldsets, which should be ... a different object.
  236 + $oFieldset = KTFieldset::createFromArray(array(
  237 + "name" => $data['name'],
  238 + "description" => $data['description'],
  239 + "namespace" => $namespace,
  240 + "mandatory" => false, // FIXME deprecated
  241 + "isConditional" => $is_conditional, // handle this
  242 + "isGeneric" => $data['generic'],
  243 + "isComplete" => false,
  244 + "isComplex" => false,
  245 + "isSystem" => false,
  246 + ));
  247 + if (PEAR::isError($oFieldset)) {
  248 + return $oForm->handleError(sprintf(_kt("Failed to create fieldset: %s"), $oFieldset->getMessage()));
  249 + }
  250 +
  251 + $this->successRedirectTo('edit',_kt("Fieldset created."), sprintf('fFieldsetId=%d', $oFieldset->getId()));
  252 + }
  253 + /**
  254 + * Gets tyoes for fieldsets
  255 + * @return string
  256 + * @param $oFieldset Object
  257 + *
  258 + * iNET Process
  259 + */
  260 + function getTypesForFieldset($oFieldset) {
  261 + global $default;
  262 + if ($oFieldset->getIsGeneric()) {
  263 + return _kt('All types use this generic fieldset.');
  264 + }
  265 +
  266 + $types = $oFieldset->getAssociatedTypes();
  267 + if (PEAR::isError($types)) {
  268 + $default->log->debug('Fieldsets admin: Error retrieving list of associated document types.');
  269 + return _kt('Error retrieving list of types.');
  270 + }
  271 + if (empty($types)) {
  272 + return _kt('None');
  273 + }
  274 +
  275 + $aNames = array();
  276 + foreach ($types as $oType) {
  277 + if (!PEAR::isError($oType)) {
  278 + $aNames[] = $oType->getName();
  279 + }else{
  280 + $default->log->debug('Fieldsets admin: Document type gives error: '.$oType->getMessage());
  281 + }
  282 + }
  283 +
  284 + $list = implode(', ', $aNames);
  285 + $length = mb_strlen($list);
  286 +
  287 + if($length < 50){
  288 + return $list;
  289 + }
  290 + $default->log->debug('Fieldsets admin: wrapping the list of doc types from length '.$length);
  291 +
  292 + // Wrap the list to 50 characters per line
  293 + $wrapList = '';
  294 + $cut = 0;
  295 + while ($length > 50 && $cut !== false){
  296 + $cut = strpos($list, ' ', 50);
  297 + $wrapList .= mb_strcut($list, 0, $cut);
  298 + $wrapList .= '<br />';
  299 + $list = mb_strcut($list, $cut);
  300 + $length = mb_strlen($list);
  301 + }
  302 + $wrapList .= $list;
  303 +
  304 + return $wrapList;
  305 + }
  306 +
  307 + /**
  308 + * Edits fields
  309 + * @return template
  310 + *
  311 + * iNET Process
  312 + */
  313 + function do_edit() {
  314 +
  315 + // here we engage in some major evil.
  316 + // we check for the subevent var
  317 + // and subdispatch if appropriate.
  318 + //
  319 + // saves a little code-duplication (actually, a lot of code-duplication)
  320 +
  321 + // FIXME this is essentially a stub for the fieldset-delegation code.
  322 + if ($this->oFieldset->getIsConditional()) {
  323 +
  324 + require_once(KT_DIR.'/plugins/ktcore/admin/fieldsets/conditional.inc.php');
  325 + $oSubDispatcher = new ConditionalFieldsetManagementDispatcher;
  326 + } else {
  327 + // multiselect change start
  328 + if(KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin'))
  329 + {
  330 + require_once(KT_DIR.'/plugins/multiselect/inetbasic.inc.php');
  331 + $oSubDispatcher = new InetBasicFieldsetManagementDispatcher;
  332 + }
  333 + else
  334 + {
  335 +
  336 + require_once(KT_DIR.'/plugins/ktcore/admin/fieldsets/basic.inc.php');
  337 + $oSubDispatcher = new BasicFieldsetManagementDispatcher;
  338 + }
  339 + // multiselect change end
  340 +
  341 +
  342 + }
  343 +
  344 + $subevent_var = 'fieldset_action';
  345 + $subevent = KTUtil::arrayGet($_REQUEST, $subevent_var);
  346 + if (!empty($subevent)) {
  347 + // do nothing, since this will handle everything
  348 + $this_url = KTUtil::addQueryStringSelf($this->meldPersistQuery("","edit"));
  349 + $oSubDispatcher->redispatch($subevent_var, null, $this, $this_url);
  350 + exit(0);
  351 + } else {
  352 + // what we want is the "additional info" section
  353 + $additional = $oSubDispatcher->describe_fieldset($this->oFieldset);
  354 + }
  355 +
  356 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/metadata/admin/edit');
  357 + $oTemplate->setData(array(
  358 + 'context' => $this,
  359 + 'fieldset_name' => $this->oFieldset->getName(),
  360 + 'additional' => $additional,
  361 + ));
  362 + return $oTemplate->render();
  363 + }
  364 + /**
  365 + * deletes field
  366 + * @return
  367 + *
  368 + * iNET Process
  369 + */
  370 + function do_delete() {
  371 + $this->startTransaction();
  372 +
  373 + // check if fieldset is associated with a document type - remove association
  374 + $types = $this->oFieldset->getAssociatedTypes();
  375 + $sFieldSetId = $this->oFieldset->getId();
  376 + if(!PEAR::isError($types) AND !empty($types)){
  377 + foreach($types as $oType){
  378 + $res = KTMetadataUtil::removeSetsFromDocumentType($oType, $sFieldSetId);
  379 + }
  380 + }
  381 +
  382 + $res = $this->oFieldset->delete('true');
  383 + $this->oValidator->notErrorFalse($res, array(
  384 + 'redirect_to' => array('main', ''),
  385 + 'message' => _kt('Could not delete fieldset'),
  386 + ));
  387 + $this->successRedirectToMain(_kt('Fieldset deleted'));
  388 + }
  389 + /**
  390 + * Form for edit
  391 + * @return form
  392 + *
  393 + * iNET Process
  394 + */
  395 + function form_edit() {
  396 + $oForm = new KTForm;
  397 + $oForm->setOptions(array(
  398 + 'identifier' => 'ktcore.fieldsets.edit',
  399 + 'label' => _kt("Change Fieldset Details"),
  400 + 'submit_label' => _kt('Update Fieldset'),
  401 + 'cancel_action' => 'edit',
  402 + 'fail_action' => 'editfieldset',
  403 + 'action' => 'savefieldset',
  404 + 'context' => $this,
  405 + ));
  406 +
  407 +
  408 + // construct the widget set.
  409 + // we use a slight variation here, because "type" is only present in certain circumstances.
  410 + $widgets = array(
  411 + array('ktcore.widgets.string',array(
  412 + 'label' => _kt("Fieldset Name"),
  413 + 'name' => 'name',
  414 + 'required' => true,
  415 + 'description' => _kt("Each fieldset needs a unique name."),
  416 + 'value' => sanitizeForHTML($this->oFieldset->getName()),
  417 + )),
  418 + array('ktcore.widgets.text',array(
  419 + 'label' => _kt("Description"),
  420 + 'name' => 'description',
  421 + 'required' => true,
  422 + 'description' => _kt("In order to ensure that the data that users enter is useful, it is essential that you provide a good example."),
  423 + 'value' => sanitizeForHTML($this->oFieldset->getDescription()),
  424 + )),
  425 + );
  426 +
  427 + $widgets[] = array('ktcore.widgets.boolean',array(
  428 + 'label' => _kt("Generic"),
  429 + 'name' => 'generic',
  430 + 'description' => _kt("A generic fieldset is one that is available for every document by default. These fieldsets will be available for users to edit and add for every document in the document management system."),
  431 + 'value' => $this->oFieldset->getIsGeneric(),
  432 + ));
  433 +
  434 + $oForm->setWidgets($widgets);
  435 +
  436 + // similarly, we construct validators here.
  437 + $validators = array(
  438 + array('ktcore.validators.string', array(
  439 + 'test' => 'name',
  440 + 'output' => 'name',
  441 + )),
  442 + array('ktcore.validators.string', array(
  443 + 'test' => 'description',
  444 + 'output' => 'description',
  445 + )),
  446 + array('ktcore.validators.boolean', array(
  447 + 'test' => 'generic',
  448 + 'output' => 'generic',
  449 + )),
  450 + );
  451 +
  452 + $oForm->setValidators($validators);
  453 +
  454 + return $oForm;
  455 + }
  456 + /**
  457 + * Edits a fieldsets
  458 + * @return form
  459 + *
  460 + * iNET Process
  461 + */
  462 + function do_editfieldset() {
  463 + $oForm = $this->form_edit();
  464 + $this->oPage->setBreadcrumbDetails(_kt('edit fieldset'));
  465 + return $oForm->renderPage(_kt("Edit Fieldset"));
  466 + }
  467 + /**
  468 + * saves a fieldset
  469 + * @return
  470 + *
  471 + * iNET Process
  472 + */
  473 + function do_savefieldset() {
  474 + $oForm = $this->form_edit();
  475 + $res = $oForm->validate();
  476 +
  477 + $data = $res['results'];
  478 + $errors = $res['errors'];
  479 + $extra_errors = array();
  480 + if ($data['name'] != $this->oFieldset->getName()) {
  481 + $oOldFieldset = KTFieldset::getByName($data['name']);
  482 + if (!PEAR::isError($oOldFieldset)) {
  483 + $extra_errors['name'][] = _kt("A fieldset with that name already exists.");
  484 + }
  485 + }
  486 +
  487 + if (!empty($errors) || !empty($extra_errors)) {
  488 + return $oForm->handleError(null, $extra_errors);
  489 + }
  490 +
  491 + $this->startTransaction();
  492 +
  493 + $this->oFieldset->setName($data['name']);
  494 + $this->oFieldset->setDescription($data['description']);
  495 + $bGeneric = $data['generic'];
  496 + if ($bGeneric != $this->oFieldset->getIsGeneric() && $bGeneric == true) {
  497 + // delink it from all doctypes.
  498 + $aTypes = $this->oFieldset->getAssociatedTypes();
  499 + foreach ($aTypes as $oType) {
  500 + $res = KTMetadataUtil::removeSetsFromDocumentType($oType, $this->oFieldset->getId());
  501 + if (PEAR::isError($res)) {
  502 + $this->errorRedirectTo('edit', _kt('Could not save fieldset changes'));
  503 + exit(0);
  504 + }
  505 + }
  506 + }
  507 +
  508 + $this->oFieldset->setIsGeneric($data['generic']);
  509 +
  510 + $res = $this->oFieldset->update();
  511 + if (PEAR::isError($res)) {
  512 + $this->errorRedirectTo('edit', _kt('Could not save fieldset changes'));
  513 + exit(0);
  514 + }
  515 +
  516 + return $this->successRedirectTo('edit', _kt("Fieldset details updated."));
  517 + }
  518 +}
  519 +
  520 +?>
0 521 \ No newline at end of file
... ...
plugins/multiselect/MultiSelectPlugin.php 0 โ†’ 100644
  1 +<?php
  2 +/**
  3 + * $Id$
  4 + *
  5 + * KnowledgeTree Community Edition
  6 + * Document Management Made Simple
  7 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  8 + * Portions copyright The Jam Warehouse Software (Pty) Limited
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify it under
  11 + * the terms of the GNU General Public License version 3 as published by the
  12 + * Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but WITHOUT
  15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  17 + * details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  23 + * California 94120-7775, or email info@knowledgetree.com.
  24 + *
  25 + * The interactive user interfaces in modified source and object code versions
  26 + * of this program must display Appropriate Legal Notices, as required under
  27 + * Section 5 of the GNU General Public License version 3.
  28 + *
  29 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  30 + * these Appropriate Legal Notices must retain the display of the "Powered by
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
  35 + * Contributor( s): ______________________________________
  36 + *
  37 + */
  38 +
  39 +require_once(KT_LIB_DIR . '/plugins/plugin.inc.php');
  40 +require_once(KT_LIB_DIR . '/plugins/pluginregistry.inc.php');
  41 +
  42 +class MultiSelectPlugin extends KTPlugin {
  43 + var $sNamespace = "inet.multiselect.lookupvalue.plugin";
  44 + var $autoRegister = false;
  45 +
  46 + /**
  47 + * returns plugin name
  48 + * @param string.
  49 + * @return string.
  50 + *
  51 + * iNET Process
  52 + */
  53 + function MultiSelectPlugin($sFilename = null) {
  54 + $res = parent::KTPlugin($sFilename);
  55 + $this->sFriendlyName = _kt('Multi-select Plugin');
  56 + return $res;
  57 + }
  58 +
  59 + /**
  60 + * Register the action, location, call adminsetup function and sql function
  61 + * iNET Process
  62 + */
  63 + function setup() {
  64 + $oTemplating =& KTTemplating::getSingleton();
  65 + $oTemplating->addLocation('Multiselect in metadata Part {lookup Value}', '/plugins/multiselect/templates');
  66 +
  67 + $dir = dirname(__FILE__);
  68 + $this->applySQL(realpath($dir . '/sql/script.sql'));
  69 +
  70 + //For adding documents
  71 + $this->registerAction('folderaction', 'MultiDocumentAddAction', 'inet.multiselect.actions.document.addDocument', 'addDocument.php');
  72 +
  73 + //For bulk upload
  74 + $this->registerAction('folderaction', 'InetBulkUploadFolderAction', 'inet.actions.folder.bulkUpload', 'BulkUpload.php');
  75 + /**
  76 + * Change Starts | iNET Process
  77 + * Code is Added 2009-03-04 :SL
  78 + * Reason : To Register "import from folder location" action for multiselect
  79 + */
  80 + $this->registerAction('folderaction', 'InetBulkImportFolderMultiSelectAction', 'inet.actions.folder.bulkImport.multiselect', 'BulkImport.php');
  81 + /**
  82 + * Change Ends | iNET Process
  83 + */
  84 + $this->setupAdmin();
  85 + }
  86 + /**
  87 + * applies queries to the database
  88 + * @return
  89 + * @param $filename Object
  90 + */
  91 + function applySQL($filename)
  92 + {
  93 + global $default;
  94 + DBUtil::setupAdminDatabase();
  95 + $db = $default->_admindb;
  96 +
  97 + $content = file_get_contents($filename);
  98 + $aQueries = SQLFile::splitSQL($content);
  99 +
  100 + DBUtil::startTransaction();
  101 + foreach($aQueries as $sQuery)
  102 + {
  103 + $res = DBUtil::runQuery($sQuery, $db);
  104 + if (PEAR::isError($res)) {
  105 + continue;
  106 + }
  107 + }
  108 + DBUtil::commit();
  109 + }
  110 + /**
  111 + * Sets up an admin
  112 + * @return
  113 + */
  114 + function setupAdmin()
  115 + {
  116 + $js = "<script src='plugins/multiselect/js/jquery-1.2.6.js' type='text/javascript'></script>";
  117 + $js .= "<script src='plugins/multiselect/js/hideadminlink.js' type='text/javascript'></script>";
  118 + $this->registerAdminPage('ratpfieldset', 'InetDocumentFieldDispatcher', 'documents',
  119 + $js._kt('Document Fieldsets'),
  120 + _kt('Manage the different types of information with multiselect functionality that can be associated with classes of documents.'),
  121 + 'InetdocumentFieldsv2.php', null);
  122 + }
  123 +}
  124 +$oPluginRegistry =& KTPluginRegistry::getSingleton();
  125 +$oPluginRegistry->registerPlugin('MultiSelectPlugin', 'inet.multiselect.lookupvalue.plugin', __FILE__);
  126 +?>
0 127 \ No newline at end of file
... ...
plugins/multiselect/addDocument.php 0 โ†’ 100644
  1 +<?php
  2 +/**
  3 + * $Id$
  4 + *
  5 + * KnowledgeTree Community Edition
  6 + * Document Management Made Simple
  7 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  8 + * Portions copyright The Jam Warehouse Software (Pty) Limited
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify it under
  11 + * the terms of the GNU General Public License version 3 as published by the
  12 + * Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but WITHOUT
  15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  17 + * details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  23 + * California 94120-7775, or email info@knowledgetree.com.
  24 + *
  25 + * The interactive user interfaces in modified source and object code versions
  26 + * of this program must display Appropriate Legal Notices, as required under
  27 + * Section 5 of the GNU General Public License version 3.
  28 + *
  29 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  30 + * these Appropriate Legal Notices must retain the display of the "Powered by
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
  35 + * Contributor( s): ______________________________________
  36 + *
  37 + */
  38 +
  39 +/* The file adds a document with multiselect fields.The main code for fetching multiselect
  40 + * fields is written in this file.
  41 + */
  42 +
  43 +require_once(KT_LIB_DIR . '/actions/folderaction.inc.php');
  44 +require_once(KT_LIB_DIR . "/widgets/fieldsetDisplay.inc.php");
  45 +require_once(KT_LIB_DIR . "/widgets/FieldsetDisplayRegistry.inc.php");
  46 +require_once(KT_LIB_DIR . "/foldermanagement/folderutil.inc.php");
  47 +require_once(KT_LIB_DIR . "/documentmanagement/observers.inc.php");
  48 +require_once(KT_LIB_DIR . "/documentmanagement/documentutil.inc.php");
  49 +require_once(KT_LIB_DIR . "/metadata/fieldsetregistry.inc.php");
  50 +require_once(KT_LIB_DIR . "/util/sanitize.inc");
  51 +
  52 +class MultiDocumentAddAction extends KTFolderAction {
  53 + var $sName = 'inet.multiselect.actions.document.addDocument';
  54 + var $_sShowPermission = "ktcore.permissions.write";
  55 + var $oDocumentType = null;
  56 +
  57 + /**
  58 + * returns a display name 'Add Document'
  59 + * @return
  60 + *
  61 + * iNET Process
  62 + */
  63 + function getDisplayName() {
  64 + return _kt('Add Document');
  65 + }
  66 +
  67 + /**
  68 + * get the button
  69 + * @return
  70 + *
  71 + * iNET Process
  72 + */
  73 + function getButton(){
  74 + $btn = array();
  75 + $btn['display_text'] = _kt('Upload Document');
  76 + $btn['arrow_class'] = 'arrow_upload';
  77 + return $btn;
  78 + }
  79 + /**
  80 + * check if document can be added or not
  81 + * @return
  82 + *
  83 + * iNET Process
  84 + */
  85 + function check() {
  86 + $res = parent::check();
  87 + if (empty($res)) {
  88 + return $res;
  89 + }
  90 +
  91 + $postExpected = KTUtil::arrayGet($_REQUEST, "postExpected");
  92 + $postReceived = KTUtil::arrayGet($_REQUEST, "postReceived");
  93 + if (!empty($postExpected)) {
  94 + $aErrorOptions = array(
  95 + 'redirect_to' => array('main', sprintf('fFolderId=%d', $this->oFolder->getId())),
  96 + 'message' => _kt('Upload larger than maximum POST size (post_max_size variable in .htaccess or php.ini)'),
  97 + );
  98 + $this->oValidator->notEmpty($postReceived, $aErrorOptions);
  99 + }
  100 + return true;
  101 + }
  102 + /**
  103 + * Initializes for data
  104 + * @return
  105 + *
  106 + * iNET Process
  107 + */
  108 + function form_initialdata() {
  109 + $oForm = new KTForm;
  110 +
  111 + $oForm->setOptions(array(
  112 + 'label' => _kt("Add a document"),
  113 + 'action' => 'processInitialData',
  114 + 'actionparams' => 'postExpected=1&fFolderId='.$this->oFolder->getId(),
  115 + // 'cancel_action' => KTBrowseUtil::getUrlForFolder($this->oFolder),
  116 + 'fail_action' => 'main',
  117 + 'context' => &$this,
  118 + 'extraargs' => $this->meldPersistQuery("","",true),
  119 + 'submit_label' => _kt("Add"),
  120 + 'file_upload' => true,
  121 + ));
  122 +
  123 + $aTypes = array();
  124 + foreach (DocumentType::getListForUserAndFolder($this->oUser, $this->oFolder) as $oDocumentType) {
  125 + if(!$oDocumentType->getDisabled()) {
  126 + $aTypes[] = $oDocumentType;
  127 + }
  128 + }
  129 +
  130 + // Onchange gets the name of the file and inserts it as the document title.
  131 + $sFileOnchange = "javascript:
  132 + var doc = document.getElementById('document_name');
  133 + if(doc.value == ''){
  134 + var arrPath=this.value.split('/');
  135 + if(arrPath.length == 1){
  136 + var arrPath=this.value.split('\\\');
  137 + }
  138 + var name=arrPath[arrPath.length-1];
  139 + var name=name.split('.');
  140 + var len = name.length;
  141 + if(len > 1){
  142 + if(name[len-1].length <= 4){
  143 + name.pop();
  144 + }
  145 + }
  146 + var title=name.join('.');
  147 + doc.value=title;
  148 + }";
  149 +
  150 + $oForm->setWidgets(array(
  151 + array('ktcore.widgets.file',array(
  152 + 'label' => _kt('File'),
  153 + 'description' => _kt('The contents of the document to be added to the document management system.'),
  154 + 'name' => 'file',
  155 + 'required' => true,
  156 + 'onchange' => $sFileOnchange,
  157 + )),
  158 + array('ktcore.widgets.string',array(
  159 + 'label' => _kt('Document Title'),
  160 + 'description' => sprintf(_kt('The document title is used as the main name of a document throughout %s.'), APP_NAME),
  161 + 'name' => 'document_name',
  162 + 'required' => true,
  163 + 'id' => 'document_name',
  164 + )),
  165 + array('ktcore.widgets.entityselection',array(
  166 + 'label' => _kt('Document Type'),
  167 + 'description' => _kt('Document Types, defined by the administrator, are used to categorise documents. Please select a Document Type from the list below.'),
  168 + 'name' => 'document_type',
  169 + 'required' => true,
  170 + 'vocab' => $aTypes,
  171 + 'initial_string' => _kt('- Please select a document type -'),
  172 + 'id_method' => 'getId',
  173 + 'label_method' => 'getName',
  174 + 'simple_select' => false,
  175 + )),
  176 + ));
  177 +
  178 + // Electronic Signature if enabled
  179 + global $default;
  180 + if($default->enableESignatures){
  181 + $oForm->addWidget(array('ktcore.widgets.info', array(
  182 + 'label' => _kt('This action requires authentication'),
  183 + 'description' => _kt('Please provide your user credentials as confirmation of this action.'),
  184 + 'name' => 'info'
  185 + )));
  186 + $oForm->addWidget(array('ktcore.widgets.string', array(
  187 + 'label' => _kt('Username'),
  188 + 'name' => 'sign_username',
  189 + 'required' => true
  190 + )));
  191 + $oForm->addWidget(array('ktcore.widgets.password', array(
  192 + 'label' => _kt('Password'),
  193 + 'name' => 'sign_password',
  194 + 'required' => true
  195 + )));
  196 + $oForm->addWidget(array('ktcore.widgets.reason', array(
  197 + 'label' => _kt('Reason'),
  198 + 'description' => _kt('Please specify why you are checking out this document. It will assist other users in understanding why you have locked this file. Please bear in mind that you can use a maximum of <strong>250</strong> characters.'),
  199 + 'name' => 'reason',
  200 + )));
  201 + }
  202 +
  203 + $oForm->setValidators(array(
  204 + array('ktcore.validators.file', array(
  205 + 'test' => 'file',
  206 + 'output' => 'file',
  207 + )),
  208 + array('ktcore.validators.fileillegalchar', array(
  209 + 'test' => 'file',
  210 + 'output' => 'file',
  211 + )),
  212 + array('ktcore.validators.string', array(
  213 + 'test' => 'document_name',
  214 + 'output' => 'document_name',
  215 + )),
  216 + array('ktcore.validators.entity', array(
  217 + 'test' => 'document_type',
  218 + 'output' => 'document_type',
  219 + 'class' => 'DocumentType',
  220 + 'ids' => true,
  221 + )),
  222 + ));
  223 +
  224 + if($default->enableESignatures){
  225 + $oForm->addValidator(array('electonic.signatures.validators.authenticate', array(
  226 + 'object_id' => $this->oFolder->getId(),
  227 + 'type' => 'folder',
  228 + 'action' => 'ktcore.transactions.add_document',
  229 + 'test' => 'info',
  230 + 'output' => 'info'
  231 + )));
  232 + }
  233 +
  234 + return $oForm;
  235 + }
  236 + /**
  237 + * Get the fieldsets for a particular document type
  238 + * @return array
  239 + * @param $iTypeId Object
  240 + *
  241 + * iNET Process
  242 + */
  243 + function getFieldsetsForType($iTypeId) {
  244 + $typeid = KTUtil::getId($iTypeId);
  245 + $aGenericFieldsetIds = KTFieldset::getGenericFieldsets(array('ids' => false));
  246 + $aSpecificFieldsetIds = KTFieldset::getForDocumentType($typeid, array('ids' => false));
  247 +
  248 + $fieldsets = kt_array_merge($aGenericFieldsetIds, $aSpecificFieldsetIds);
  249 + return $fieldsets;
  250 + }
  251 + /**
  252 + * Main default function
  253 + * @param
  254 + * @return form
  255 + * iNET Process
  256 + */
  257 + function do_main() {
  258 + $this->oPage->setBreadcrumbDetails(_kt("Add a document"));
  259 + $oForm = $this->form_initialdata();
  260 + return $oForm->renderPage(_kt('Add a document to: ') . $this->oFolder->getName());
  261 + }
  262 + /**
  263 + * Checks for validations and errors
  264 + * @return
  265 + *
  266 + * iNET Process
  267 + */
  268 + function do_processInitialData() {
  269 + $oForm = $this->form_initialdata();
  270 + $res = $oForm->validate();
  271 + if (!empty($res['errors'])) {
  272 + if(!isset($res['errors']['file'])){
  273 + $aError['file'] = array(_kt('Please reselect the file to upload.'));
  274 + }
  275 + return $oForm->handleError('', $aError);
  276 + }
  277 + $data = $res['results'];
  278 + $key = KTUtil::randomString(32);
  279 +
  280 +
  281 + // joy joy, we need to store the file first, or PHP will (helpfully)
  282 + // clean it up for us
  283 +
  284 + $oKTConfig =& KTConfig::getSingleton();
  285 + $sBasedir = $oKTConfig->get("urls/tmpDirectory");
  286 +
  287 + $sFilename = tempnam($sBasedir, 'kt_storecontents');
  288 +
  289 + //$oContents = new KTFSFileLike($data['file']['tmp_name']);
  290 + //$oOutputFile = new KTFSFileLike($sFilename);
  291 + //$res = KTFileLikeUtil::copy_contents($oContents, $oOutputFile);
  292 +
  293 + //if (PEAR::isError($res)) {
  294 + // $oForm->handleError(sprintf(_kt("Failed to store file: %s"), $res->getMessage()));
  295 + //}
  296 +
  297 +
  298 + $oStorage =& KTStorageManagerUtil::getSingleton();
  299 + $oStorage->uploadTmpFile($data['file']['tmp_name'], $sFilename);
  300 +
  301 + $data['file']['tmp_name'] = $sFilename;
  302 + $_SESSION['_add_data'] = array($key => $data);
  303 +
  304 + // if we don't need metadata
  305 + $fieldsets = $this->getFieldsetsForType($data['document_type']);
  306 + if (empty($fieldsets)) {
  307 + return $this->successRedirectTo('finalise', _kt("File uploaded successfully. Processing."), sprintf("fFileKey=%s", $key));
  308 + }
  309 +
  310 + // if we need metadata
  311 +
  312 + $this->successRedirectTo('metadata', _kt("File uploaded successfully. Please fill in the metadata below."), sprintf("fFileKey=%s", $key));
  313 + }
  314 + /**
  315 + * get the metadata
  316 + * @return form
  317 + * @param $sess_key Object
  318 + *
  319 + * iNET Process
  320 + */
  321 + function form_metadata($sess_key) {
  322 + $oForm = new KTForm;
  323 + $oForm->setOptions(array(
  324 + 'identifier' => 'ktcore.document.add',
  325 + 'label' => _kt('Specify Metadata'),
  326 + 'submit_label' => _kt('Save Document'),
  327 + 'action' => 'finalise',
  328 + 'fail_action' => 'metadata',
  329 + // 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument),
  330 + 'context' => &$this,
  331 + 'extraargs' => $this->meldPersistQuery("","",true),
  332 + ));
  333 +
  334 + $oFReg =& KTFieldsetRegistry::getSingleton();
  335 +
  336 + $doctypeid = $_SESSION['_add_data'][$sess_key]['document_type'];
  337 +
  338 + $widgets = array();
  339 + $validators = array();
  340 + $fieldsets = $this->getFieldsetsForType($doctypeid);
  341 +
  342 + foreach ($fieldsets as $oFieldset) {
  343 + $widgets = kt_array_merge($widgets, $oFReg->widgetsForFieldset($oFieldset, 'fieldset_' . $oFieldset->getId(), $this->oDocument));
  344 + $validators = kt_array_merge($validators, $oFReg->validatorsForFieldset($oFieldset, 'fieldset_' . $oFieldset->getId(), $this->oDocument));
  345 + }
  346 +
  347 + $oForm->setWidgets($widgets);
  348 + $oForm->setValidators($validators);
  349 +
  350 + return $oForm;
  351 + }
  352 + /**
  353 + * render metadata for a document
  354 + * @return form
  355 + *
  356 + * iNET Process
  357 + */
  358 + function do_metadata() {
  359 + $this->persistParams(array('fFileKey'));
  360 +
  361 + $oForm = $this->form_metadata($_REQUEST['fFileKey']);
  362 + return $oForm->render();
  363 + }
  364 + /**
  365 + * finally adds a document
  366 + * @return.
  367 + *
  368 + * iNET Process
  369 + */
  370 + function do_finalise() {
  371 + $this->persistParams(array('fFileKey'));
  372 + $sess_key = $_REQUEST['fFileKey'];
  373 + $oForm = $this->form_metadata($sess_key);
  374 + $res = $oForm->validate();
  375 + if (!empty($res['errors'])) {
  376 + return $oForm->handleError();
  377 + }
  378 + $data = $res['results'];
  379 +
  380 + $extra_d = $_SESSION['_add_data'][$sess_key];
  381 + $doctypeid = $extra_d['document_type'];
  382 + $aGenericFieldsetIds = KTFieldset::getGenericFieldsets(array('ids' => false));
  383 + $aSpecificFieldsetIds = KTFieldset::getForDocumentType($doctypeid, array('ids' => false));
  384 + $fieldsets = kt_array_merge($aGenericFieldsetIds, $aSpecificFieldsetIds);
  385 +
  386 +
  387 + $MDPack = array();
  388 + foreach ($fieldsets as $oFieldset) {
  389 + $fields = $oFieldset->getFields();
  390 + $values = (array) KTUtil::arrayGet($data, 'fieldset_' . $oFieldset->getId());
  391 +
  392 + foreach ($fields as $oField) {
  393 + $val = KTUtil::arrayGet($values, 'metadata_' . $oField->getId());
  394 + if ($oFieldset->getIsConditional())
  395 + {
  396 + if ($val == _kt('No selection.'))
  397 + {
  398 + $val = null;
  399 + }
  400 + }
  401 + // ALT.METADATA.LAYER.DIE.DIE.DIE
  402 + if (!is_null($val)) {
  403 + // multiselect change start
  404 + if(is_array($val) && $oField->getHasInetLookup())
  405 + {
  406 + $val = join(", ",$val);
  407 + }
  408 + // multiselect change end
  409 + $MDPack[] = array(
  410 + $oField,
  411 + $val
  412 + );
  413 + }
  414 +
  415 + }
  416 + }
  417 + // older code
  418 +
  419 + $mpo =& new JavascriptObserver($this);
  420 + $oUploadChannel =& KTUploadChannel::getSingleton();
  421 + $oUploadChannel->addObserver($mpo);
  422 +
  423 + require_once(KT_LIB_DIR . '/storage/storagemanager.inc.php');
  424 + //require_once(KT_LIB_DIR . '/filelike/fsfilelike.inc.php');
  425 + require_once(KT_LIB_DIR . '/documentmanagement/DocumentType.inc');
  426 + require_once(KT_LIB_DIR . '/metadata/fieldset.inc.php');
  427 + require_once(KT_LIB_DIR . '/documentmanagement/documentutil.inc.php');
  428 +
  429 + $aErrorOptions = array(
  430 + 'redirect_to' => array('main', sprintf('fFolderId=%d', $this->oFolder->getId())),
  431 + 'max_str_len' => 200,
  432 + );
  433 +
  434 + $aFile = $this->oValidator->validateFile($extra_d['file'], $aErrorOptions);
  435 + $sTitle = $extra_d['document_name'];
  436 +
  437 + $iFolderId = $this->oFolder->getId();
  438 + $aOptions = array(
  439 + // 'contents' => new KTFSFileLike($aFile['tmp_name']),
  440 + 'temp_file' => $aFile['tmp_name'],
  441 + 'documenttype' => DocumentType::get($extra_d['document_type']),
  442 + 'metadata' => $MDPack,
  443 + 'description' => $sTitle,
  444 + 'cleanup_initial_file' => true,
  445 + );
  446 +
  447 + $mpo->start();
  448 + //$this->startTransaction();
  449 + $oDocument =& KTDocumentUtil::add($this->oFolder, $aFile['name'], $this->oUser, $aOptions);
  450 + if (PEAR::isError($oDocument)) {
  451 + $message = $oDocument->getMessage();
  452 + $this->errorRedirectTo('main',sprintf(_kt("Unexpected failure to add document - %s"), $message), 'fFolderId=' . $this->oFolder->getId());
  453 + exit(0);
  454 + }
  455 + $this->addInfoMessage(_kt("Document added"));
  456 +
  457 + //$this->commitTransaction();
  458 + $mpo->redirectToDocument($oDocument->getId());
  459 + exit(0);
  460 +
  461 + }
  462 +
  463 +}
  464 +
  465 +?>
... ...
plugins/multiselect/inetbasic.inc.php 0 โ†’ 100644
  1 +<?php
  2 +/**
  3 + * $Id$
  4 + *
  5 + * KnowledgeTree Community Edition
  6 + * Document Management Made Simple
  7 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  8 + * Portions copyright The Jam Warehouse Software (Pty) Limited
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify it under
  11 + * the terms of the GNU General Public License version 3 as published by the
  12 + * Free Software Foundation.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but WITHOUT
  15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  17 + * details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  23 + * California 94120-7775, or email info@knowledgetree.com.
  24 + *
  25 + * The interactive user interfaces in modified source and object code versions
  26 + * of this program must display Appropriate Legal Notices, as required under
  27 + * Section 5 of the GNU General Public License version 3.
  28 + *
  29 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  30 + * these Appropriate Legal Notices must retain the display of the "Powered by
  31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  33 + * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * copyright notice.
  35 + * Contributor( s): ______________________________________
  36 + *
  37 + */
  38 +
  39 +require_once(KT_LIB_DIR . '/dispatcher.inc.php');
  40 +require_once(KT_LIB_DIR . '/metadata/fieldset.inc.php');
  41 +require_once(KT_LIB_DIR . '/widgets/forms.inc.php');
  42 +require_once(KT_LIB_DIR . '/plugins/pluginutil.inc.php');
  43 +require_once(KT_LIB_DIR . "/documentmanagement/MDTree.inc");
  44 +
  45 +class InetBasicFieldsetManagementDispatcher extends KTAdminDispatcher {
  46 + var $bAutomaticTransaction = true;
  47 + var $bHaveConditional = null;
  48 + var $sHelpPage = 'ktcore/admin/document fieldsets.html';
  49 +
  50 + /**
  51 + * @param.
  52 + * @return.
  53 + *
  54 + * iNET Process
  55 + */
  56 + function predispatch() {
  57 + $this->persistParams(array('fFieldId'));
  58 + $this->oFieldset = KTFieldset::get(KTUtil::arrayGet($_REQUEST, 'fFieldsetId'));
  59 + if (PEAR::isError($this->oFieldset)) {
  60 + $this->oFieldset = null;
  61 + unset($_REQUEST['fFieldsetId']); // prevent further attacks.
  62 + }
  63 + $this->oField = DocumentField::get(KTUtil::arrayGet($_REQUEST, 'fFieldId'));
  64 + if (PEAR::isError($this->oField)) {
  65 + $this->oField = null;
  66 + unset($_REQUEST['fFieldId']); // prevent further attacks.
  67 + } else {
  68 + $this->aBreadcrumbs[] = array('url' => KTUtil::addQueryStringSelf($this->meldPersistQuery("","managefield")), 'name' => $this->oField->getName());
  69 + }
  70 + }
  71 +
  72 + /**
  73 + * API: this provides information about the fieldset, including which actions are available.
  74 + *
  75 + * @param $oFieldset object.
  76 + * @return template.
  77 + *
  78 + * iNET Process
  79 + */
  80 + function describe_fieldset($oFieldset) {
  81 + $this->persistParams(array('fFieldsetId','action'));
  82 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/metadata/admin/basic_overview');
  83 + $oTemplate->setData(array(
  84 + 'context' => $this,
  85 + 'fields' => $oFieldset->getFields(),
  86 + ));
  87 + return $oTemplate->render();
  88 + }
  89 + /**
  90 + * Nothing doing
  91 + * iNET Process
  92 + */
  93 + function do_main () {
  94 + return _kt("Something very unexpected happened.");
  95 + }
  96 +
  97 + /**
  98 + * returns array of field type.
  99 + *
  100 + * @param.
  101 + * @return array.
  102 + *
  103 + * iNET Process
  104 + */
  105 + function getFieldTypeVocab() {
  106 + $types = array(
  107 + 'normal' => _kt("Normal (String)"),
  108 + 'lookup' => _kt("Lookup"),
  109 + 'tree' => _kt("Tree"),
  110 + 'Multiselect' => _kt("Multiselect"),
  111 + );
  112 + return $types;
  113 + }
  114 +
  115 +
  116 + /**
  117 + * multiselect change starts
  118 + * @return array
  119 + *
  120 + * iNET Process
  121 + */
  122 + function getLookupFieldTypeVocab() {
  123 + $types = array(
  124 +
  125 + 'multiwithlist' => _kt("Multiselect with a list"),
  126 + 'multiwithcheckboxes' => _kt("Multiselect with checkboxes"),
  127 + );
  128 + return $types;
  129 + }
  130 +
  131 + /**
  132 + * returns lookup type
  133 + * @return string
  134 + *
  135 + * iNET Process
  136 + */
  137 + function getDefaultLookupType() {
  138 + return 'multiwithlist';
  139 +
  140 + }
  141 +
  142 + /**
  143 + * multiselect change end
  144 + * @return
  145 + *
  146 + * iNET Process
  147 + */
  148 + function getDefaultType() {
  149 + return 'normal';
  150 + }
  151 + /**
  152 + * For for displaying new field
  153 + * @return
  154 + *
  155 + * iNET Process
  156 + */
  157 + function form_newfield() {
  158 + $this->oPage->setBreadcrumbDetails(_kt('add field'));
  159 +
  160 + $oForm = new KTForm;
  161 + $oForm->setOptions(array(
  162 + 'identifier' => 'ktcore.fieldsets.basic.field.create',
  163 + 'label' => _kt("Add New Field"),
  164 + 'submit_label' => _kt('Add Field'),
  165 + 'cancel_url' => $this->sParentUrl,
  166 + 'fail_action' => 'newfield',
  167 + 'action' => 'createfield',
  168 + 'context' => $this,
  169 + ));
  170 +
  171 + $type_vocab = $this->getFieldTypeVocab();
  172 +
  173 + $oForm->setWidgets(array(
  174 + array('ktcore.widgets.string',array(
  175 + 'label' => _kt("Field Name"),
  176 + 'name' => 'name',
  177 + 'required' => true,
  178 + 'description' => _kt("Within a given fieldset, each field needs a unique name."),
  179 + )),
  180 + array('ktcore.widgets.text',array(
  181 + 'label' => _kt("Description"),
  182 + 'name' => 'description',
  183 + 'required' => true,
  184 + 'description' => _kt("A good description can be the difference between useful metadata and poor metadata. At the same time, overly long descriptions are far less valuable than concise ones."),
  185 + )),
  186 + array('ktcore.widgets.selection', array(
  187 + 'label' => _kt('Field Type'),
  188 + 'name' => 'field_type',
  189 + 'vocab' => $this->getFieldTypeVocab(),
  190 + 'description' => _kt("Different types of fields may be available, depending on the system."),
  191 + 'required' => true,
  192 + 'value' => $this->getDefaultType(),
  193 + )),
  194 + array('ktcore.widgets.boolean',array(
  195 + 'label' => _kt("Required"),
  196 + 'name' => 'required',
  197 + 'description' => _kt("Required fields must be filled in, or the adding process will be rejected."),
  198 + )),
  199 +
  200 + ));
  201 +
  202 + $oForm->setValidators(array(
  203 + array('ktcore.validators.string', array(
  204 + 'test' => 'name',
  205 + 'output' => 'name',
  206 + )),
  207 + array('ktcore.validators.string', array(
  208 + 'test' => 'description',
  209 + 'output' => 'description',
  210 + )),
  211 + array('ktcore.validators.boolean', array(
  212 + 'test' => 'required',
  213 + 'output' => 'required',
  214 + )),
  215 + array('ktcore.validators.string', array(
  216 + 'test' => 'field_type',
  217 + 'output' => 'field_type',
  218 + )),
  219 + ));
  220 +
  221 + return $oForm;
  222 + }
  223 + /**
  224 + * Renders the page for new field
  225 + * @return
  226 + *
  227 + * iNET Process
  228 + */
  229 + function do_newfield() {
  230 + $oForm = $this->form_newfield();
  231 +
  232 + return $oForm->render();
  233 + }
  234 +
  235 + /**
  236 + * Creats a new field->multiselect
  237 + * @return
  238 + *
  239 + *
  240 + * iNET Process
  241 + */
  242 + function do_createfield() {
  243 + $oForm = $this->form_newfield();
  244 + $res = $oForm->validate();
  245 +
  246 + $data = $res['results'];
  247 + $errors = $res['errors'];
  248 + $extra_errors = array();
  249 +
  250 + $oField = DocumentField::getByFieldsetAndName($this->oFieldset, $data['name']);
  251 + if (!PEAR::isError($oField)) {
  252 + $extra_errors['name'] = _kt("A field with that name already exists in this fieldset.");
  253 + }
  254 +
  255 + if (!empty($errors) || !empty($extra_errors)) {
  256 + return $oForm->handleError(null, $extra_errors);
  257 + }
  258 +
  259 + $lookup = false;
  260 + $tree = false;
  261 + // multiselect change start
  262 + $inetlookup = false;
  263 + $inetlookupvalue = '';
  264 + // multiselect change end
  265 +
  266 + if ($data['field_type'] == 'lookup') {
  267 + $lookup = true;
  268 + } else if ($data['field_type'] == 'tree') {
  269 + $lookup = true;
  270 + $tree = true;
  271 + }
  272 + // multiselect change start
  273 + else if($data['field_type'] == 'Multiselect')
  274 + {
  275 + $inetlookup = true;
  276 + $inetlookupvalue = $this->getDefaultLookupType();
  277 + }
  278 + // multiselect change end
  279 +
  280 + $oField = DocumentField::createFromArray(array(
  281 + 'Name' => $data['name'],
  282 + 'Description' => $data['description'],
  283 + 'DataType' => 'STRING',
  284 + 'IsGeneric' => false,
  285 + 'HasLookup' => $lookup,
  286 + 'HasLookupTree' => $tree,
  287 + 'ParentFieldset' => $this->oFieldset->getId(),
  288 + 'IsMandatory' => $data['required'],
  289 + // multiselect change start
  290 + 'HasInetLookup' => $inetlookup,
  291 + 'InetLookupType' => $inetlookupvalue,
  292 + // multiselect change end
  293 + ));
  294 +
  295 + if (PEAR::isError($oField)) {
  296 + return $oForm->handleError(sprintf(_kt("Unable to create field: %s"), $oField->getMessage()));
  297 + }
  298 +
  299 + $this->successRedirectTo('managefield', _kt("Field created."), sprintf('fFieldId=%d', $oField->getId()));
  300 + }
  301 + /**
  302 + * Form for editing a field
  303 + * @return form
  304 + * @param $oField Object
  305 + *
  306 + * iNET Process
  307 + */
  308 + function form_editfield($oField) {
  309 + $oForm = new KTForm;
  310 + $oForm->setOptions(array(
  311 + 'identifier' => 'ktcore.fieldsets.basic.field.edit',
  312 + 'label' => _kt("Edit Field"),
  313 + 'submit_label' => _kt('Update Field'),
  314 + 'cancel_url' => $this->sParentUrl,
  315 + 'fail_action' => 'managefield',
  316 + 'action' => 'updatefield',
  317 + 'context' => $this,
  318 + ));
  319 +
  320 + $field_type = $oField->getType();
  321 + if($field_type == "Multiselect")
  322 + {
  323 + $oForm->setWidgets(array(
  324 + array('ktcore.widgets.string',array(
  325 + 'label' => _kt("Field Name"),
  326 + 'name' => 'name',
  327 + 'value' => sanitizeForHTML($oField->getName()),
  328 + 'required' => true,
  329 + 'description' => _kt("Within a given fieldset, each field needs a unique name."),
  330 + )),
  331 + array('ktcore.widgets.text',array(
  332 + 'label' => _kt("Description"),
  333 + 'name' => 'description',
  334 + 'value' => sanitizeForHTML($oField->getDescription()),
  335 + 'required' => true,
  336 + 'description' => _kt("A good description can be the difference between useful metadata and poor metadata. At the same time, overly long descriptions are far less valuable than concise ones."),
  337 + )),
  338 + array('ktcore.widgets.boolean',array(
  339 + 'label' => _kt("Required"),
  340 + 'value' => $oField->getIsMandatory(),
  341 + 'name' => 'required',
  342 + 'description' => _kt("Required fields must be filled in, or the adding process will be rejected."),
  343 + )),
  344 + array('ktcore.widgets.selection', array(
  345 + 'label' => _kt('Type of field'),
  346 + 'name' => 'inetlookup_type',
  347 + 'vocab' => $this->getLookupFieldTypeVocab(),
  348 + 'description' => _kt("Permits to create a multiselect or single select choices."),
  349 + 'required' => true,
  350 + 'value' => $oField->getInetLookupType(),
  351 + 'simple_select' => false,
  352 + )),
  353 + ));
  354 +
  355 + $oForm->setValidators(array(
  356 + array('ktcore.validators.string', array(
  357 + 'test' => 'name',
  358 + 'output' => 'name',
  359 + )),
  360 + array('ktcore.validators.string', array(
  361 + 'test' => 'description',
  362 + 'output' => 'description',
  363 + )),
  364 + array('ktcore.validators.boolean', array(
  365 + 'test' => 'required',
  366 + 'output' => 'required',
  367 + )),
  368 + array('ktcore.validators.string', array(
  369 + 'test' => 'inetlookup_type',
  370 + 'output' => 'inetlookup_type',
  371 + )),
  372 + ));
  373 + }
  374 + else
  375 + {
  376 +
  377 + $oForm->setWidgets(array(
  378 + array('ktcore.widgets.string',array(
  379 + 'label' => _kt("Field Name"),
  380 + 'name' => 'name',
  381 + 'value' => sanitizeForHTML($oField->getName()),
  382 + 'required' => true,
  383 + 'description' => _kt("Within a given fieldset, each field needs a unique name."),
  384 + )),
  385 + array('ktcore.widgets.text',array(
  386 + 'label' => _kt("Description"),
  387 + 'name' => 'description',
  388 + 'value' => sanitizeForHTML($oField->getDescription()),
  389 + 'required' => true,
  390 + 'description' => _kt("A good description can be the difference between useful metadata and poor metadata. At the same time, overly long descriptions are far less valuable than concise ones."),
  391 + )),
  392 + array('ktcore.widgets.boolean',array(
  393 + 'label' => _kt("Required"),
  394 + 'value' => $oField->getIsMandatory(),
  395 + 'name' => 'required',
  396 + 'description' => _kt("Required fields must be filled in, or the adding process will be rejected."),
  397 + )),
  398 +
  399 + ));
  400 +
  401 + $oForm->setValidators(array(
  402 + array('ktcore.validators.string', array(
  403 + 'test' => 'name',
  404 + 'output' => 'name',
  405 + )),
  406 + array('ktcore.validators.string', array(
  407 + 'test' => 'description',
  408 + 'output' => 'description',
  409 + )),
  410 + array('ktcore.validators.boolean', array(
  411 + 'test' => 'required',
  412 + 'output' => 'required',
  413 + )),
  414 + ));
  415 + }
  416 + return $oForm;
  417 + }
  418 + /**
  419 + * Manages a field
  420 + * @return template
  421 + *
  422 + *
  423 + * iNET Process
  424 + */
  425 + function do_managefield() {
  426 + $oTemplate = $this->oValidator->validateTemplate('manage_field');
  427 +
  428 + $oTemplate->setData(array(
  429 + 'context' => $this,
  430 + 'field_name' => $this->oField->getName(),
  431 + 'field_id' => $this->oField->getId(),
  432 + 'form' => $this->form_editfield($this->oField),
  433 + 'field' => $this->oField,
  434 + ));
  435 + return $oTemplate->render();
  436 + }
  437 + /**
  438 + * Updates a field
  439 + * @return.
  440 + *
  441 + *
  442 + * iNET Process
  443 + */
  444 + function do_updatefield() {
  445 + $oForm = $this->form_editfield($this->oField);
  446 + $res = $oForm->validate();
  447 + $data = $res['results'];
  448 + $errors = $res['errors'];
  449 + $extra_errors = array();
  450 +
  451 + // check that the field name either hasn't changed, or doesn't exist.
  452 + if ($data['name'] != $this->oField->getName()) {
  453 + $oOldField = DocumentField::getByFieldsetAndName($this->oFieldset, $data['name']);
  454 + if (!PEAR::isError($oOldField)) {
  455 + $extra_errors['name'] = _kt("That name is already in use in this fieldset. Please specify a unique name.");
  456 + }
  457 + }
  458 +
  459 + if (!empty($errors) || !empty($extra_errors)) {
  460 + return $oForm->handleError(null, $extra_errors);
  461 + }
  462 +
  463 + $this->oField->setName($data['name']);
  464 + $this->oField->setDescription($data['description']);
  465 + $this->oField->setIsMandatory($data['required']);
  466 +
  467 + // multiselect change start
  468 + if(isset($data['inetlookup_type']) && $this->oField->getHasInetLookup())
  469 + {
  470 + $this->oField->setInetLookupType($data['inetlookup_type']);
  471 + }
  472 + // multiselect change end
  473 +
  474 + $res = $this->oField->update();
  475 + if (PEAR::isError($res)) {
  476 + return $oForm->handleError(sprintf(_kt("Failed to update field: %s"), $res->getMessage()));
  477 + }
  478 +
  479 + $this->successRedirectTo('managefield',_kt("Field updated."));
  480 + }
  481 + /**
  482 + * Add lookup
  483 + * @return form
  484 + *
  485 + * iNET Process
  486 + */
  487 + function form_addlookups() {
  488 + $oForm = new KTForm;
  489 + $oForm->setOptions(array(
  490 + 'identifier' => 'ktcore.fieldsets.basic.field.addlookup',
  491 + 'label' => _kt("Add Lookup Values"),
  492 + 'submit_label' => _kt('Add Lookups'),
  493 + 'cancel_action' => 'managefield',
  494 + 'fail_action' => 'addlookupvalues',
  495 + 'action' => 'createlookupvalues',
  496 + 'context' => $this,
  497 + ));
  498 +
  499 + $oForm->setWidgets(array(
  500 + array('ktcore.widgets.text',array(
  501 + 'label' => _kt("Lookup Values"),
  502 + 'name' => 'lookups',
  503 + 'required' => true,
  504 + 'description' => _kt("Lookup values are what a user can select from a dropdown. These pre-created lookup values are useful, since they help you keep the metadata in the system organised."),
  505 + 'important_description' => _kt("Please enter the lookup values you wish to add, one per line."),
  506 + )),
  507 + ));
  508 +
  509 + $oForm->setValidators(array(
  510 + array('ktcore.validators.string', array(
  511 + 'test' => 'lookups',
  512 + 'output' => 'lookups',
  513 + 'max_length' => 9999,
  514 + )),
  515 + ));
  516 +
  517 + return $oForm;
  518 + }
  519 +
  520 + /**
  521 + * Add lookup values
  522 + * @return
  523 + *
  524 + * iNET Process
  525 + */
  526 + function do_addlookupvalues() {
  527 + $this->oPage->setBreadcrumbDetails(_kt('add lookup values'));
  528 +
  529 + $oForm = $this->form_addlookups();
  530 + return $oForm->render();
  531 + }
  532 + /**
  533 + * Create lookup values
  534 + * @return
  535 + */
  536 + function do_createlookupvalues() {
  537 + $oForm = $this->form_addlookups();
  538 + $res = $oForm->validate();
  539 + $data = $res['results'];
  540 + $errors = $res['errors'];
  541 + $extra_errors = array();
  542 +
  543 +
  544 + $failed = array();
  545 + $lookups = array();
  546 +
  547 + $raw_lookups = $data['lookups'];
  548 + $lookup_candidates = explode("\n", $raw_lookups);
  549 + foreach ($lookup_candidates as $candidate) {
  550 + $name = trim($candidate);
  551 +
  552 + if (empty($name)) {
  553 + continue;
  554 + }
  555 +
  556 + // check for existing or to-be-created lookups.
  557 + if ($lookups[$name]) {
  558 + $failed[$name] = $name;
  559 + continue;
  560 + }
  561 +
  562 + if ($failed[$name]) {
  563 + continue; // already blown up, fix it.
  564 + }
  565 +
  566 + $oOldLookup = MetaData::getByValueAndDocumentField($name, $this->oField);
  567 + if (!PEAR::isError($oOldLookup)) {
  568 + $failed[$name] = $name;
  569 + continue;
  570 + }
  571 +
  572 + $lookups[$name] = $name;
  573 + }
  574 + if (!empty($failed)) {
  575 + $extra_errors['lookups'][] = sprintf(_kt("The following lookups you specified already exist, or are specified twice: %s"), implode(', ', $failed));
  576 + } else if (empty($lookups)) {
  577 + $extra_errors['lookups'][] = _kt("You must have at least 1 new lookup value.");
  578 + }
  579 +
  580 + if (!empty($errors) || !empty($extra_errors)) {
  581 + return $oForm->handleError(null, $extra_errors);
  582 + }
  583 +
  584 + $data['lookups'] = $lookups;
  585 +
  586 + foreach ($lookups as $value) {
  587 + $oLookup = MetaData::createFromArray(array(
  588 + 'DocFieldId' => $this->oField->getId(),
  589 + 'sName' => $value,
  590 + 'iTreeParent' => null,
  591 + 'bDisabled' => false,
  592 + 'bIsStuck' => false,
  593 + ));
  594 + if (PEAR::isError($oLookup)) {
  595 + return $oForm->handleError(sprintf(_kt("Failed to create lookup: %s"), $oLookup->getMessage()));
  596 + }
  597 + }
  598 +
  599 + $this->successRedirectTo('managefield', sprintf(_kt("%d lookups added."), count($lookups)));
  600 + }
  601 + /**
  602 + * Manages lookups
  603 + * @return template
  604 + *
  605 + * iNET Process
  606 + */
  607 + function do_managelookups() {
  608 + $this->oPage->setBreadcrumbDetails(_kt('manage lookup values'));
  609 +
  610 + // Add javascript to create the edit form
  611 + $sJavaScript = "\nfunction editLookup(id)\n
  612 + {\n
  613 + var div = document.getElementById(id);\n
  614 + var value = div.innerHTML;
  615 +
  616 + <!-- Replace all double quotes with &#34; -->\n
  617 + matches = value.match(/\"/g);\n
  618 + var newValue = value;\n
  619 + if(matches){\n
  620 + for(var i = 0; i < matches.length; i++){\n
  621 + newValue = newValue.replace('\"', '&#34;');\n
  622 + }\n
  623 + }\n\n
  624 +
  625 + var inner = '<input type=\"text\" name=\"lookup['+id+']\" id=\"lookup_'+id+'\" value=\"'+newValue+'\" />';\n
  626 + inner += '<input type=\"hidden\" id=\"original_'+id+'\" value=\"'+newValue+'\" />';\n
  627 + inner += '<input type=\"submit\" name=\"submit[edit]\" value=\""._kt('Save')."\" />';\n
  628 + inner += '<input type=\"button\" onclick=\"javascript: closeLookupEdit('+id+');\" name=\"cancel\" value=\""._kt('Cancel')."\" />';\n
  629 + div.innerHTML = inner;\n
  630 + document.getElementById('lookup_'+id).focus();\n
  631 + }\n\n
  632 +
  633 + function closeLookupEdit(id)
  634 + {\n
  635 + value = document.getElementById('original_'+id).value;\n
  636 + document.getElementById(id).innerHTML = value;\n
  637 + }\n\n";
  638 +
  639 + $this->oPage->requireJSStandalone($sJavaScript);
  640 +
  641 + $lookups =& MetaData::getByDocumentField($this->oField);
  642 + $args = $this->meldPersistQuery("","metadataMultiAction", true);
  643 +
  644 + $oTemplate =& $this->oValidator->validateTemplate("ktcore/metadata/admin/manage_lookups");
  645 + $oTemplate->setData(array(
  646 + 'context' => $this,
  647 + 'field_name' => $this->oField->getName(),
  648 + 'lookups' => $lookups,
  649 + 'args' => $args,
  650 + ));
  651 + return $oTemplate->render();
  652 + }
  653 +
  654 + // {{{ do_metadataMultiAction
  655 + /**
  656 + * call metadata multiaction methods
  657 + * @param.
  658 + * @return.
  659 + *
  660 + * iNET Process
  661 + */
  662 + function do_metadataMultiAction() {
  663 + $subaction = array_keys(KTUtil::arrayGet($_REQUEST, 'submit', array()));
  664 + $this->oValidator->notEmpty($subaction, array("message" => _kt("No action specified")));
  665 + $subaction = $subaction[0];
  666 + $method = null;
  667 + if (method_exists($this, 'lookup_' . $subaction)) {
  668 + $method = 'lookup_' . $subaction;
  669 + }
  670 + $this->oValidator->notEmpty($method, array("message" => _kt("Unknown action specified")));
  671 + return $this->$method();
  672 + }
  673 + // }}}
  674 +
  675 + // {{{ lookup_remove
  676 + /**
  677 + * remove lookup value.
  678 + * @param
  679 + * @return
  680 + *
  681 + * iNET Process
  682 + */
  683 + function lookup_remove() {
  684 + $oFieldset =& $this->oValidator->validateFieldset($_REQUEST['fFieldsetId']);
  685 + $oField =& DocumentField::get($_REQUEST['fFieldId']);
  686 + $aMetadata = KTUtil::arrayGet($_REQUEST, 'metadata');
  687 + if (empty($aMetadata)) {
  688 + $this->errorRedirectTo('managelookups', _kt('No lookups selected'));
  689 + }
  690 + foreach ($_REQUEST['metadata'] as $iMetaDataId) {
  691 + $oMetaData =& MetaData::get($iMetaDataId);
  692 + if (PEAR::isError($oMetaData)) {
  693 + $this->errorRedirectTo('managelookups', _kt('Invalid lookup selected'));
  694 + }
  695 + $oMetaData->delete();
  696 + }
  697 + $this->successRedirectTo('managelookups', _kt('Lookups removed'));
  698 + exit(0);
  699 + }
  700 + // }}}
  701 +
  702 + // {{{ lookup_disable
  703 + /**
  704 + * disable lookup value.
  705 + * @param
  706 + * @return
  707 + *
  708 + * iNET Process
  709 + */
  710 + function lookup_disable() {
  711 + $oFieldset =& $this->oValidator->validateFieldset($_REQUEST['fFieldsetId']);
  712 + $oField =& DocumentField::get($_REQUEST['fFieldId']);
  713 + $aMetadata = KTUtil::arrayGet($_REQUEST, 'metadata');
  714 + if (empty($aMetadata)) {
  715 + $this->errorRedirectTo('managelookups', _kt('No lookups selected'));
  716 + }
  717 + foreach ($_REQUEST['metadata'] as $iMetaDataId) {
  718 + $oMetaData =& MetaData::get($iMetaDataId);
  719 + if (PEAR::isError($oMetaData)) {
  720 + $this->errorRedirectTo('managelookups', _kt('Invalid lookup selected'));
  721 + }
  722 + $oMetaData->setDisabled(true);
  723 + $oMetaData->update();
  724 + }
  725 + $this->successRedirectTo('managelookups', _kt('Lookups disabled'));
  726 + exit(0);
  727 + }
  728 + // }}}
  729 +
  730 + /**
  731 + * Save the edited lookup values
  732 + *
  733 + * @param.
  734 + * @return.
  735 + *
  736 + *iNET Process
  737 + */
  738 + function lookup_edit(){
  739 + $aLookupValues = $_REQUEST['lookup'];
  740 +
  741 + if(empty($aLookupValues)){
  742 + $this->errorRedirectTo('managelookups', _kt('No lookups were selected for editing'));
  743 + exit;
  744 + }
  745 +
  746 + foreach ($aLookupValues as $iMetaDataId => $sValue){
  747 + $oMetaData = MetaData::get($iMetaDataId);
  748 + if (PEAR::isError($oMetaData)) {
  749 + $this->addErrorMessage(_kt('Invalid lookup selected').': '.$sValue);
  750 + continue;
  751 +
  752 + }
  753 + if(empty($sValue)){
  754 + $this->addErrorMessage(_kt('Lookup cannot be empty').': '.$oMetaData->getName());
  755 + if(count($aLookupValues) == 1){
  756 + $this->redirectTo('managelookups');
  757 + }
  758 + continue;
  759 + }
  760 + $oMetaData->setName($sValue);
  761 + $oMetaData->update();
  762 + }
  763 +
  764 + $this->successRedirectTo('managelookups', _kt('Lookup values saved'));
  765 + exit(0);
  766 + }
  767 +
  768 + // {{{ lookup_enable
  769 + /**
  770 + * enable lookup value
  771 + * @param
  772 + * @return
  773 + *
  774 + * iNET Process
  775 + */
  776 + function lookup_toggleenabled() {
  777 + $oFieldset =& $this->oValidator->validateFieldset($_REQUEST['fFieldsetId']);
  778 + $oField =& DocumentField::get($_REQUEST['fFieldId']);
  779 + $aMetadata = KTUtil::arrayGet($_REQUEST, 'metadata');
  780 + if (empty($aMetadata)) {
  781 + $this->errorRedirectTo('managelookups', _kt('No lookups selected'));
  782 + }
  783 + foreach ($_REQUEST['metadata'] as $iMetaDataId) {
  784 + $oMetaData =& MetaData::get($iMetaDataId);
  785 + if (PEAR::isError($oMetadata)) {
  786 + $this->errorRedirectTo('managelookups', _kt('Invalid lookup selected'));
  787 + }
  788 + $oMetaData->setDisabled(!$oMetaData->getDisabled());
  789 + $oMetaData->update();
  790 + }
  791 + $this->successRedirectTo('managelookups', _kt('Status Toggled'));
  792 + exit(0);
  793 + }
  794 + // }}}
  795 +
  796 + // {{{ lookup_togglestickiness
  797 + /**
  798 + * toggle stickiness of lookup values
  799 + * @param
  800 + * @return
  801 + *
  802 + * iNET Process
  803 + */
  804 + function lookup_togglestickiness() {
  805 + $oFieldset =& $this->oValidator->validateFieldset($_REQUEST['fFieldsetId']);
  806 + $oField =& DocumentField::get($_REQUEST['fFieldId']);
  807 + $aMetadata = KTUtil::arrayGet($_REQUEST, 'metadata');
  808 + if (empty($aMetadata)) {
  809 + $this->errorRedirectTo('managelookups', _kt('No lookups selected'));
  810 + }
  811 + foreach ($_REQUEST['metadata'] as $iMetaDataId) {
  812 + $oMetaData =& MetaData::get($iMetaDataId);
  813 + if (PEAR::isError($oMetaData)) {
  814 + $this->errorRedirectTo('managelookups', _kt('Invalid lookups selected'));
  815 + }
  816 + $bStuck = (boolean)$oMetaData->getIsStuck();
  817 + $oMetaData->setIsStuck(!$bStuck);
  818 + $oMetaData->update();
  819 + }
  820 + $this->successRedirectTo('managelookups', _kt('Lookup stickiness toggled'));
  821 + exit(0);
  822 + }
  823 + // }}}
  824 +
  825 +// {{{ TREE
  826 + // create and display the tree editing form.
  827 + /**
  828 + * create and display the tree editing form.
  829 + * @param.
  830 + * @return template
  831 + *
  832 + * iNET Process
  833 + */
  834 + function do_managetree() {
  835 + global $default;
  836 + // extract.
  837 + $iFieldsetId = KTUtil::getId($this->oFieldset);
  838 + $iFieldId = KTUtil::getId($this->oField);
  839 +
  840 + $oFieldset =& $this->oFieldset;
  841 + $oField =& $this->oField;
  842 +
  843 + $this->oPage->setBreadcrumbDetails(_kt('edit lookup tree'));
  844 +
  845 + $field_id = $iFieldId;
  846 + $current_node = KTUtil::arrayGet($_REQUEST, 'current_node', 0);
  847 + $subaction = KTUtil::arrayGet($_REQUEST, 'subaction');
  848 +
  849 + // validate
  850 + if (empty($field_id)) { return $this->errorRedirectToMain(_kt("Must select a field to edit.")); }
  851 + $oField =& DocumentField::get($field_id);
  852 + if (PEAR::isError($oField)) { return $this->errorRedirectToMain(_kt("Invalid field.")); }
  853 +
  854 + $aErrorOptions = array(
  855 + 'redirect_to' => array('editTree', sprintf('field_id=%d', $field_id)),
  856 + );
  857 +
  858 + // under here we do the subaction rendering.
  859 + // we do this so we don't have to do _very_ strange things with multiple actions.
  860 +
  861 + $fieldTree =& new MDTree();
  862 + $fieldTree->buildForField($oField->getId());
  863 +
  864 + if ($subaction !== null) {
  865 + $target = 'managetree';
  866 + $msg = _kt('Changes saved.');
  867 + if ($subaction === "addCategory") {
  868 + $new_category = KTUtil::arrayGet($_REQUEST, 'category_name');
  869 + if (empty($new_category)) {
  870 + return $this->errorRedirectTo("managetree", _kt("Must enter a name for the new category."), array("field_id" => $field_id, "fFieldsetId" => $iFieldsetId));
  871 + } else {
  872 + $this->subact_addCategory($field_id, $current_node, $new_category, $fieldTree);
  873 + }
  874 + $msg = _kt('Category added'). ': ' . $new_category;
  875 + }
  876 + if ($subaction === "deleteCategory") {
  877 + $this->subact_deleteCategory($fieldTree, $current_node);
  878 + $current_node = 0; // clear out, and don't try and render the newly deleted category.
  879 + $msg = _kt('Category removed.');
  880 + }
  881 + if ($subaction === "linkKeywords") {
  882 + $keywords = KTUtil::arrayGet($_REQUEST, 'keywordsToAdd');
  883 + $aErrorOptions['message'] = _kt("No keywords selected");
  884 + $this->oValidator->notEmpty($keywords, $aErrorOptions);
  885 + $this->subact_linkKeywords($fieldTree, $current_node, $keywords);
  886 + $current_node = 0; // clear out, and don't try and render the newly deleted category.
  887 + $msg = _kt('Keywords added to category.');
  888 + }
  889 + if ($subaction === "unlinkKeyword") {
  890 + $keyword = KTUtil::arrayGet($_REQUEST, 'keyword_id');
  891 + $this->subact_unlinkKeyword($fieldTree, $keyword);
  892 + $msg = _kt('Keyword moved to base of tree.');
  893 + }
  894 + // now redirect
  895 + $query = sprintf('field_id=%d&fFieldsetId=%d', $field_id, $iFieldsetId);
  896 + return $this->successRedirectTo($target, $msg, $query);
  897 + }
  898 + if ($fieldTree->root === null) {
  899 + return $this->errorRedirectToMain(_kt("Error building tree. Is this a valid tree-lookup field?"));
  900 + }
  901 +
  902 + // FIXME extract this from MDTree (helper method?)
  903 + $free_metadata = MetaData::getList('document_field_id = '.$oField->getId().' AND (treeorg_parent = 0 OR treeorg_parent IS NULL) AND (disabled = 0)');
  904 +
  905 + // render edit template.
  906 +
  907 + $oTemplate = $this->oValidator->validateTemplate("ktcore/metadata/admin/edit_lookuptree");
  908 + $renderedTree = $this->_evilTreeRenderer($fieldTree);
  909 +
  910 + $this->oPage->setTitle(_kt('Edit Lookup Tree'));
  911 +
  912 + if ($current_node == 0) { $category_name = 'Root'; }
  913 + else {
  914 + $oNode = MDTreeNode::get($current_node);
  915 + $category_name = $oNode->getName();
  916 + }
  917 +
  918 + $aTemplateData = array(
  919 + "context" => $this,
  920 + "args" => $this->meldPersistQuery("","managetree", true),
  921 + "field" => $oField,
  922 + "oFieldset" => $oFieldset,
  923 + "tree" => $fieldTree,
  924 + "renderedTree" => $renderedTree,
  925 + "currentNode" => $current_node,
  926 + 'category_name' => $category_name,
  927 + "freechildren" => $free_metadata,
  928 +
  929 + );
  930 + return $oTemplate->render($aTemplateData);
  931 + }
  932 + /**
  933 + * Adds a category
  934 + * @return
  935 + * @param $field_id Object
  936 + * @param $current_node Object
  937 + * @param $new_category Object
  938 + * @param $constructedTree Object
  939 + *
  940 + * iNET Process
  941 + */
  942 + function subact_addCategory($field_id, $current_node, $new_category, &$constructedTree) {
  943 + $newCategory = MDTreeNode::createFromArray(array (
  944 + "iFieldId" => $field_id,
  945 + "sName" => $new_category,
  946 + "iParentNode" => $current_node,
  947 + ));
  948 + if (PEAR::isError($newCategory))
  949 + {
  950 + return false;
  951 + }
  952 + $constructedTree->addNode($newCategory);
  953 + return true;
  954 + }
  955 + /**
  956 + * Deletes a catagory
  957 + * @return
  958 + * @param $constructedTree Object
  959 + * @param $current_node Object
  960 + */
  961 + function subact_deleteCategory(&$constructedTree, $current_node) {
  962 + $constructedTree->deleteNode($current_node);
  963 + return true;
  964 + }
  965 +
  966 + /**
  967 + *
  968 + * @param $constructedTree object
  969 + * @param $keywords
  970 + * @return true.
  971 + *
  972 + * iNET Process
  973 + */
  974 + function subact_unlinkKeyword(&$constructedTree, $keyword) {
  975 + $oKW = MetaData::get($keyword);
  976 + if (PEAR::isError($oKW)) {
  977 + return true;
  978 + }
  979 + $constructedTree->reparentKeyword($oKW->getId(), 0);
  980 + return true;
  981 + }
  982 +
  983 + /**
  984 + *
  985 + * @param $constructedTree object
  986 + * @param $current_node node id
  987 + * @param $keywords array
  988 + * @return true.
  989 + *
  990 + * iNET Process
  991 + */
  992 + function subact_linkKeywords(&$constructedTree, $current_node, $keywords) {
  993 + foreach ($keywords as $md_id)
  994 + {
  995 + $constructedTree->reparentKeyword($md_id, $current_node);
  996 + }
  997 + return true;
  998 + }
  999 +
  1000 + /* ----------------------- EVIL HACK --------------------------
  1001 + *
  1002 + * This whole thing needs to replaced, as soon as I work out how
  1003 + * to non-sucking Smarty recursion.
  1004 + */
  1005 +
  1006 + /**
  1007 + * render to subnode of tree
  1008 + *
  1009 + * @param $subnode node
  1010 + * @param $treeToRender object
  1011 + * @Return string
  1012 + *
  1013 + * iNET Process
  1014 + */
  1015 + function _evilTreeRecursion($subnode, $treeToRender)
  1016 + {
  1017 + // deliver us from evil....
  1018 + $iFieldId = $treeToRender->field_id;
  1019 + $oField = DocumentField::get($iFieldId);
  1020 + $iFieldsetId = $oField->getParentFieldsetId();
  1021 +
  1022 + $treeStr = "<ul>";
  1023 + foreach ($treeToRender->contents[$subnode] as $subnode_id => $subnode_val)
  1024 + {
  1025 + if ($subnode_id !== "leaves") {
  1026 + $treeStr .= '<li class="treenode active"><a class="pathnode inactive" onclick="toggleElementClass(\'active\', this.parentNode); toggleElementClass(\'inactive\', this.parentNode);">' . $treeToRender->mapnodes[$subnode_val]->getName() . '</a>';
  1027 + $treeStr .= $this->_evilActionHelper($iFieldsetId, $iFieldId, false, $subnode_val);
  1028 + $treeStr .= $this->_evilTreeRecursion($subnode_val, $treeToRender);
  1029 + $treeStr .= '</li>';
  1030 + }
  1031 + else
  1032 + {
  1033 + foreach ($subnode_val as $leaf)
  1034 + {
  1035 + $treeStr .= '<li class="leafnode">' . $treeToRender->lookups[$leaf]->getName();
  1036 + $treeStr .= $this->_evilActionHelper($iFieldsetId, $iFieldId, true, $leaf);
  1037 + $treeStr .= '</li>'; }
  1038 + }
  1039 + }
  1040 + $treeStr .= '</ul>';
  1041 + return $treeStr;
  1042 +
  1043 + }
  1044 +
  1045 + // I can't seem to do recursion in smarty, and recursive templates seems a bad solution.
  1046 + // Come up with a better way to do this (? NBM)
  1047 +
  1048 + /**
  1049 + * render tree
  1050 + *
  1051 + * @param $treeToRender object
  1052 + * @return tree string
  1053 + *
  1054 + * iNET Process
  1055 + */
  1056 + function _evilTreeRenderer($treeToRender) {
  1057 + //global $default;
  1058 +
  1059 + $treeStr = "<!-- this is rendered with an unholy hack. sorry. -->";
  1060 + $stack = array();
  1061 + $exitstack = array();
  1062 +
  1063 + // since the root is virtual, we need to fake it here.
  1064 + // the inner section is generised.
  1065 + $treeStr .= '<ul class="kt_treenodes"><li class="treenode active"><a class="pathnode" onclick="toggleElementClass(\'active\', this.parentNode);toggleElementClass(\'inactive\', this.parentNode);">' . _kt('Root') . '</a>';
  1066 + $treeStr .= ' (<a href="' . KTUtil::addQueryStringSelf($this->meldPersistQuery('current_node=0', 'managetree')) . '">' . _kt('attach keywords') . '</a>)';
  1067 + $treeStr .= '<ul>';
  1068 +
  1069 +
  1070 + foreach ($treeToRender->getRoot() as $node_id => $subtree_nodes)
  1071 + {
  1072 +
  1073 + // leaves are handled differently.
  1074 + if ($node_id !== "leaves") {
  1075 +
  1076 + $treeStr .= '<li class="treenode active"><a class="pathnode" onclick="toggleElementClass(\'active\', this.parentNode);toggleElementClass(\'inactive\', this.parentNode);">' . $treeToRender->mapnodes[$subtree_nodes]->getName() . '</a>';
  1077 + $treeStr .= $this->_evilActionHelper($iFieldsetId, $iFieldId, false, $subtree_nodes);
  1078 + $treeStr .= $this->_evilTreeRecursion($subtree_nodes, $treeToRender);
  1079 + $treeStr .= '</li>';
  1080 + }
  1081 + else
  1082 + {
  1083 + foreach ($subtree_nodes as $leaf)
  1084 + {
  1085 + $treeStr .= '<li class="leafnode">' . $treeToRender->lookups[$leaf]->getName();
  1086 + $treeStr .= $this->_evilActionHelper($iFieldsetId, $iFieldId, true, $leaf);
  1087 + $treeStr .= '</li>';
  1088 + }
  1089 + }
  1090 + }
  1091 + $treeStr .= '</ul></li>';
  1092 + $treeStr .= '</ul>';
  1093 +
  1094 + return $treeStr;
  1095 + }
  1096 +
  1097 + // BS: don't hate me.
  1098 + // BD: sorry. I hate you.
  1099 + /**
  1100 + * KT function
  1101 + *
  1102 + * @param $iFieldsetId ID
  1103 + * @param $iFieldId ID
  1104 + * @param $bIsKeyword boolean
  1105 + * @param $current_node node ID
  1106 + * @return string.
  1107 + *
  1108 + * iNET Process
  1109 + */
  1110 + function _evilActionHelper($iFieldsetId, $iFieldId, $bIsKeyword, $current_node) {
  1111 + $actionStr = " (";
  1112 + if ($bIsKeyword === true) {
  1113 + $actionStr .= '<a href="' . KTUtil::addQueryStringSelf(KTUtil::addQueryStringSelf($this->meldPersistQuery('keyword_id='.$current_node.'&subaction=unlinkKeyword', 'managetree'))) . '">' . _kt('unlink') . '</a>';
  1114 + } else {
  1115 + $actionStr .= '<a href="' . KTUtil::addQueryStringSelf($this->meldPersistQuery('current_node=' . $current_node, 'managetree')) .'">' . _kt('attach keywords') . '</a> ';
  1116 + $actionStr .= '| <a href="' . KTUtil::addQueryStringSelf($this->meldPersistQuery('current_node='.$current_node.'&subaction=deleteCategory', 'managetree')) . '">' . _kt('delete') . '</a>';
  1117 + }
  1118 + $actionStr .= ")";
  1119 + return $actionStr;
  1120 + }
  1121 + /**
  1122 + * Deletes a field
  1123 + * @return
  1124 + *
  1125 + * iNET Process
  1126 + */
  1127 + function do_deletefield() {
  1128 + $res = $this->oField->delete();
  1129 + if (PEAR::isError($res)) {
  1130 + $this->errorRedirectToParent(sprintf(_kt("Unable to delete field: %s"), $res->getMessage()));
  1131 + }
  1132 +
  1133 + $this->successRedirectToParent(_kt("Field deleted."));
  1134 + }
  1135 +
  1136 + /**
  1137 + * Move field up in the order
  1138 + *
  1139 + * iNET Process
  1140 + */
  1141 + function do_orderUp() {
  1142 + $iId = $this->oField->getID();
  1143 + $iFieldsetId = $this->oField->getParentFieldsetId();
  1144 +
  1145 + $res = $this->oField->movePosition($iFieldsetId, $iId, 'up');
  1146 + if ($res === false) {
  1147 + $this->errorRedirectToParent(_kt("Unable to move field up"));
  1148 + }
  1149 +
  1150 + $this->successRedirectToParent(_kt("Field moved up."));
  1151 + }
  1152 +
  1153 + /**
  1154 + * Move field down in the order
  1155 + *
  1156 + * iNET Process
  1157 + */
  1158 + function do_orderDown() {
  1159 + $iId = $this->oField->getID();
  1160 + $iFieldsetId = $this->oField->getParentFieldsetId();
  1161 +
  1162 + $res = $this->oField->movePosition($iFieldsetId, $iId, 'down');
  1163 + if ($res === false) {
  1164 + $this->errorRedirectToParent(_kt("Unable to move field down"));
  1165 + }
  1166 +
  1167 + $this->successRedirectToParent(_kt("Field moved down."));
  1168 + }
  1169 +}
  1170 +
  1171 +?>
... ...
plugins/multiselect/js/hideadminlink.js 0 โ†’ 100644
  1 +//To hide the link for existing document fieldset
  2 +JQ(document).ready(function(){
  3 + var elems = JQ("dl.panel_menu").find("a");
  4 + for (i = 0; i < elems.length; i++) {
  5 + if(elems[i].href.search("kt_path_info=documents/fieldmanagement2") > -1)
  6 + {
  7 + JQ(elems[i]).parent("dt").hide();
  8 + }
  9 + }
  10 +
  11 + var elemsDesc = JQ("dl.panel_menu").find("dd");
  12 + for (i = 0; i < elemsDesc.length; i++) {
  13 + if(elemsDesc[i].innerHTML.search("Manage the different types of information that can be associated with classes of documents.") > -1)
  14 + {
  15 + JQ(elemsDesc[i]).hide();
  16 + }
  17 + }
  18 +});
... ...
plugins/multiselect/js/hidelink.js 0 โ†’ 100644
  1 +//To hide the link for existing bulk upload link
  2 +JQ(document).ready(function(){
  3 + var elems = JQ("ul.actionlist").find("a");
  4 + for (i = 0; i < elems.length; i++) {
  5 + if(elems[i].href.search("kt_path_info=ktcore.actions.folder.bulkUpload") > -1 || elems[i].href.search("kt_path_info=inetfoldermetadata.actions.folder.bulkUpload") > -1)
  6 + {
  7 + JQ(elems[i]).parent("li").hide();
  8 + }
  9 + }
  10 +});
  11 +// added by SL:2009-03-04
  12 +JQ(document).ready(function(){
  13 + var elems = JQ("ul.actionlist").find("a");
  14 + for (i = 0; i < elems.length; i++) {
  15 + if(elems[i].href.search("kt_path_info=ktcore.actions.folder.bulkImport") > -1 || elems[i].href.search("kt_path_info=inetfoldermetadata.actions.folder.bulkUpload") > -1)
  16 + {
  17 + JQ(elems[i]).parent("li").hide();
  18 + }
  19 + }
  20 +});
0 21 \ No newline at end of file
... ...
plugins/multiselect/js/jquery-1.2.6.js 0 โ†’ 100644
  1 +(function(){
  2 +/*
  3 + * jQuery 1.2.6 - New Wave Javascript
  4 + *
  5 + * Copyright (c) 2008 John Resig (jquery.com)
  6 + * Dual licensed under the MIT (MIT-LICENSE.txt)
  7 + * and GPL (GPL-LICENSE.txt) licenses.
  8 + *
  9 + * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
  10 + * $Rev: 5685 $
  11 + */
  12 +
  13 +// Map over jQuery in case of overwrite
  14 +var _jQuery = window.jQuery,
  15 +// Map over the $ in case of overwrite
  16 + _$ = window.$;
  17 +
  18 +var jQuery = window.jQuery = window.$ = function( selector, context ) {
  19 + // The jQuery object is actually just the init constructor 'enhanced'
  20 + return new jQuery.fn.init( selector, context );
  21 +};
  22 +
  23 +// A simple way to check for HTML strings or ID strings
  24 +// (both of which we optimize for)
  25 +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,
  26 +
  27 +// Is it a simple selector
  28 + isSimple = /^.[^:#\[\.]*$/,
  29 +
  30 +// Will speed up references to undefined, and allows munging its name.
  31 + undefined;
  32 +
  33 +jQuery.fn = jQuery.prototype = {
  34 + init: function( selector, context ) {
  35 + // Make sure that a selection was provided
  36 + selector = selector || document;
  37 +
  38 + // Handle $(DOMElement)
  39 + if ( selector.nodeType ) {
  40 + this[0] = selector;
  41 + this.length = 1;
  42 + return this;
  43 + }
  44 + // Handle HTML strings
  45 + if ( typeof selector == "string" ) {
  46 + // Are we dealing with HTML string or an ID?
  47 + var match = quickExpr.exec( selector );
  48 +
  49 + // Verify a match, and that no context was specified for #id
  50 + if ( match && (match[1] || !context) ) {
  51 +
  52 + // HANDLE: $(html) -> $(array)
  53 + if ( match[1] )
  54 + selector = jQuery.clean( [ match[1] ], context );
  55 +
  56 + // HANDLE: $("#id")
  57 + else {
  58 + var elem = document.getElementById( match[3] );
  59 +
  60 + // Make sure an element was located
  61 + if ( elem ){
  62 + // Handle the case where IE and Opera return items
  63 + // by name instead of ID
  64 + if ( elem.id != match[3] )
  65 + return jQuery().find( selector );
  66 +
  67 + // Otherwise, we inject the element directly into the jQuery object
  68 + return jQuery( elem );
  69 + }
  70 + selector = [];
  71 + }
  72 +
  73 + // HANDLE: $(expr, [context])
  74 + // (which is just equivalent to: $(content).find(expr)
  75 + } else
  76 + return jQuery( context ).find( selector );
  77 +
  78 + // HANDLE: $(function)
  79 + // Shortcut for document ready
  80 + } else if ( jQuery.isFunction( selector ) )
  81 + return jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
  82 +
  83 + return this.setArray(jQuery.makeArray(selector));
  84 + },
  85 +
  86 + // The current version of jQuery being used
  87 + jquery: "1.2.6",
  88 +
  89 + // The number of elements contained in the matched element set
  90 + size: function() {
  91 + return this.length;
  92 + },
  93 +
  94 + // The number of elements contained in the matched element set
  95 + length: 0,
  96 +
  97 + // Get the Nth element in the matched element set OR
  98 + // Get the whole matched element set as a clean array
  99 + get: function( num ) {
  100 + return num == undefined ?
  101 +
  102 + // Return a 'clean' array
  103 + jQuery.makeArray( this ) :
  104 +
  105 + // Return just the object
  106 + this[ num ];
  107 + },
  108 +
  109 + // Take an array of elements and push it onto the stack
  110 + // (returning the new matched element set)
  111 + pushStack: function( elems ) {
  112 + // Build a new jQuery matched element set
  113 + var ret = jQuery( elems );
  114 +
  115 + // Add the old object onto the stack (as a reference)
  116 + ret.prevObject = this;
  117 +
  118 + // Return the newly-formed element set
  119 + return ret;
  120 + },
  121 +
  122 + // Force the current matched set of elements to become
  123 + // the specified array of elements (destroying the stack in the process)
  124 + // You should use pushStack() in order to do this, but maintain the stack
  125 + setArray: function( elems ) {
  126 + // Resetting the length to 0, then using the native Array push
  127 + // is a super-fast way to populate an object with array-like properties
  128 + this.length = 0;
  129 + Array.prototype.push.apply( this, elems );
  130 +
  131 + return this;
  132 + },
  133 +
  134 + // Execute a callback for every element in the matched set.
  135 + // (You can seed the arguments with an array of args, but this is
  136 + // only used internally.)
  137 + each: function( callback, args ) {
  138 + return jQuery.each( this, callback, args );
  139 + },
  140 +
  141 + // Determine the position of an element within
  142 + // the matched set of elements
  143 + index: function( elem ) {
  144 + var ret = -1;
  145 +
  146 + // Locate the position of the desired element
  147 + return jQuery.inArray(
  148 + // If it receives a jQuery object, the first element is used
  149 + elem && elem.jquery ? elem[0] : elem
  150 + , this );
  151 + },
  152 +
  153 + attr: function( name, value, type ) {
  154 + var options = name;
  155 +
  156 + // Look for the case where we're accessing a style value
  157 + if ( name.constructor == String )
  158 + if ( value === undefined )
  159 + return this[0] && jQuery[ type || "attr" ]( this[0], name );
  160 +
  161 + else {
  162 + options = {};
  163 + options[ name ] = value;
  164 + }
  165 +
  166 + // Check to see if we're setting style values
  167 + return this.each(function(i){
  168 + // Set all the styles
  169 + for ( name in options )
  170 + jQuery.attr(
  171 + type ?
  172 + this.style :
  173 + this,
  174 + name, jQuery.prop( this, options[ name ], type, i, name )
  175 + );
  176 + });
  177 + },
  178 +
  179 + css: function( key, value ) {
  180 + // ignore negative width and height values
  181 + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
  182 + value = undefined;
  183 + return this.attr( key, value, "curCSS" );
  184 + },
  185 +
  186 + text: function( text ) {
  187 + if ( typeof text != "object" && text != null )
  188 + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
  189 +
  190 + var ret = "";
  191 +
  192 + jQuery.each( text || this, function(){
  193 + jQuery.each( this.childNodes, function(){
  194 + if ( this.nodeType != 8 )
  195 + ret += this.nodeType != 1 ?
  196 + this.nodeValue :
  197 + jQuery.fn.text( [ this ] );
  198 + });
  199 + });
  200 +
  201 + return ret;
  202 + },
  203 +
  204 + wrapAll: function( html ) {
  205 + if ( this[0] )
  206 + // The elements to wrap the target around
  207 + jQuery( html, this[0].ownerDocument )
  208 + .clone()
  209 + .insertBefore( this[0] )
  210 + .map(function(){
  211 + var elem = this;
  212 +
  213 + while ( elem.firstChild )
  214 + elem = elem.firstChild;
  215 +
  216 + return elem;
  217 + })
  218 + .append(this);
  219 +
  220 + return this;
  221 + },
  222 +
  223 + wrapInner: function( html ) {
  224 + return this.each(function(){
  225 + jQuery( this ).contents().wrapAll( html );
  226 + });
  227 + },
  228 +
  229 + wrap: function( html ) {
  230 + return this.each(function(){
  231 + jQuery( this ).wrapAll( html );
  232 + });
  233 + },
  234 +
  235 + append: function() {
  236 + return this.domManip(arguments, true, false, function(elem){
  237 + if (this.nodeType == 1)
  238 + this.appendChild( elem );
  239 + });
  240 + },
  241 +
  242 + prepend: function() {
  243 + return this.domManip(arguments, true, true, function(elem){
  244 + if (this.nodeType == 1)
  245 + this.insertBefore( elem, this.firstChild );
  246 + });
  247 + },
  248 +
  249 + before: function() {
  250 + return this.domManip(arguments, false, false, function(elem){
  251 + this.parentNode.insertBefore( elem, this );
  252 + });
  253 + },
  254 +
  255 + after: function() {
  256 + return this.domManip(arguments, false, true, function(elem){
  257 + this.parentNode.insertBefore( elem, this.nextSibling );
  258 + });
  259 + },
  260 +
  261 + end: function() {
  262 + return this.prevObject || jQuery( [] );
  263 + },
  264 +
  265 + find: function( selector ) {
  266 + var elems = jQuery.map(this, function(elem){
  267 + return jQuery.find( selector, elem );
  268 + });
  269 +
  270 + return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
  271 + jQuery.unique( elems ) :
  272 + elems );
  273 + },
  274 +
  275 + clone: function( events ) {
  276 + // Do the clone
  277 + var ret = this.map(function(){
  278 + if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {
  279 + // IE copies events bound via attachEvent when
  280 + // using cloneNode. Calling detachEvent on the
  281 + // clone will also remove the events from the orignal
  282 + // In order to get around this, we use innerHTML.
  283 + // Unfortunately, this means some modifications to
  284 + // attributes in IE that are actually only stored
  285 + // as properties will not be copied (such as the
  286 + // the name attribute on an input).
  287 + var clone = this.cloneNode(true),
  288 + container = document.createElement("div");
  289 + container.appendChild(clone);
  290 + return jQuery.clean([container.innerHTML])[0];
  291 + } else
  292 + return this.cloneNode(true);
  293 + });
  294 +
  295 + // Need to set the expando to null on the cloned set if it exists
  296 + // removeData doesn't work here, IE removes it from the original as well
  297 + // this is primarily for IE but the data expando shouldn't be copied over in any browser
  298 + var clone = ret.find("*").andSelf().each(function(){
  299 + if ( this[ expando ] != undefined )
  300 + this[ expando ] = null;
  301 + });
  302 +
  303 + // Copy the events from the original to the clone
  304 + if ( events === true )
  305 + this.find("*").andSelf().each(function(i){
  306 + if (this.nodeType == 3)
  307 + return;
  308 + var events = jQuery.data( this, "events" );
  309 +
  310 + for ( var type in events )
  311 + for ( var handler in events[ type ] )
  312 + jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
  313 + });
  314 +
  315 + // Return the cloned set
  316 + return ret;
  317 + },
  318 +
  319 + filter: function( selector ) {
  320 + return this.pushStack(
  321 + jQuery.isFunction( selector ) &&
  322 + jQuery.grep(this, function(elem, i){
  323 + return selector.call( elem, i );
  324 + }) ||
  325 +
  326 + jQuery.multiFilter( selector, this ) );
  327 + },
  328 +
  329 + not: function( selector ) {
  330 + if ( selector.constructor == String )
  331 + // test special case where just one selector is passed in
  332 + if ( isSimple.test( selector ) )
  333 + return this.pushStack( jQuery.multiFilter( selector, this, true ) );
  334 + else
  335 + selector = jQuery.multiFilter( selector, this );
  336 +
  337 + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
  338 + return this.filter(function() {
  339 + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
  340 + });
  341 + },
  342 +
  343 + add: function( selector ) {
  344 + return this.pushStack( jQuery.unique( jQuery.merge(
  345 + this.get(),
  346 + typeof selector == 'string' ?
  347 + jQuery( selector ) :
  348 + jQuery.makeArray( selector )
  349 + )));
  350 + },
  351 +
  352 + is: function( selector ) {
  353 + return !!selector && jQuery.multiFilter( selector, this ).length > 0;
  354 + },
  355 +
  356 + hasClass: function( selector ) {
  357 + return this.is( "." + selector );
  358 + },
  359 +
  360 + val: function( value ) {
  361 + if ( value == undefined ) {
  362 +
  363 + if ( this.length ) {
  364 + var elem = this[0];
  365 +
  366 + // We need to handle select boxes special
  367 + if ( jQuery.nodeName( elem, "select" ) ) {
  368 + var index = elem.selectedIndex,
  369 + values = [],
  370 + options = elem.options,
  371 + one = elem.type == "select-one";
  372 +
  373 + // Nothing was selected
  374 + if ( index < 0 )
  375 + return null;
  376 +
  377 + // Loop through all the selected options
  378 + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
  379 + var option = options[ i ];
  380 +
  381 + if ( option.selected ) {
  382 + // Get the specifc value for the option
  383 + value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;
  384 +
  385 + // We don't need an array for one selects
  386 + if ( one )
  387 + return value;
  388 +
  389 + // Multi-Selects return an array
  390 + values.push( value );
  391 + }
  392 + }
  393 +
  394 + return values;
  395 +
  396 + // Everything else, we just grab the value
  397 + } else
  398 + return (this[0].value || "").replace(/\r/g, "");
  399 +
  400 + }
  401 +
  402 + return undefined;
  403 + }
  404 +
  405 + if( value.constructor == Number )
  406 + value += '';
  407 +
  408 + return this.each(function(){
  409 + if ( this.nodeType != 1 )
  410 + return;
  411 +
  412 + if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
  413 + this.checked = (jQuery.inArray(this.value, value) >= 0 ||
  414 + jQuery.inArray(this.name, value) >= 0);
  415 +
  416 + else if ( jQuery.nodeName( this, "select" ) ) {
  417 + var values = jQuery.makeArray(value);
  418 +
  419 + jQuery( "option", this ).each(function(){
  420 + this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
  421 + jQuery.inArray( this.text, values ) >= 0);
  422 + });
  423 +
  424 + if ( !values.length )
  425 + this.selectedIndex = -1;
  426 +
  427 + } else
  428 + this.value = value;
  429 + });
  430 + },
  431 +
  432 + html: function( value ) {
  433 + return value == undefined ?
  434 + (this[0] ?
  435 + this[0].innerHTML :
  436 + null) :
  437 + this.empty().append( value );
  438 + },
  439 +
  440 + replaceWith: function( value ) {
  441 + return this.after( value ).remove();
  442 + },
  443 +
  444 + eq: function( i ) {
  445 + return this.slice( i, i + 1 );
  446 + },
  447 +
  448 + slice: function() {
  449 + return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
  450 + },
  451 +
  452 + map: function( callback ) {
  453 + return this.pushStack( jQuery.map(this, function(elem, i){
  454 + return callback.call( elem, i, elem );
  455 + }));
  456 + },
  457 +
  458 + andSelf: function() {
  459 + return this.add( this.prevObject );
  460 + },
  461 +
  462 + data: function( key, value ){
  463 + var parts = key.split(".");
  464 + parts[1] = parts[1] ? "." + parts[1] : "";
  465 +
  466 + if ( value === undefined ) {
  467 + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
  468 +
  469 + if ( data === undefined && this.length )
  470 + data = jQuery.data( this[0], key );
  471 +
  472 + return data === undefined && parts[1] ?
  473 + this.data( parts[0] ) :
  474 + data;
  475 + } else
  476 + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
  477 + jQuery.data( this, key, value );
  478 + });
  479 + },
  480 +
  481 + removeData: function( key ){
  482 + return this.each(function(){
  483 + jQuery.removeData( this, key );
  484 + });
  485 + },
  486 +
  487 + domManip: function( args, table, reverse, callback ) {
  488 + var clone = this.length > 1, elems;
  489 +
  490 + return this.each(function(){
  491 + if ( !elems ) {
  492 + elems = jQuery.clean( args, this.ownerDocument );
  493 +
  494 + if ( reverse )
  495 + elems.reverse();
  496 + }
  497 +
  498 + var obj = this;
  499 +
  500 + if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
  501 + obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
  502 +
  503 + var scripts = jQuery( [] );
  504 +
  505 + jQuery.each(elems, function(){
  506 + var elem = clone ?
  507 + jQuery( this ).clone( true )[0] :
  508 + this;
  509 +
  510 + // execute all scripts after the elements have been injected
  511 + if ( jQuery.nodeName( elem, "script" ) )
  512 + scripts = scripts.add( elem );
  513 + else {
  514 + // Remove any inner scripts for later evaluation
  515 + if ( elem.nodeType == 1 )
  516 + scripts = scripts.add( jQuery( "script", elem ).remove() );
  517 +
  518 + // Inject the elements into the document
  519 + callback.call( obj, elem );
  520 + }
  521 + });
  522 +
  523 + scripts.each( evalScript );
  524 + });
  525 + }
  526 +};
  527 +
  528 +// Give the init function the jQuery prototype for later instantiation
  529 +jQuery.fn.init.prototype = jQuery.fn;
  530 +
  531 +function evalScript( i, elem ) {
  532 + if ( elem.src )
  533 + jQuery.ajax({
  534 + url: elem.src,
  535 + async: false,
  536 + dataType: "script"
  537 + });
  538 +
  539 + else
  540 + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
  541 +
  542 + if ( elem.parentNode )
  543 + elem.parentNode.removeChild( elem );
  544 +}
  545 +
  546 +function now(){
  547 + return +new Date;
  548 +}
  549 +
  550 +jQuery.extend = jQuery.fn.extend = function() {
  551 + // copy reference to target object
  552 + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
  553 +
  554 + // Handle a deep copy situation
  555 + if ( target.constructor == Boolean ) {
  556 + deep = target;
  557 + target = arguments[1] || {};
  558 + // skip the boolean and the target
  559 + i = 2;
  560 + }
  561 +
  562 + // Handle case when target is a string or something (possible in deep copy)
  563 + if ( typeof target != "object" && typeof target != "function" )
  564 + target = {};
  565 +
  566 + // extend jQuery itself if only one argument is passed
  567 + if ( length == i ) {
  568 + target = this;
  569 + --i;
  570 + }
  571 +
  572 + for ( ; i < length; i++ )
  573 + // Only deal with non-null/undefined values
  574 + if ( (options = arguments[ i ]) != null )
  575 + // Extend the base object
  576 + for ( var name in options ) {
  577 + var src = target[ name ], copy = options[ name ];
  578 +
  579 + // Prevent never-ending loop
  580 + if ( target === copy )
  581 + continue;
  582 +
  583 + // Recurse if we're merging object values
  584 + if ( deep && copy && typeof copy == "object" && !copy.nodeType )
  585 + target[ name ] = jQuery.extend( deep,
  586 + // Never move original objects, clone them
  587 + src || ( copy.length != null ? [ ] : { } )
  588 + , copy );
  589 +
  590 + // Don't bring in undefined values
  591 + else if ( copy !== undefined )
  592 + target[ name ] = copy;
  593 +
  594 + }
  595 +
  596 + // Return the modified object
  597 + return target;
  598 +};
  599 +
  600 +var expando = "jQuery" + now(), uuid = 0, windowData = {},
  601 + // exclude the following css properties to add px
  602 + exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
  603 + // cache defaultView
  604 + defaultView = document.defaultView || {};
  605 +
  606 +jQuery.extend({
  607 + noConflict: function( deep ) {
  608 + window.$ = _$;
  609 +
  610 + if ( deep )
  611 + window.jQuery = _jQuery;
  612 +
  613 + return jQuery;
  614 + },
  615 +
  616 + // See test/unit/core.js for details concerning this function.
  617 + isFunction: function( fn ) {
  618 + return !!fn && typeof fn != "string" && !fn.nodeName &&
  619 + fn.constructor != Array && /^[\s[]?function/.test( fn + "" );
  620 + },
  621 +
  622 + // check if an element is in a (or is an) XML document
  623 + isXMLDoc: function( elem ) {
  624 + return elem.documentElement && !elem.body ||
  625 + elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
  626 + },
  627 +
  628 + // Evalulates a script in a global context
  629 + globalEval: function( data ) {
  630 + data = jQuery.trim( data );
  631 +
  632 + if ( data ) {
  633 + // Inspired by code by Andrea Giammarchi
  634 + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
  635 + var head = document.getElementsByTagName("head")[0] || document.documentElement,
  636 + script = document.createElement("script");
  637 +
  638 + script.type = "text/javascript";
  639 + if ( jQuery.browser.msie )
  640 + script.text = data;
  641 + else
  642 + script.appendChild( document.createTextNode( data ) );
  643 +
  644 + // Use insertBefore instead of appendChild to circumvent an IE6 bug.
  645 + // This arises when a base node is used (#2709).
  646 + head.insertBefore( script, head.firstChild );
  647 + head.removeChild( script );
  648 + }
  649 + },
  650 +
  651 + nodeName: function( elem, name ) {
  652 + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
  653 + },
  654 +
  655 + cache: {},
  656 +
  657 + data: function( elem, name, data ) {
  658 + elem = elem == window ?
  659 + windowData :
  660 + elem;
  661 +
  662 + var id = elem[ expando ];
  663 +
  664 + // Compute a unique ID for the element
  665 + if ( !id )
  666 + id = elem[ expando ] = ++uuid;
  667 +
  668 + // Only generate the data cache if we're
  669 + // trying to access or manipulate it
  670 + if ( name && !jQuery.cache[ id ] )
  671 + jQuery.cache[ id ] = {};
  672 +
  673 + // Prevent overriding the named cache with undefined values
  674 + if ( data !== undefined )
  675 + jQuery.cache[ id ][ name ] = data;
  676 +
  677 + // Return the named cache data, or the ID for the element
  678 + return name ?
  679 + jQuery.cache[ id ][ name ] :
  680 + id;
  681 + },
  682 +
  683 + removeData: function( elem, name ) {
  684 + elem = elem == window ?
  685 + windowData :
  686 + elem;
  687 +
  688 + var id = elem[ expando ];
  689 +
  690 + // If we want to remove a specific section of the element's data
  691 + if ( name ) {
  692 + if ( jQuery.cache[ id ] ) {
  693 + // Remove the section of cache data
  694 + delete jQuery.cache[ id ][ name ];
  695 +
  696 + // If we've removed all the data, remove the element's cache
  697 + name = "";
  698 +
  699 + for ( name in jQuery.cache[ id ] )
  700 + break;
  701 +
  702 + if ( !name )
  703 + jQuery.removeData( elem );
  704 + }
  705 +
  706 + // Otherwise, we want to remove all of the element's data
  707 + } else {
  708 + // Clean up the element expando
  709 + try {
  710 + delete elem[ expando ];
  711 + } catch(e){
  712 + // IE has trouble directly removing the expando
  713 + // but it's ok with using removeAttribute
  714 + if ( elem.removeAttribute )
  715 + elem.removeAttribute( expando );
  716 + }
  717 +
  718 + // Completely remove the data cache
  719 + delete jQuery.cache[ id ];
  720 + }
  721 + },
  722 +
  723 + // args is for internal usage only
  724 + each: function( object, callback, args ) {
  725 + var name, i = 0, length = object.length;
  726 +
  727 + if ( args ) {
  728 + if ( length == undefined ) {
  729 + for ( name in object )
  730 + if ( callback.apply( object[ name ], args ) === false )
  731 + break;
  732 + } else
  733 + for ( ; i < length; )
  734 + if ( callback.apply( object[ i++ ], args ) === false )
  735 + break;
  736 +
  737 + // A special, fast, case for the most common use of each
  738 + } else {
  739 + if ( length == undefined ) {
  740 + for ( name in object )
  741 + if ( callback.call( object[ name ], name, object[ name ] ) === false )
  742 + break;
  743 + } else
  744 + for ( var value = object[0];
  745 + i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
  746 + }
  747 +
  748 + return object;
  749 + },
  750 +
  751 + prop: function( elem, value, type, i, name ) {
  752 + // Handle executable functions
  753 + if ( jQuery.isFunction( value ) )
  754 + value = value.call( elem, i );
  755 +
  756 + // Handle passing in a number to a CSS property
  757 + return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ?
  758 + value + "px" :
  759 + value;
  760 + },
  761 +
  762 + className: {
  763 + // internal only, use addClass("class")
  764 + add: function( elem, classNames ) {
  765 + jQuery.each((classNames || "").split(/\s+/), function(i, className){
  766 + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
  767 + elem.className += (elem.className ? " " : "") + className;
  768 + });
  769 + },
  770 +
  771 + // internal only, use removeClass("class")
  772 + remove: function( elem, classNames ) {
  773 + if (elem.nodeType == 1)
  774 + elem.className = classNames != undefined ?
  775 + jQuery.grep(elem.className.split(/\s+/), function(className){
  776 + return !jQuery.className.has( classNames, className );
  777 + }).join(" ") :
  778 + "";
  779 + },
  780 +
  781 + // internal only, use hasClass("class")
  782 + has: function( elem, className ) {
  783 + return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
  784 + }
  785 + },
  786 +
  787 + // A method for quickly swapping in/out CSS properties to get correct calculations
  788 + swap: function( elem, options, callback ) {
  789 + var old = {};
  790 + // Remember the old values, and insert the new ones
  791 + for ( var name in options ) {
  792 + old[ name ] = elem.style[ name ];
  793 + elem.style[ name ] = options[ name ];
  794 + }
  795 +
  796 + callback.call( elem );
  797 +
  798 + // Revert the old values
  799 + for ( var name in options )
  800 + elem.style[ name ] = old[ name ];
  801 + },
  802 +
  803 + css: function( elem, name, force ) {
  804 + if ( name == "width" || name == "height" ) {
  805 + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
  806 +
  807 + function getWH() {
  808 + val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
  809 + var padding = 0, border = 0;
  810 + jQuery.each( which, function() {
  811 + padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
  812 + border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
  813 + });
  814 + val -= Math.round(padding + border);
  815 + }
  816 +
  817 + if ( jQuery(elem).is(":visible") )
  818 + getWH();
  819 + else
  820 + jQuery.swap( elem, props, getWH );
  821 +
  822 + return Math.max(0, val);
  823 + }
  824 +
  825 + return jQuery.curCSS( elem, name, force );
  826 + },
  827 +
  828 + curCSS: function( elem, name, force ) {
  829 + var ret, style = elem.style;
  830 +
  831 + // A helper method for determining if an element's values are broken
  832 + function color( elem ) {
  833 + if ( !jQuery.browser.safari )
  834 + return false;
  835 +
  836 + // defaultView is cached
  837 + var ret = defaultView.getComputedStyle( elem, null );
  838 + return !ret || ret.getPropertyValue("color") == "";
  839 + }
  840 +
  841 + // We need to handle opacity special in IE
  842 + if ( name == "opacity" && jQuery.browser.msie ) {
  843 + ret = jQuery.attr( style, "opacity" );
  844 +
  845 + return ret == "" ?
  846 + "1" :
  847 + ret;
  848 + }
  849 + // Opera sometimes will give the wrong display answer, this fixes it, see #2037
  850 + if ( jQuery.browser.opera && name == "display" ) {
  851 + var save = style.outline;
  852 + style.outline = "0 solid black";
  853 + style.outline = save;
  854 + }
  855 +
  856 + // Make sure we're using the right name for getting the float value
  857 + if ( name.match( /float/i ) )
  858 + name = styleFloat;
  859 +
  860 + if ( !force && style && style[ name ] )
  861 + ret = style[ name ];
  862 +
  863 + else if ( defaultView.getComputedStyle ) {
  864 +
  865 + // Only "float" is needed here
  866 + if ( name.match( /float/i ) )
  867 + name = "float";
  868 +
  869 + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
  870 +
  871 + var computedStyle = defaultView.getComputedStyle( elem, null );
  872 +
  873 + if ( computedStyle && !color( elem ) )
  874 + ret = computedStyle.getPropertyValue( name );
  875 +
  876 + // If the element isn't reporting its values properly in Safari
  877 + // then some display: none elements are involved
  878 + else {
  879 + var swap = [], stack = [], a = elem, i = 0;
  880 +
  881 + // Locate all of the parent display: none elements
  882 + for ( ; a && color(a); a = a.parentNode )
  883 + stack.unshift(a);
  884 +
  885 + // Go through and make them visible, but in reverse
  886 + // (It would be better if we knew the exact display type that they had)
  887 + for ( ; i < stack.length; i++ )
  888 + if ( color( stack[ i ] ) ) {
  889 + swap[ i ] = stack[ i ].style.display;
  890 + stack[ i ].style.display = "block";
  891 + }
  892 +
  893 + // Since we flip the display style, we have to handle that
  894 + // one special, otherwise get the value
  895 + ret = name == "display" && swap[ stack.length - 1 ] != null ?
  896 + "none" :
  897 + ( computedStyle && computedStyle.getPropertyValue( name ) ) || "";
  898 +
  899 + // Finally, revert the display styles back
  900 + for ( i = 0; i < swap.length; i++ )
  901 + if ( swap[ i ] != null )
  902 + stack[ i ].style.display = swap[ i ];
  903 + }
  904 +
  905 + // We should always get a number back from opacity
  906 + if ( name == "opacity" && ret == "" )
  907 + ret = "1";
  908 +
  909 + } else if ( elem.currentStyle ) {
  910 + var camelCase = name.replace(/\-(\w)/g, function(all, letter){
  911 + return letter.toUpperCase();
  912 + });
  913 +
  914 + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
  915 +
  916 + // From the awesome hack by Dean Edwards
  917 + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  918 +
  919 + // If we're not dealing with a regular pixel number
  920 + // but a number that has a weird ending, we need to convert it to pixels
  921 + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
  922 + // Remember the original values
  923 + var left = style.left, rsLeft = elem.runtimeStyle.left;
  924 +
  925 + // Put in the new values to get a computed value out
  926 + elem.runtimeStyle.left = elem.currentStyle.left;
  927 + style.left = ret || 0;
  928 + ret = style.pixelLeft + "px";
  929 +
  930 + // Revert the changed values
  931 + style.left = left;
  932 + elem.runtimeStyle.left = rsLeft;
  933 + }
  934 + }
  935 +
  936 + return ret;
  937 + },
  938 +
  939 + clean: function( elems, context ) {
  940 + var ret = [];
  941 + context = context || document;
  942 + // !context.createElement fails in IE with an error but returns typeof 'object'
  943 + if (typeof context.createElement == 'undefined')
  944 + context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
  945 +
  946 + jQuery.each(elems, function(i, elem){
  947 + if ( !elem )
  948 + return;
  949 +
  950 + if ( elem.constructor == Number )
  951 + elem += '';
  952 +
  953 + // Convert html string into DOM nodes
  954 + if ( typeof elem == "string" ) {
  955 + // Fix "XHTML"-style tags in all browsers
  956 + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
  957 + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
  958 + all :
  959 + front + "></" + tag + ">";
  960 + });
  961 +
  962 + // Trim whitespace, otherwise indexOf won't work as expected
  963 + var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
  964 +
  965 + var wrap =
  966 + // option or optgroup
  967 + !tags.indexOf("<opt") &&
  968 + [ 1, "<select multiple='multiple'>", "</select>" ] ||
  969 +
  970 + !tags.indexOf("<leg") &&
  971 + [ 1, "<fieldset>", "</fieldset>" ] ||
  972 +
  973 + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
  974 + [ 1, "<table>", "</table>" ] ||
  975 +
  976 + !tags.indexOf("<tr") &&
  977 + [ 2, "<table><tbody>", "</tbody></table>" ] ||
  978 +
  979 + // <thead> matched above
  980 + (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
  981 + [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
  982 +
  983 + !tags.indexOf("<col") &&
  984 + [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
  985 +
  986 + // IE can't serialize <link> and <script> tags normally
  987 + jQuery.browser.msie &&
  988 + [ 1, "div<div>", "</div>" ] ||
  989 +
  990 + [ 0, "", "" ];
  991 +
  992 + // Go to html and back, then peel off extra wrappers
  993 + div.innerHTML = wrap[1] + elem + wrap[2];
  994 +
  995 + // Move to the right depth
  996 + while ( wrap[0]-- )
  997 + div = div.lastChild;
  998 +
  999 + // Remove IE's autoinserted <tbody> from table fragments
  1000 + if ( jQuery.browser.msie ) {
  1001 +
  1002 + // String was a <table>, *may* have spurious <tbody>
  1003 + var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
  1004 + div.firstChild && div.firstChild.childNodes :
  1005 +
  1006 + // String was a bare <thead> or <tfoot>
  1007 + wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
  1008 + div.childNodes :
  1009 + [];
  1010 +
  1011 + for ( var j = tbody.length - 1; j >= 0 ; --j )
  1012 + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
  1013 + tbody[ j ].parentNode.removeChild( tbody[ j ] );
  1014 +
  1015 + // IE completely kills leading whitespace when innerHTML is used
  1016 + if ( /^\s/.test( elem ) )
  1017 + div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
  1018 +
  1019 + }
  1020 +
  1021 + elem = jQuery.makeArray( div.childNodes );
  1022 + }
  1023 +
  1024 + if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
  1025 + return;
  1026 +
  1027 + if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
  1028 + ret.push( elem );
  1029 +
  1030 + else
  1031 + ret = jQuery.merge( ret, elem );
  1032 +
  1033 + });
  1034 +
  1035 + return ret;
  1036 + },
  1037 +
  1038 + attr: function( elem, name, value ) {
  1039 + // don't set attributes on text and comment nodes
  1040 + if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
  1041 + return undefined;
  1042 +
  1043 + var notxml = !jQuery.isXMLDoc( elem ),
  1044 + // Whether we are setting (or getting)
  1045 + set = value !== undefined,
  1046 + msie = jQuery.browser.msie;
  1047 +
  1048 + // Try to normalize/fix the name
  1049 + name = notxml && jQuery.props[ name ] || name;
  1050 +
  1051 + // Only do all the following if this is a node (faster for style)
  1052 + // IE elem.getAttribute passes even for style
  1053 + if ( elem.tagName ) {
  1054 +
  1055 + // These attributes require special treatment
  1056 + var special = /href|src|style/.test( name );
  1057 +
  1058 + // Safari mis-reports the default selected property of a hidden option
  1059 + // Accessing the parent's selectedIndex property fixes it
  1060 + if ( name == "selected" && jQuery.browser.safari )
  1061 + elem.parentNode.selectedIndex;
  1062 +
  1063 + // If applicable, access the attribute via the DOM 0 way
  1064 + if ( name in elem && notxml && !special ) {
  1065 + if ( set ){
  1066 + // We can't allow the type property to be changed (since it causes problems in IE)
  1067 + if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
  1068 + throw "type property can't be changed";
  1069 +
  1070 + elem[ name ] = value;
  1071 + }
  1072 +
  1073 + // browsers index elements by id/name on forms, give priority to attributes.
  1074 + if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
  1075 + return elem.getAttributeNode( name ).nodeValue;
  1076 +
  1077 + return elem[ name ];
  1078 + }
  1079 +
  1080 + if ( msie && notxml && name == "style" )
  1081 + return jQuery.attr( elem.style, "cssText", value );
  1082 +
  1083 + if ( set )
  1084 + // convert the value to a string (all browsers do this but IE) see #1070
  1085 + elem.setAttribute( name, "" + value );
  1086 +
  1087 + var attr = msie && notxml && special
  1088 + // Some attributes require a special call on IE
  1089 + ? elem.getAttribute( name, 2 )
  1090 + : elem.getAttribute( name );
  1091 +
  1092 + // Non-existent attributes return null, we normalize to undefined
  1093 + return attr === null ? undefined : attr;
  1094 + }
  1095 +
  1096 + // elem is actually elem.style ... set the style
  1097 +
  1098 + // IE uses filters for opacity
  1099 + if ( msie && name == "opacity" ) {
  1100 + if ( set ) {
  1101 + // IE has trouble with opacity if it does not have layout
  1102 + // Force it by setting the zoom level
  1103 + elem.zoom = 1;
  1104 +
  1105 + // Set the alpha filter to set the opacity
  1106 + elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
  1107 + (parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
  1108 + }
  1109 +
  1110 + return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
  1111 + (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
  1112 + "";
  1113 + }
  1114 +
  1115 + name = name.replace(/-([a-z])/ig, function(all, letter){
  1116 + return letter.toUpperCase();
  1117 + });
  1118 +
  1119 + if ( set )
  1120 + elem[ name ] = value;
  1121 +
  1122 + return elem[ name ];
  1123 + },
  1124 +
  1125 + trim: function( text ) {
  1126 + return (text || "").replace( /^\s+|\s+$/g, "" );
  1127 + },
  1128 +
  1129 + makeArray: function( array ) {
  1130 + var ret = [];
  1131 +
  1132 + if( array != null ){
  1133 + var i = array.length;
  1134 + //the window, strings and functions also have 'length'
  1135 + if( i == null || array.split || array.setInterval || array.call )
  1136 + ret[0] = array;
  1137 + else
  1138 + while( i )
  1139 + ret[--i] = array[i];
  1140 + }
  1141 +
  1142 + return ret;
  1143 + },
  1144 +
  1145 + inArray: function( elem, array ) {
  1146 + for ( var i = 0, length = array.length; i < length; i++ )
  1147 + // Use === because on IE, window == document
  1148 + if ( array[ i ] === elem )
  1149 + return i;
  1150 +
  1151 + return -1;
  1152 + },
  1153 +
  1154 + merge: function( first, second ) {
  1155 + // We have to loop this way because IE & Opera overwrite the length
  1156 + // expando of getElementsByTagName
  1157 + var i = 0, elem, pos = first.length;
  1158 + // Also, we need to make sure that the correct elements are being returned
  1159 + // (IE returns comment nodes in a '*' query)
  1160 + if ( jQuery.browser.msie ) {
  1161 + while ( elem = second[ i++ ] )
  1162 + if ( elem.nodeType != 8 )
  1163 + first[ pos++ ] = elem;
  1164 +
  1165 + } else
  1166 + while ( elem = second[ i++ ] )
  1167 + first[ pos++ ] = elem;
  1168 +
  1169 + return first;
  1170 + },
  1171 +
  1172 + unique: function( array ) {
  1173 + var ret = [], done = {};
  1174 +
  1175 + try {
  1176 +
  1177 + for ( var i = 0, length = array.length; i < length; i++ ) {
  1178 + var id = jQuery.data( array[ i ] );
  1179 +
  1180 + if ( !done[ id ] ) {
  1181 + done[ id ] = true;
  1182 + ret.push( array[ i ] );
  1183 + }
  1184 + }
  1185 +
  1186 + } catch( e ) {
  1187 + ret = array;
  1188 + }
  1189 +
  1190 + return ret;
  1191 + },
  1192 +
  1193 + grep: function( elems, callback, inv ) {
  1194 + var ret = [];
  1195 +
  1196 + // Go through the array, only saving the items
  1197 + // that pass the validator function
  1198 + for ( var i = 0, length = elems.length; i < length; i++ )
  1199 + if ( !inv != !callback( elems[ i ], i ) )
  1200 + ret.push( elems[ i ] );
  1201 +
  1202 + return ret;
  1203 + },
  1204 +
  1205 + map: function( elems, callback ) {
  1206 + var ret = [];
  1207 +
  1208 + // Go through the array, translating each of the items to their
  1209 + // new value (or values).
  1210 + for ( var i = 0, length = elems.length; i < length; i++ ) {
  1211 + var value = callback( elems[ i ], i );
  1212 +
  1213 + if ( value != null )
  1214 + ret[ ret.length ] = value;
  1215 + }
  1216 +
  1217 + return ret.concat.apply( [], ret );
  1218 + }
  1219 +});
  1220 +
  1221 +var userAgent = navigator.userAgent.toLowerCase();
  1222 +
  1223 +// Figure out what browser is being used
  1224 +jQuery.browser = {
  1225 + version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
  1226 + safari: /webkit/.test( userAgent ),
  1227 + opera: /opera/.test( userAgent ),
  1228 + msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
  1229 + mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
  1230 +};
  1231 +
  1232 +var styleFloat = jQuery.browser.msie ?
  1233 + "styleFloat" :
  1234 + "cssFloat";
  1235 +
  1236 +jQuery.extend({
  1237 + // Check to see if the W3C box model is being used
  1238 + boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
  1239 +
  1240 + props: {
  1241 + "for": "htmlFor",
  1242 + "class": "className",
  1243 + "float": styleFloat,
  1244 + cssFloat: styleFloat,
  1245 + styleFloat: styleFloat,
  1246 + readonly: "readOnly",
  1247 + maxlength: "maxLength",
  1248 + cellspacing: "cellSpacing"
  1249 + }
  1250 +});
  1251 +
  1252 +jQuery.each({
  1253 + parent: function(elem){return elem.parentNode;},
  1254 + parents: function(elem){return jQuery.dir(elem,"parentNode");},
  1255 + next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
  1256 + prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
  1257 + nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
  1258 + prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
  1259 + siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
  1260 + children: function(elem){return jQuery.sibling(elem.firstChild);},
  1261 + contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
  1262 +}, function(name, fn){
  1263 + jQuery.fn[ name ] = function( selector ) {
  1264 + var ret = jQuery.map( this, fn );
  1265 +
  1266 + if ( selector && typeof selector == "string" )
  1267 + ret = jQuery.multiFilter( selector, ret );
  1268 +
  1269 + return this.pushStack( jQuery.unique( ret ) );
  1270 + };
  1271 +});
  1272 +
  1273 +jQuery.each({
  1274 + appendTo: "append",
  1275 + prependTo: "prepend",
  1276 + insertBefore: "before",
  1277 + insertAfter: "after",
  1278 + replaceAll: "replaceWith"
  1279 +}, function(name, original){
  1280 + jQuery.fn[ name ] = function() {
  1281 + var args = arguments;
  1282 +
  1283 + return this.each(function(){
  1284 + for ( var i = 0, length = args.length; i < length; i++ )
  1285 + jQuery( args[ i ] )[ original ]( this );
  1286 + });
  1287 + };
  1288 +});
  1289 +
  1290 +jQuery.each({
  1291 + removeAttr: function( name ) {
  1292 + jQuery.attr( this, name, "" );
  1293 + if (this.nodeType == 1)
  1294 + this.removeAttribute( name );
  1295 + },
  1296 +
  1297 + addClass: function( classNames ) {
  1298 + jQuery.className.add( this, classNames );
  1299 + },
  1300 +
  1301 + removeClass: function( classNames ) {
  1302 + jQuery.className.remove( this, classNames );
  1303 + },
  1304 +
  1305 + toggleClass: function( classNames ) {
  1306 + jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
  1307 + },
  1308 +
  1309 + remove: function( selector ) {
  1310 + if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
  1311 + // Prevent memory leaks
  1312 + jQuery( "*", this ).add(this).each(function(){
  1313 + jQuery.event.remove(this);
  1314 + jQuery.removeData(this);
  1315 + });
  1316 + if (this.parentNode)
  1317 + this.parentNode.removeChild( this );
  1318 + }
  1319 + },
  1320 +
  1321 + empty: function() {
  1322 + // Remove element nodes and prevent memory leaks
  1323 + jQuery( ">*", this ).remove();
  1324 +
  1325 + // Remove any remaining nodes
  1326 + while ( this.firstChild )
  1327 + this.removeChild( this.firstChild );
  1328 + }
  1329 +}, function(name, fn){
  1330 + jQuery.fn[ name ] = function(){
  1331 + return this.each( fn, arguments );
  1332 + };
  1333 +});
  1334 +
  1335 +jQuery.each([ "Height", "Width" ], function(i, name){
  1336 + var type = name.toLowerCase();
  1337 +
  1338 + jQuery.fn[ type ] = function( size ) {
  1339 + // Get window width or height
  1340 + return this[0] == window ?
  1341 + // Opera reports document.body.client[Width/Height] properly in both quirks and standards
  1342 + jQuery.browser.opera && document.body[ "client" + name ] ||
  1343 +
  1344 + // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
  1345 + jQuery.browser.safari && window[ "inner" + name ] ||
  1346 +
  1347 + // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
  1348 + document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :
  1349 +
  1350 + // Get document width or height
  1351 + this[0] == document ?
  1352 + // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
  1353 + Math.max(
  1354 + Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
  1355 + Math.max(document.body["offset" + name], document.documentElement["offset" + name])
  1356 + ) :
  1357 +
  1358 + // Get or set width or height on the element
  1359 + size == undefined ?
  1360 + // Get width or height on the element
  1361 + (this.length ? jQuery.css( this[0], type ) : null) :
  1362 +
  1363 + // Set the width or height on the element (default to pixels if value is unitless)
  1364 + this.css( type, size.constructor == String ? size : size + "px" );
  1365 + };
  1366 +});
  1367 +
  1368 +// Helper function used by the dimensions and offset modules
  1369 +function num(elem, prop) {
  1370 + return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
  1371 +}var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
  1372 + "(?:[\\w*_-]|\\\\.)" :
  1373 + "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
  1374 + quickChild = new RegExp("^>\\s*(" + chars + "+)"),
  1375 + quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
  1376 + quickClass = new RegExp("^([#.]?)(" + chars + "*)");
  1377 +
  1378 +jQuery.extend({
  1379 + expr: {
  1380 + "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
  1381 + "#": function(a,i,m){return a.getAttribute("id")==m[2];},
  1382 + ":": {
  1383 + // Position Checks
  1384 + lt: function(a,i,m){return i<m[3]-0;},
  1385 + gt: function(a,i,m){return i>m[3]-0;},
  1386 + nth: function(a,i,m){return m[3]-0==i;},
  1387 + eq: function(a,i,m){return m[3]-0==i;},
  1388 + first: function(a,i){return i==0;},
  1389 + last: function(a,i,m,r){return i==r.length-1;},
  1390 + even: function(a,i){return i%2==0;},
  1391 + odd: function(a,i){return i%2;},
  1392 +
  1393 + // Child Checks
  1394 + "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
  1395 + "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
  1396 + "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},
  1397 +
  1398 + // Parent Checks
  1399 + parent: function(a){return a.firstChild;},
  1400 + empty: function(a){return !a.firstChild;},
  1401 +
  1402 + // Text Check
  1403 + contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},
  1404 +
  1405 + // Visibility
  1406 + visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
  1407 + hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},
  1408 +
  1409 + // Form attributes
  1410 + enabled: function(a){return !a.disabled;},
  1411 + disabled: function(a){return a.disabled;},
  1412 + checked: function(a){return a.checked;},
  1413 + selected: function(a){return a.selected||jQuery.attr(a,"selected");},
  1414 +
  1415 + // Form elements
  1416 + text: function(a){return "text"==a.type;},
  1417 + radio: function(a){return "radio"==a.type;},
  1418 + checkbox: function(a){return "checkbox"==a.type;},
  1419 + file: function(a){return "file"==a.type;},
  1420 + password: function(a){return "password"==a.type;},
  1421 + submit: function(a){return "submit"==a.type;},
  1422 + image: function(a){return "image"==a.type;},
  1423 + reset: function(a){return "reset"==a.type;},
  1424 + button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
  1425 + input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},
  1426 +
  1427 + // :has()
  1428 + has: function(a,i,m){return jQuery.find(m[3],a).length;},
  1429 +
  1430 + // :header
  1431 + header: function(a){return /h\d/i.test(a.nodeName);},
  1432 +
  1433 + // :animated
  1434 + animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
  1435 + }
  1436 + },
  1437 +
  1438 + // The regular expressions that power the parsing engine
  1439 + parse: [
  1440 + // Match: [@value='test'], [@foo]
  1441 + /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
  1442 +
  1443 + // Match: :contains('foo')
  1444 + /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
  1445 +
  1446 + // Match: :even, :last-child, #id, .class
  1447 + new RegExp("^([:.#]*)(" + chars + "+)")
  1448 + ],
  1449 +
  1450 + multiFilter: function( expr, elems, not ) {
  1451 + var old, cur = [];
  1452 +
  1453 + while ( expr && expr != old ) {
  1454 + old = expr;
  1455 + var f = jQuery.filter( expr, elems, not );
  1456 + expr = f.t.replace(/^\s*,\s*/, "" );
  1457 + cur = not ? elems = f.r : jQuery.merge( cur, f.r );
  1458 + }
  1459 +
  1460 + return cur;
  1461 + },
  1462 +
  1463 + find: function( t, context ) {
  1464 + // Quickly handle non-string expressions
  1465 + if ( typeof t != "string" )
  1466 + return [ t ];
  1467 +
  1468 + // check to make sure context is a DOM element or a document
  1469 + if ( context && context.nodeType != 1 && context.nodeType != 9)
  1470 + return [ ];
  1471 +
  1472 + // Set the correct context (if none is provided)
  1473 + context = context || document;
  1474 +
  1475 + // Initialize the search
  1476 + var ret = [context], done = [], last, nodeName;
  1477 +
  1478 + // Continue while a selector expression exists, and while
  1479 + // we're no longer looping upon ourselves
  1480 + while ( t && last != t ) {
  1481 + var r = [];
  1482 + last = t;
  1483 +
  1484 + t = jQuery.trim(t);
  1485 +
  1486 + var foundToken = false,
  1487 +
  1488 + // An attempt at speeding up child selectors that
  1489 + // point to a specific element tag
  1490 + re = quickChild,
  1491 +
  1492 + m = re.exec(t);
  1493 +
  1494 + if ( m ) {
  1495 + nodeName = m[1].toUpperCase();
  1496 +
  1497 + // Perform our own iteration and filter
  1498 + for ( var i = 0; ret[i]; i++ )
  1499 + for ( var c = ret[i].firstChild; c; c = c.nextSibling )
  1500 + if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
  1501 + r.push( c );
  1502 +
  1503 + ret = r;
  1504 + t = t.replace( re, "" );
  1505 + if ( t.indexOf(" ") == 0 ) continue;
  1506 + foundToken = true;
  1507 + } else {
  1508 + re = /^([>+~])\s*(\w*)/i;
  1509 +
  1510 + if ( (m = re.exec(t)) != null ) {
  1511 + r = [];
  1512 +
  1513 + var merge = {};
  1514 + nodeName = m[2].toUpperCase();
  1515 + m = m[1];
  1516 +
  1517 + for ( var j = 0, rl = ret.length; j < rl; j++ ) {
  1518 + var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
  1519 + for ( ; n; n = n.nextSibling )
  1520 + if ( n.nodeType == 1 ) {
  1521 + var id = jQuery.data(n);
  1522 +
  1523 + if ( m == "~" && merge[id] ) break;
  1524 +
  1525 + if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
  1526 + if ( m == "~" ) merge[id] = true;
  1527 + r.push( n );
  1528 + }
  1529 +
  1530 + if ( m == "+" ) break;
  1531 + }
  1532 + }
  1533 +
  1534 + ret = r;
  1535 +
  1536 + // And remove the token
  1537 + t = jQuery.trim( t.replace( re, "" ) );
  1538 + foundToken = true;
  1539 + }
  1540 + }
  1541 +
  1542 + // See if there's still an expression, and that we haven't already
  1543 + // matched a token
  1544 + if ( t && !foundToken ) {
  1545 + // Handle multiple expressions
  1546 + if ( !t.indexOf(",") ) {
  1547 + // Clean the result set
  1548 + if ( context == ret[0] ) ret.shift();
  1549 +
  1550 + // Merge the result sets
  1551 + done = jQuery.merge( done, ret );
  1552 +
  1553 + // Reset the context
  1554 + r = ret = [context];
  1555 +
  1556 + // Touch up the selector string
  1557 + t = " " + t.substr(1,t.length);
  1558 +
  1559 + } else {
  1560 + // Optimize for the case nodeName#idName
  1561 + var re2 = quickID;
  1562 + var m = re2.exec(t);
  1563 +
  1564 + // Re-organize the results, so that they're consistent
  1565 + if ( m ) {
  1566 + m = [ 0, m[2], m[3], m[1] ];
  1567 +
  1568 + } else {
  1569 + // Otherwise, do a traditional filter check for
  1570 + // ID, class, and element selectors
  1571 + re2 = quickClass;
  1572 + m = re2.exec(t);
  1573 + }
  1574 +
  1575 + m[2] = m[2].replace(/\\/g, "");
  1576 +
  1577 + var elem = ret[ret.length-1];
  1578 +
  1579 + // Try to do a global search by ID, where we can
  1580 + if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
  1581 + // Optimization for HTML document case
  1582 + var oid = elem.getElementById(m[2]);
  1583 +
  1584 + // Do a quick check for the existence of the actual ID attribute
  1585 + // to avoid selecting by the name attribute in IE
  1586 + // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
  1587 + if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
  1588 + oid = jQuery('[@id="'+m[2]+'"]', elem)[0];
  1589 +
  1590 + // Do a quick check for node name (where applicable) so
  1591 + // that div#foo searches will be really fast
  1592 + ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];
  1593 + } else {
  1594 + // We need to find all descendant elements
  1595 + for ( var i = 0; ret[i]; i++ ) {
  1596 + // Grab the tag name being searched for
  1597 + var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];
  1598 +
  1599 + // Handle IE7 being really dumb about <object>s
  1600 + if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
  1601 + tag = "param";
  1602 +
  1603 + r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
  1604 + }
  1605 +
  1606 + // It's faster to filter by class and be done with it
  1607 + if ( m[1] == "." )
  1608 + r = jQuery.classFilter( r, m[2] );
  1609 +
  1610 + // Same with ID filtering
  1611 + if ( m[1] == "#" ) {
  1612 + var tmp = [];
  1613 +
  1614 + // Try to find the element with the ID
  1615 + for ( var i = 0; r[i]; i++ )
  1616 + if ( r[i].getAttribute("id") == m[2] ) {
  1617 + tmp = [ r[i] ];
  1618 + break;
  1619 + }
  1620 +
  1621 + r = tmp;
  1622 + }
  1623 +
  1624 + ret = r;
  1625 + }
  1626 +
  1627 + t = t.replace( re2, "" );
  1628 + }
  1629 +
  1630 + }
  1631 +
  1632 + // If a selector string still exists
  1633 + if ( t ) {
  1634 + // Attempt to filter it
  1635 + var val = jQuery.filter(t,r);
  1636 + ret = r = val.r;
  1637 + t = jQuery.trim(val.t);
  1638 + }
  1639 + }
  1640 +
  1641 + // An error occurred with the selector;
  1642 + // just return an empty set instead
  1643 + if ( t )
  1644 + ret = [];
  1645 +
  1646 + // Remove the root context
  1647 + if ( ret && context == ret[0] )
  1648 + ret.shift();
  1649 +
  1650 + // And combine the results
  1651 + done = jQuery.merge( done, ret );
  1652 +
  1653 + return done;
  1654 + },
  1655 +
  1656 + classFilter: function(r,m,not){
  1657 + m = " " + m + " ";
  1658 + var tmp = [];
  1659 + for ( var i = 0; r[i]; i++ ) {
  1660 + var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
  1661 + if ( !not && pass || not && !pass )
  1662 + tmp.push( r[i] );
  1663 + }
  1664 + return tmp;
  1665 + },
  1666 +
  1667 + filter: function(t,r,not) {
  1668 + var last;
  1669 +
  1670 + // Look for common filter expressions
  1671 + while ( t && t != last ) {
  1672 + last = t;
  1673 +
  1674 + var p = jQuery.parse, m;
  1675 +
  1676 + for ( var i = 0; p[i]; i++ ) {
  1677 + m = p[i].exec( t );
  1678 +
  1679 + if ( m ) {
  1680 + // Remove what we just matched
  1681 + t = t.substring( m[0].length );
  1682 +
  1683 + m[2] = m[2].replace(/\\/g, "");
  1684 + break;
  1685 + }
  1686 + }
  1687 +
  1688 + if ( !m )
  1689 + break;
  1690 +
  1691 + // :not() is a special case that can be optimized by
  1692 + // keeping it out of the expression list
  1693 + if ( m[1] == ":" && m[2] == "not" )
  1694 + // optimize if only one selector found (most common case)
  1695 + r = isSimple.test( m[3] ) ?
  1696 + jQuery.filter(m[3], r, true).r :
  1697 + jQuery( r ).not( m[3] );
  1698 +
  1699 + // We can get a big speed boost by filtering by class here
  1700 + else if ( m[1] == "." )
  1701 + r = jQuery.classFilter(r, m[2], not);
  1702 +
  1703 + else if ( m[1] == "[" ) {
  1704 + var tmp = [], type = m[3];
  1705 +
  1706 + for ( var i = 0, rl = r.length; i < rl; i++ ) {
  1707 + var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
  1708 +
  1709 + if ( z == null || /href|src|selected/.test(m[2]) )
  1710 + z = jQuery.attr(a,m[2]) || '';
  1711 +
  1712 + if ( (type == "" && !!z ||
  1713 + type == "=" && z == m[5] ||
  1714 + type == "!=" && z != m[5] ||
  1715 + type == "^=" && z && !z.indexOf(m[5]) ||
  1716 + type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
  1717 + (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
  1718 + tmp.push( a );
  1719 + }
  1720 +
  1721 + r = tmp;
  1722 +
  1723 + // We can get a speed boost by handling nth-child here
  1724 + } else if ( m[1] == ":" && m[2] == "nth-child" ) {
  1725 + var merge = {}, tmp = [],
  1726 + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
  1727 + test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
  1728 + m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
  1729 + !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
  1730 + // calculate the numbers (first)n+(last) including if they are negative
  1731 + first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
  1732 +
  1733 + // loop through all the elements left in the jQuery object
  1734 + for ( var i = 0, rl = r.length; i < rl; i++ ) {
  1735 + var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
  1736 +
  1737 + if ( !merge[id] ) {
  1738 + var c = 1;
  1739 +
  1740 + for ( var n = parentNode.firstChild; n; n = n.nextSibling )
  1741 + if ( n.nodeType == 1 )
  1742 + n.nodeIndex = c++;
  1743 +
  1744 + merge[id] = true;
  1745 + }
  1746 +
  1747 + var add = false;
  1748 +
  1749 + if ( first == 0 ) {
  1750 + if ( node.nodeIndex == last )
  1751 + add = true;
  1752 + } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
  1753 + add = true;
  1754 +
  1755 + if ( add ^ not )
  1756 + tmp.push( node );
  1757 + }
  1758 +
  1759 + r = tmp;
  1760 +
  1761 + // Otherwise, find the expression to execute
  1762 + } else {
  1763 + var fn = jQuery.expr[ m[1] ];
  1764 + if ( typeof fn == "object" )
  1765 + fn = fn[ m[2] ];
  1766 +
  1767 + if ( typeof fn == "string" )
  1768 + fn = eval("false||function(a,i){return " + fn + ";}");
  1769 +
  1770 + // Execute it against the current filter
  1771 + r = jQuery.grep( r, function(elem, i){
  1772 + return fn(elem, i, m, r);
  1773 + }, not );
  1774 + }
  1775 + }
  1776 +
  1777 + // Return an array of filtered elements (r)
  1778 + // and the modified expression string (t)
  1779 + return { r: r, t: t };
  1780 + },
  1781 +
  1782 + dir: function( elem, dir ){
  1783 + var matched = [],
  1784 + cur = elem[dir];
  1785 + while ( cur && cur != document ) {
  1786 + if ( cur.nodeType == 1 )
  1787 + matched.push( cur );
  1788 + cur = cur[dir];
  1789 + }
  1790 + return matched;
  1791 + },
  1792 +
  1793 + nth: function(cur,result,dir,elem){
  1794 + result = result || 1;
  1795 + var num = 0;
  1796 +
  1797 + for ( ; cur; cur = cur[dir] )
  1798 + if ( cur.nodeType == 1 && ++num == result )
  1799 + break;
  1800 +
  1801 + return cur;
  1802 + },
  1803 +
  1804 + sibling: function( n, elem ) {
  1805 + var r = [];
  1806 +
  1807 + for ( ; n; n = n.nextSibling ) {
  1808 + if ( n.nodeType == 1 && n != elem )
  1809 + r.push( n );
  1810 + }
  1811 +
  1812 + return r;
  1813 + }
  1814 +});
  1815 +/*
  1816 + * A number of helper functions used for managing events.
  1817 + * Many of the ideas behind this code orignated from
  1818 + * Dean Edwards' addEvent library.
  1819 + */
  1820 +jQuery.event = {
  1821 +
  1822 + // Bind an event to an element
  1823 + // Original by Dean Edwards
  1824 + add: function(elem, types, handler, data) {
  1825 + if ( elem.nodeType == 3 || elem.nodeType == 8 )
  1826 + return;
  1827 +
  1828 + // For whatever reason, IE has trouble passing the window object
  1829 + // around, causing it to be cloned in the process
  1830 + if ( jQuery.browser.msie && elem.setInterval )
  1831 + elem = window;
  1832 +
  1833 + // Make sure that the function being executed has a unique ID
  1834 + if ( !handler.guid )
  1835 + handler.guid = this.guid++;
  1836 +
  1837 + // if data is passed, bind to handler
  1838 + if( data != undefined ) {
  1839 + // Create temporary function pointer to original handler
  1840 + var fn = handler;
  1841 +
  1842 + // Create unique handler function, wrapped around original handler
  1843 + handler = this.proxy( fn, function() {
  1844 + // Pass arguments and context to original handler
  1845 + return fn.apply(this, arguments);
  1846 + });
  1847 +
  1848 + // Store data in unique handler
  1849 + handler.data = data;
  1850 + }
  1851 +
  1852 + // Init the element's event structure
  1853 + var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
  1854 + handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
  1855 + // Handle the second event of a trigger and when
  1856 + // an event is called after a page has unloaded
  1857 + if ( typeof jQuery != "undefined" && !jQuery.event.triggered )
  1858 + return jQuery.event.handle.apply(arguments.callee.elem, arguments);
  1859 + });
  1860 + // Add elem as a property of the handle function
  1861 + // This is to prevent a memory leak with non-native
  1862 + // event in IE.
  1863 + handle.elem = elem;
  1864 +
  1865 + // Handle multiple events separated by a space
  1866 + // jQuery(...).bind("mouseover mouseout", fn);
  1867 + jQuery.each(types.split(/\s+/), function(index, type) {
  1868 + // Namespaced event handlers
  1869 + var parts = type.split(".");
  1870 + type = parts[0];
  1871 + handler.type = parts[1];
  1872 +
  1873 + // Get the current list of functions bound to this event
  1874 + var handlers = events[type];
  1875 +
  1876 + // Init the event handler queue
  1877 + if (!handlers) {
  1878 + handlers = events[type] = {};
  1879 +
  1880 + // Check for a special event handler
  1881 + // Only use addEventListener/attachEvent if the special
  1882 + // events handler returns false
  1883 + if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
  1884 + // Bind the global event handler to the element
  1885 + if (elem.addEventListener)
  1886 + elem.addEventListener(type, handle, false);
  1887 + else if (elem.attachEvent)
  1888 + elem.attachEvent("on" + type, handle);
  1889 + }
  1890 + }
  1891 +
  1892 + // Add the function to the element's handler list
  1893 + handlers[handler.guid] = handler;
  1894 +
  1895 + // Keep track of which events have been used, for global triggering
  1896 + jQuery.event.global[type] = true;
  1897 + });
  1898 +
  1899 + // Nullify elem to prevent memory leaks in IE
  1900 + elem = null;
  1901 + },
  1902 +
  1903 + guid: 1,
  1904 + global: {},
  1905 +
  1906 + // Detach an event or set of events from an element
  1907 + remove: function(elem, types, handler) {
  1908 + // don't do events on text and comment nodes
  1909 + if ( elem.nodeType == 3 || elem.nodeType == 8 )
  1910 + return;
  1911 +
  1912 + var events = jQuery.data(elem, "events"), ret, index;
  1913 +
  1914 + if ( events ) {
  1915 + // Unbind all events for the element
  1916 + if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
  1917 + for ( var type in events )
  1918 + this.remove( elem, type + (types || "") );
  1919 + else {
  1920 + // types is actually an event object here
  1921 + if ( types.type ) {
  1922 + handler = types.handler;
  1923 + types = types.type;
  1924 + }
  1925 +
  1926 + // Handle multiple events seperated by a space
  1927 + // jQuery(...).unbind("mouseover mouseout", fn);
  1928 + jQuery.each(types.split(/\s+/), function(index, type){
  1929 + // Namespaced event handlers
  1930 + var parts = type.split(".");
  1931 + type = parts[0];
  1932 +
  1933 + if ( events[type] ) {
  1934 + // remove the given handler for the given type
  1935 + if ( handler )
  1936 + delete events[type][handler.guid];
  1937 +
  1938 + // remove all handlers for the given type
  1939 + else
  1940 + for ( handler in events[type] )
  1941 + // Handle the removal of namespaced events
  1942 + if ( !parts[1] || events[type][handler].type == parts[1] )
  1943 + delete events[type][handler];
  1944 +
  1945 + // remove generic event handler if no more handlers exist
  1946 + for ( ret in events[type] ) break;
  1947 + if ( !ret ) {
  1948 + if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
  1949 + if (elem.removeEventListener)
  1950 + elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
  1951 + else if (elem.detachEvent)
  1952 + elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
  1953 + }
  1954 + ret = null;
  1955 + delete events[type];
  1956 + }
  1957 + }
  1958 + });
  1959 + }
  1960 +
  1961 + // Remove the expando if it's no longer used
  1962 + for ( ret in events ) break;
  1963 + if ( !ret ) {
  1964 + var handle = jQuery.data( elem, "handle" );
  1965 + if ( handle ) handle.elem = null;
  1966 + jQuery.removeData( elem, "events" );
  1967 + jQuery.removeData( elem, "handle" );
  1968 + }
  1969 + }
  1970 + },
  1971 +
  1972 + trigger: function(type, data, elem, donative, extra) {
  1973 + // Clone the incoming data, if any
  1974 + data = jQuery.makeArray(data);
  1975 +
  1976 + if ( type.indexOf("!") >= 0 ) {
  1977 + type = type.slice(0, -1);
  1978 + var exclusive = true;
  1979 + }
  1980 +
  1981 + // Handle a global trigger
  1982 + if ( !elem ) {
  1983 + // Only trigger if we've ever bound an event for it
  1984 + if ( this.global[type] )
  1985 + jQuery("*").add([window, document]).trigger(type, data);
  1986 +
  1987 + // Handle triggering a single element
  1988 + } else {
  1989 + // don't do events on text and comment nodes
  1990 + if ( elem.nodeType == 3 || elem.nodeType == 8 )
  1991 + return undefined;
  1992 +
  1993 + var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
  1994 + // Check to see if we need to provide a fake event, or not
  1995 + event = !data[0] || !data[0].preventDefault;
  1996 +
  1997 + // Pass along a fake event
  1998 + if ( event ) {
  1999 + data.unshift({
  2000 + type: type,
  2001 + target: elem,
  2002 + preventDefault: function(){},
  2003 + stopPropagation: function(){},
  2004 + timeStamp: now()
  2005 + });
  2006 + data[0][expando] = true; // no need to fix fake event
  2007 + }
  2008 +
  2009 + // Enforce the right trigger type
  2010 + data[0].type = type;
  2011 + if ( exclusive )
  2012 + data[0].exclusive = true;
  2013 +
  2014 + // Trigger the event, it is assumed that "handle" is a function
  2015 + var handle = jQuery.data(elem, "handle");
  2016 + if ( handle )
  2017 + val = handle.apply( elem, data );
  2018 +
  2019 + // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
  2020 + if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
  2021 + val = false;
  2022 +
  2023 + // Extra functions don't get the custom event object
  2024 + if ( event )
  2025 + data.shift();
  2026 +
  2027 + // Handle triggering of extra function
  2028 + if ( extra && jQuery.isFunction( extra ) ) {
  2029 + // call the extra function and tack the current return value on the end for possible inspection
  2030 + ret = extra.apply( elem, val == null ? data : data.concat( val ) );
  2031 + // if anything is returned, give it precedence and have it overwrite the previous value
  2032 + if (ret !== undefined)
  2033 + val = ret;
  2034 + }
  2035 +
  2036 + // Trigger the native events (except for clicks on links)
  2037 + if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
  2038 + this.triggered = true;
  2039 + try {
  2040 + elem[ type ]();
  2041 + // prevent IE from throwing an error for some hidden elements
  2042 + } catch (e) {}
  2043 + }
  2044 +
  2045 + this.triggered = false;
  2046 + }
  2047 +
  2048 + return val;
  2049 + },
  2050 +
  2051 + handle: function(event) {
  2052 + // returned undefined or false
  2053 + var val, ret, namespace, all, handlers;
  2054 +
  2055 + event = arguments[0] = jQuery.event.fix( event || window.event );
  2056 +
  2057 + // Namespaced event handlers
  2058 + namespace = event.type.split(".");
  2059 + event.type = namespace[0];
  2060 + namespace = namespace[1];
  2061 + // Cache this now, all = true means, any handler
  2062 + all = !namespace && !event.exclusive;
  2063 +
  2064 + handlers = ( jQuery.data(this, "events") || {} )[event.type];
  2065 +
  2066 + for ( var j in handlers ) {
  2067 + var handler = handlers[j];
  2068 +
  2069 + // Filter the functions by class
  2070 + if ( all || handler.type == namespace ) {
  2071 + // Pass in a reference to the handler function itself
  2072 + // So that we can later remove it
  2073 + event.handler = handler;
  2074 + event.data = handler.data;
  2075 +
  2076 + ret = handler.apply( this, arguments );
  2077 +
  2078 + if ( val !== false )
  2079 + val = ret;
  2080 +
  2081 + if ( ret === false ) {
  2082 + event.preventDefault();
  2083 + event.stopPropagation();
  2084 + }
  2085 + }
  2086 + }
  2087 +
  2088 + return val;
  2089 + },
  2090 +
  2091 + fix: function(event) {
  2092 + if ( event[expando] == true )
  2093 + return event;
  2094 +
  2095 + // store a copy of the original event object
  2096 + // and "clone" to set read-only properties
  2097 + var originalEvent = event;
  2098 + event = { originalEvent: originalEvent };
  2099 + var props = "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");
  2100 + for ( var i=props.length; i; i-- )
  2101 + event[ props[i] ] = originalEvent[ props[i] ];
  2102 +
  2103 + // Mark it as fixed
  2104 + event[expando] = true;
  2105 +
  2106 + // add preventDefault and stopPropagation since
  2107 + // they will not work on the clone
  2108 + event.preventDefault = function() {
  2109 + // if preventDefault exists run it on the original event
  2110 + if (originalEvent.preventDefault)
  2111 + originalEvent.preventDefault();
  2112 + // otherwise set the returnValue property of the original event to false (IE)
  2113 + originalEvent.returnValue = false;
  2114 + };
  2115 + event.stopPropagation = function() {
  2116 + // if stopPropagation exists run it on the original event
  2117 + if (originalEvent.stopPropagation)
  2118 + originalEvent.stopPropagation();
  2119 + // otherwise set the cancelBubble property of the original event to true (IE)
  2120 + originalEvent.cancelBubble = true;
  2121 + };
  2122 +
  2123 + // Fix timeStamp
  2124 + event.timeStamp = event.timeStamp || now();
  2125 +
  2126 + // Fix target property, if necessary
  2127 + if ( !event.target )
  2128 + event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
  2129 +
  2130 + // check if target is a textnode (safari)
  2131 + if ( event.target.nodeType == 3 )
  2132 + event.target = event.target.parentNode;
  2133 +
  2134 + // Add relatedTarget, if necessary
  2135 + if ( !event.relatedTarget && event.fromElement )
  2136 + event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
  2137 +
  2138 + // Calculate pageX/Y if missing and clientX/Y available
  2139 + if ( event.pageX == null && event.clientX != null ) {
  2140 + var doc = document.documentElement, body = document.body;
  2141 + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
  2142 + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
  2143 + }
  2144 +
  2145 + // Add which for key events
  2146 + if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
  2147 + event.which = event.charCode || event.keyCode;
  2148 +
  2149 + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
  2150 + if ( !event.metaKey && event.ctrlKey )
  2151 + event.metaKey = event.ctrlKey;
  2152 +
  2153 + // Add which for click: 1 == left; 2 == middle; 3 == right
  2154 + // Note: button is not normalized, so don't use it
  2155 + if ( !event.which && event.button )
  2156 + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
  2157 +
  2158 + return event;
  2159 + },
  2160 +
  2161 + proxy: function( fn, proxy ){
  2162 + // Set the guid of unique handler to the same of original handler, so it can be removed
  2163 + proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
  2164 + // So proxy can be declared as an argument
  2165 + return proxy;
  2166 + },
  2167 +
  2168 + special: {
  2169 + ready: {
  2170 + setup: function() {
  2171 + // Make sure the ready event is setup
  2172 + bindReady();
  2173 + return;
  2174 + },
  2175 +
  2176 + teardown: function() { return; }
  2177 + },
  2178 +
  2179 + mouseenter: {
  2180 + setup: function() {
  2181 + if ( jQuery.browser.msie ) return false;
  2182 + jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
  2183 + return true;
  2184 + },
  2185 +
  2186 + teardown: function() {
  2187 + if ( jQuery.browser.msie ) return false;
  2188 + jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
  2189 + return true;
  2190 + },
  2191 +
  2192 + handler: function(event) {
  2193 + // If we actually just moused on to a sub-element, ignore it
  2194 + if ( withinElement(event, this) ) return true;
  2195 + // Execute the right handlers by setting the event type to mouseenter
  2196 + event.type = "mouseenter";
  2197 + return jQuery.event.handle.apply(this, arguments);
  2198 + }
  2199 + },
  2200 +
  2201 + mouseleave: {
  2202 + setup: function() {
  2203 + if ( jQuery.browser.msie ) return false;
  2204 + jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
  2205 + return true;
  2206 + },
  2207 +
  2208 + teardown: function() {
  2209 + if ( jQuery.browser.msie ) return false;
  2210 + jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
  2211 + return true;
  2212 + },
  2213 +
  2214 + handler: function(event) {
  2215 + // If we actually just moused on to a sub-element, ignore it
  2216 + if ( withinElement(event, this) ) return true;
  2217 + // Execute the right handlers by setting the event type to mouseleave
  2218 + event.type = "mouseleave";
  2219 + return jQuery.event.handle.apply(this, arguments);
  2220 + }
  2221 + }
  2222 + }
  2223 +};
  2224 +
  2225 +jQuery.fn.extend({
  2226 + bind: function( type, data, fn ) {
  2227 + return type == "unload" ? this.one(type, data, fn) : this.each(function(){
  2228 + jQuery.event.add( this, type, fn || data, fn && data );
  2229 + });
  2230 + },
  2231 +
  2232 + one: function( type, data, fn ) {
  2233 + var one = jQuery.event.proxy( fn || data, function(event) {
  2234 + jQuery(this).unbind(event, one);
  2235 + return (fn || data).apply( this, arguments );
  2236 + });
  2237 + return this.each(function(){
  2238 + jQuery.event.add( this, type, one, fn && data);
  2239 + });
  2240 + },
  2241 +
  2242 + unbind: function( type, fn ) {
  2243 + return this.each(function(){
  2244 + jQuery.event.remove( this, type, fn );
  2245 + });
  2246 + },
  2247 +
  2248 + trigger: function( type, data, fn ) {
  2249 + return this.each(function(){
  2250 + jQuery.event.trigger( type, data, this, true, fn );
  2251 + });
  2252 + },
  2253 +
  2254 + triggerHandler: function( type, data, fn ) {
  2255 + return this[0] && jQuery.event.trigger( type, data, this[0], false, fn );
  2256 + },
  2257 +
  2258 + toggle: function( fn ) {
  2259 + // Save reference to arguments for access in closure
  2260 + var args = arguments, i = 1;
  2261 +
  2262 + // link all the functions, so any of them can unbind this click handler
  2263 + while( i < args.length )
  2264 + jQuery.event.proxy( fn, args[i++] );
  2265 +
  2266 + return this.click( jQuery.event.proxy( fn, function(event) {
  2267 + // Figure out which function to execute
  2268 + this.lastToggle = ( this.lastToggle || 0 ) % i;
  2269 +
  2270 + // Make sure that clicks stop
  2271 + event.preventDefault();
  2272 +
  2273 + // and execute the function
  2274 + return args[ this.lastToggle++ ].apply( this, arguments ) || false;
  2275 + }));
  2276 + },
  2277 +
  2278 + hover: function(fnOver, fnOut) {
  2279 + return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
  2280 + },
  2281 +
  2282 + ready: function(fn) {
  2283 + // Attach the listeners
  2284 + bindReady();
  2285 +
  2286 + // If the DOM is already ready
  2287 + if ( jQuery.isReady )
  2288 + // Execute the function immediately
  2289 + fn.call( document, jQuery );
  2290 +
  2291 + // Otherwise, remember the function for later
  2292 + else
  2293 + // Add the function to the wait list
  2294 + jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
  2295 +
  2296 + return this;
  2297 + }
  2298 +});
  2299 +
  2300 +jQuery.extend({
  2301 + isReady: false,
  2302 + readyList: [],
  2303 + // Handle when the DOM is ready
  2304 + ready: function() {
  2305 + // Make sure that the DOM is not already loaded
  2306 + if ( !jQuery.isReady ) {
  2307 + // Remember that the DOM is ready
  2308 + jQuery.isReady = true;
  2309 +
  2310 + // If there are functions bound, to execute
  2311 + if ( jQuery.readyList ) {
  2312 + // Execute all of them
  2313 + jQuery.each( jQuery.readyList, function(){
  2314 + this.call( document );
  2315 + });
  2316 +
  2317 + // Reset the list of functions
  2318 + jQuery.readyList = null;
  2319 + }
  2320 +
  2321 + // Trigger any bound ready events
  2322 + jQuery(document).triggerHandler("ready");
  2323 + }
  2324 + }
  2325 +});
  2326 +
  2327 +var readyBound = false;
  2328 +
  2329 +function bindReady(){
  2330 + if ( readyBound ) return;
  2331 + readyBound = true;
  2332 +
  2333 + // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
  2334 + if ( document.addEventListener && !jQuery.browser.opera)
  2335 + // Use the handy event callback
  2336 + document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
  2337 +
  2338 + // If IE is used and is not in a frame
  2339 + // Continually check to see if the document is ready
  2340 + if ( jQuery.browser.msie && window == top ) (function(){
  2341 + if (jQuery.isReady) return;
  2342 + try {
  2343 + // If IE is used, use the trick by Diego Perini
  2344 + // http://javascript.nwbox.com/IEContentLoaded/
  2345 + document.documentElement.doScroll("left");
  2346 + } catch( error ) {
  2347 + setTimeout( arguments.callee, 0 );
  2348 + return;
  2349 + }
  2350 + // and execute any waiting functions
  2351 + jQuery.ready();
  2352 + })();
  2353 +
  2354 + if ( jQuery.browser.opera )
  2355 + document.addEventListener( "DOMContentLoaded", function () {
  2356 + if (jQuery.isReady) return;
  2357 + for (var i = 0; i < document.styleSheets.length; i++)
  2358 + if (document.styleSheets[i].disabled) {
  2359 + setTimeout( arguments.callee, 0 );
  2360 + return;
  2361 + }
  2362 + // and execute any waiting functions
  2363 + jQuery.ready();
  2364 + }, false);
  2365 +
  2366 + if ( jQuery.browser.safari ) {
  2367 + var numStyles;
  2368 + (function(){
  2369 + if (jQuery.isReady) return;
  2370 + if ( document.readyState != "loaded" && document.readyState != "complete" ) {
  2371 + setTimeout( arguments.callee, 0 );
  2372 + return;
  2373 + }
  2374 + if ( numStyles === undefined )
  2375 + numStyles = jQuery("style, link[rel=stylesheet]").length;
  2376 + if ( document.styleSheets.length != numStyles ) {
  2377 + setTimeout( arguments.callee, 0 );
  2378 + return;
  2379 + }
  2380 + // and execute any waiting functions
  2381 + jQuery.ready();
  2382 + })();
  2383 + }
  2384 +
  2385 + // A fallback to window.onload, that will always work
  2386 + jQuery.event.add( window, "load", jQuery.ready );
  2387 +}
  2388 +
  2389 +jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
  2390 + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
  2391 + "submit,keydown,keypress,keyup,error").split(","), function(i, name){
  2392 +
  2393 + // Handle event binding
  2394 + jQuery.fn[name] = function(fn){
  2395 + return fn ? this.bind(name, fn) : this.trigger(name);
  2396 + };
  2397 +});
  2398 +
  2399 +// Checks if an event happened on an element within another element
  2400 +// Used in jQuery.event.special.mouseenter and mouseleave handlers
  2401 +var withinElement = function(event, elem) {
  2402 + // Check if mouse(over|out) are still within the same parent element
  2403 + var parent = event.relatedTarget;
  2404 + // Traverse up the tree
  2405 + while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
  2406 + // Return true if we actually just moused on to a sub-element
  2407 + return parent == elem;
  2408 +};
  2409 +
  2410 +// Prevent memory leaks in IE
  2411 +// And prevent errors on refresh with events like mouseover in other browsers
  2412 +// Window isn't included so as not to unbind existing unload events
  2413 +jQuery(window).bind("unload", function() {
  2414 + jQuery("*").add(document).unbind();
  2415 +});
  2416 +jQuery.fn.extend({
  2417 + // Keep a copy of the old load
  2418 + _load: jQuery.fn.load,
  2419 +
  2420 + load: function( url, params, callback ) {
  2421 + if ( typeof url != 'string' )
  2422 + return this._load( url );
  2423 +
  2424 + var off = url.indexOf(" ");
  2425 + if ( off >= 0 ) {
  2426 + var selector = url.slice(off, url.length);
  2427 + url = url.slice(0, off);
  2428 + }
  2429 +
  2430 + callback = callback || function(){};
  2431 +
  2432 + // Default to a GET request
  2433 + var type = "GET";
  2434 +
  2435 + // If the second parameter was provided
  2436 + if ( params )
  2437 + // If it's a function
  2438 + if ( jQuery.isFunction( params ) ) {
  2439 + // We assume that it's the callback
  2440 + callback = params;
  2441 + params = null;
  2442 +
  2443 + // Otherwise, build a param string
  2444 + } else {
  2445 + params = jQuery.param( params );
  2446 + type = "POST";
  2447 + }
  2448 +
  2449 + var self = this;
  2450 +
  2451 + // Request the remote document
  2452 + jQuery.ajax({
  2453 + url: url,
  2454 + type: type,
  2455 + dataType: "html",
  2456 + data: params,
  2457 + complete: function(res, status){
  2458 + // If successful, inject the HTML into all the matched elements
  2459 + if ( status == "success" || status == "notmodified" )
  2460 + // See if a selector was specified
  2461 + self.html( selector ?
  2462 + // Create a dummy div to hold the results
  2463 + jQuery("<div/>")
  2464 + // inject the contents of the document in, removing the scripts
  2465 + // to avoid any 'Permission Denied' errors in IE
  2466 + .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
  2467 +
  2468 + // Locate the specified elements
  2469 + .find(selector) :
  2470 +
  2471 + // If not, just inject the full result
  2472 + res.responseText );
  2473 +
  2474 + self.each( callback, [res.responseText, status, res] );
  2475 + }
  2476 + });
  2477 + return this;
  2478 + },
  2479 +
  2480 + serialize: function() {
  2481 + return jQuery.param(this.serializeArray());
  2482 + },
  2483 + serializeArray: function() {
  2484 + return this.map(function(){
  2485 + return jQuery.nodeName(this, "form") ?
  2486 + jQuery.makeArray(this.elements) : this;
  2487 + })
  2488 + .filter(function(){
  2489 + return this.name && !this.disabled &&
  2490 + (this.checked || /select|textarea/i.test(this.nodeName) ||
  2491 + /text|hidden|password/i.test(this.type));
  2492 + })
  2493 + .map(function(i, elem){
  2494 + var val = jQuery(this).val();
  2495 + return val == null ? null :
  2496 + val.constructor == Array ?
  2497 + jQuery.map( val, function(val, i){
  2498 + return {name: elem.name, value: val};
  2499 + }) :
  2500 + {name: elem.name, value: val};
  2501 + }).get();
  2502 + }
  2503 +});
  2504 +
  2505 +// Attach a bunch of functions for handling common AJAX events
  2506 +jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
  2507 + jQuery.fn[o] = function(f){
  2508 + return this.bind(o, f);
  2509 + };
  2510 +});
  2511 +
  2512 +var jsc = now();
  2513 +
  2514 +jQuery.extend({
  2515 + get: function( url, data, callback, type ) {
  2516 + // shift arguments if data argument was ommited
  2517 + if ( jQuery.isFunction( data ) ) {
  2518 + callback = data;
  2519 + data = null;
  2520 + }
  2521 +
  2522 + return jQuery.ajax({
  2523 + type: "GET",
  2524 + url: url,
  2525 + data: data,
  2526 + success: callback,
  2527 + dataType: type
  2528 + });
  2529 + },
  2530 +
  2531 + getScript: function( url, callback ) {
  2532 + return jQuery.get(url, null, callback, "script");
  2533 + },
  2534 +
  2535 + getJSON: function( url, data, callback ) {
  2536 + return jQuery.get(url, data, callback, "json");
  2537 + },
  2538 +
  2539 + post: function( url, data, callback, type ) {
  2540 + if ( jQuery.isFunction( data ) ) {
  2541 + callback = data;
  2542 + data = {};
  2543 + }
  2544 +
  2545 + return jQuery.ajax({
  2546 + type: "POST",
  2547 + url: url,
  2548 + data: data,
  2549 + success: callback,
  2550 + dataType: type
  2551 + });
  2552 + },
  2553 +
  2554 + ajaxSetup: function( settings ) {
  2555 + jQuery.extend( jQuery.ajaxSettings, settings );
  2556 + },
  2557 +
  2558 + ajaxSettings: {
  2559 + url: location.href,
  2560 + global: true,
  2561 + type: "GET",
  2562 + timeout: 0,
  2563 + contentType: "application/x-www-form-urlencoded",
  2564 + processData: true,
  2565 + async: true,
  2566 + data: null,
  2567 + username: null,
  2568 + password: null,
  2569 + accepts: {
  2570 + xml: "application/xml, text/xml",
  2571 + html: "text/html",
  2572 + script: "text/javascript, application/javascript",
  2573 + json: "application/json, text/javascript",
  2574 + text: "text/plain",
  2575 + _default: "*/*"
  2576 + }
  2577 + },
  2578 +
  2579 + // Last-Modified header cache for next request
  2580 + lastModified: {},
  2581 +
  2582 + ajax: function( s ) {
  2583 + // Extend the settings, but re-extend 's' so that it can be
  2584 + // checked again later (in the test suite, specifically)
  2585 + s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
  2586 +
  2587 + var jsonp, jsre = /=\?(&|$)/g, status, data,
  2588 + type = s.type.toUpperCase();
  2589 +
  2590 + // convert data if not already a string
  2591 + if ( s.data && s.processData && typeof s.data != "string" )
  2592 + s.data = jQuery.param(s.data);
  2593 +
  2594 + // Handle JSONP Parameter Callbacks
  2595 + if ( s.dataType == "jsonp" ) {
  2596 + if ( type == "GET" ) {
  2597 + if ( !s.url.match(jsre) )
  2598 + s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
  2599 + } else if ( !s.data || !s.data.match(jsre) )
  2600 + s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
  2601 + s.dataType = "json";
  2602 + }
  2603 +
  2604 + // Build temporary JSONP function
  2605 + if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
  2606 + jsonp = "jsonp" + jsc++;
  2607 +
  2608 + // Replace the =? sequence both in the query string and the data
  2609 + if ( s.data )
  2610 + s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
  2611 + s.url = s.url.replace(jsre, "=" + jsonp + "$1");
  2612 +
  2613 + // We need to make sure
  2614 + // that a JSONP style response is executed properly
  2615 + s.dataType = "script";
  2616 +
  2617 + // Handle JSONP-style loading
  2618 + window[ jsonp ] = function(tmp){
  2619 + data = tmp;
  2620 + success();
  2621 + complete();
  2622 + // Garbage collect
  2623 + window[ jsonp ] = undefined;
  2624 + try{ delete window[ jsonp ]; } catch(e){}
  2625 + if ( head )
  2626 + head.removeChild( script );
  2627 + };
  2628 + }
  2629 +
  2630 + if ( s.dataType == "script" && s.cache == null )
  2631 + s.cache = false;
  2632 +
  2633 + if ( s.cache === false && type == "GET" ) {
  2634 + var ts = now();
  2635 + // try replacing _= if it is there
  2636 + var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
  2637 + // if nothing was replaced, add timestamp to the end
  2638 + s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
  2639 + }
  2640 +
  2641 + // If data is available, append data to url for get requests
  2642 + if ( s.data && type == "GET" ) {
  2643 + s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
  2644 +
  2645 + // IE likes to send both get and post data, prevent this
  2646 + s.data = null;
  2647 + }
  2648 +
  2649 + // Watch for a new set of requests
  2650 + if ( s.global && ! jQuery.active++ )
  2651 + jQuery.event.trigger( "ajaxStart" );
  2652 +
  2653 + // Matches an absolute URL, and saves the domain
  2654 + var remote = /^(?:\w+:)?\/\/([^\/?#]+)/;
  2655 +
  2656 + // If we're requesting a remote document
  2657 + // and trying to load JSON or Script with a GET
  2658 + if ( s.dataType == "script" && type == "GET"
  2659 + && remote.test(s.url) && remote.exec(s.url)[1] != location.host ){
  2660 + var head = document.getElementsByTagName("head")[0];
  2661 + var script = document.createElement("script");
  2662 + script.src = s.url;
  2663 + if (s.scriptCharset)
  2664 + script.charset = s.scriptCharset;
  2665 +
  2666 + // Handle Script loading
  2667 + if ( !jsonp ) {
  2668 + var done = false;
  2669 +
  2670 + // Attach handlers for all browsers
  2671 + script.onload = script.onreadystatechange = function(){
  2672 + if ( !done && (!this.readyState ||
  2673 + this.readyState == "loaded" || this.readyState == "complete") ) {
  2674 + done = true;
  2675 + success();
  2676 + complete();
  2677 + head.removeChild( script );
  2678 + }
  2679 + };
  2680 + }
  2681 +
  2682 + head.appendChild(script);
  2683 +
  2684 + // We handle everything using the script element injection
  2685 + return undefined;
  2686 + }
  2687 +
  2688 + var requestDone = false;
  2689 +
  2690 + // Create the request object; Microsoft failed to properly
  2691 + // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
  2692 + var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
  2693 +
  2694 + // Open the socket
  2695 + // Passing null username, generates a login popup on Opera (#2865)
  2696 + if( s.username )
  2697 + xhr.open(type, s.url, s.async, s.username, s.password);
  2698 + else
  2699 + xhr.open(type, s.url, s.async);
  2700 +
  2701 + // Need an extra try/catch for cross domain requests in Firefox 3
  2702 + try {
  2703 + // Set the correct header, if data is being sent
  2704 + if ( s.data )
  2705 + xhr.setRequestHeader("Content-Type", s.contentType);
  2706 +
  2707 + // Set the If-Modified-Since header, if ifModified mode.
  2708 + if ( s.ifModified )
  2709 + xhr.setRequestHeader("If-Modified-Since",
  2710 + jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
  2711 +
  2712 + // Set header so the called script knows that it's an XMLHttpRequest
  2713 + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  2714 +
  2715 + // Set the Accepts header for the server, depending on the dataType
  2716 + xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
  2717 + s.accepts[ s.dataType ] + ", */*" :
  2718 + s.accepts._default );
  2719 + } catch(e){}
  2720 +
  2721 + // Allow custom headers/mimetypes
  2722 + if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
  2723 + // cleanup active request counter
  2724 + s.global && jQuery.active--;
  2725 + // close opended socket
  2726 + xhr.abort();
  2727 + return false;
  2728 + }
  2729 +
  2730 + if ( s.global )
  2731 + jQuery.event.trigger("ajaxSend", [xhr, s]);
  2732 +
  2733 + // Wait for a response to come back
  2734 + var onreadystatechange = function(isTimeout){
  2735 + // The transfer is complete and the data is available, or the request timed out
  2736 + if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
  2737 + requestDone = true;
  2738 +
  2739 + // clear poll interval
  2740 + if (ival) {
  2741 + clearInterval(ival);
  2742 + ival = null;
  2743 + }
  2744 +
  2745 + status = isTimeout == "timeout" && "timeout" ||
  2746 + !jQuery.httpSuccess( xhr ) && "error" ||
  2747 + s.ifModified && jQuery.httpNotModified( xhr, s.url ) && "notmodified" ||
  2748 + "success";
  2749 +
  2750 + if ( status == "success" ) {
  2751 + // Watch for, and catch, XML document parse errors
  2752 + try {
  2753 + // process the data (runs the xml through httpData regardless of callback)
  2754 + data = jQuery.httpData( xhr, s.dataType, s.dataFilter );
  2755 + } catch(e) {
  2756 + status = "parsererror";
  2757 + }
  2758 + }
  2759 +
  2760 + // Make sure that the request was successful or notmodified
  2761 + if ( status == "success" ) {
  2762 + // Cache Last-Modified header, if ifModified mode.
  2763 + var modRes;
  2764 + try {
  2765 + modRes = xhr.getResponseHeader("Last-Modified");
  2766 + } catch(e) {} // swallow exception thrown by FF if header is not available
  2767 +
  2768 + if ( s.ifModified && modRes )
  2769 + jQuery.lastModified[s.url] = modRes;
  2770 +
  2771 + // JSONP handles its own success callback
  2772 + if ( !jsonp )
  2773 + success();
  2774 + } else
  2775 + jQuery.handleError(s, xhr, status);
  2776 +
  2777 + // Fire the complete handlers
  2778 + complete();
  2779 +
  2780 + // Stop memory leaks
  2781 + if ( s.async )
  2782 + xhr = null;
  2783 + }
  2784 + };
  2785 +
  2786 + if ( s.async ) {
  2787 + // don't attach the handler to the request, just poll it instead
  2788 + var ival = setInterval(onreadystatechange, 13);
  2789 +
  2790 + // Timeout checker
  2791 + if ( s.timeout > 0 )
  2792 + setTimeout(function(){
  2793 + // Check to see if the request is still happening
  2794 + if ( xhr ) {
  2795 + // Cancel the request
  2796 + xhr.abort();
  2797 +
  2798 + if( !requestDone )
  2799 + onreadystatechange( "timeout" );
  2800 + }
  2801 + }, s.timeout);
  2802 + }
  2803 +
  2804 + // Send the data
  2805 + try {
  2806 + xhr.send(s.data);
  2807 + } catch(e) {
  2808 + jQuery.handleError(s, xhr, null, e);
  2809 + }
  2810 +
  2811 + // firefox 1.5 doesn't fire statechange for sync requests
  2812 + if ( !s.async )
  2813 + onreadystatechange();
  2814 +
  2815 + function success(){
  2816 + // If a local callback was specified, fire it and pass it the data
  2817 + if ( s.success )
  2818 + s.success( data, status );
  2819 +
  2820 + // Fire the global callback
  2821 + if ( s.global )
  2822 + jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
  2823 + }
  2824 +
  2825 + function complete(){
  2826 + // Process result
  2827 + if ( s.complete )
  2828 + s.complete(xhr, status);
  2829 +
  2830 + // The request was completed
  2831 + if ( s.global )
  2832 + jQuery.event.trigger( "ajaxComplete", [xhr, s] );
  2833 +
  2834 + // Handle the global AJAX counter
  2835 + if ( s.global && ! --jQuery.active )
  2836 + jQuery.event.trigger( "ajaxStop" );
  2837 + }
  2838 +
  2839 + // return XMLHttpRequest to allow aborting the request etc.
  2840 + return xhr;
  2841 + },
  2842 +
  2843 + handleError: function( s, xhr, status, e ) {
  2844 + // If a local callback was specified, fire it
  2845 + if ( s.error ) s.error( xhr, status, e );
  2846 +
  2847 + // Fire the global callback
  2848 + if ( s.global )
  2849 + jQuery.event.trigger( "ajaxError", [xhr, s, e] );
  2850 + },
  2851 +
  2852 + // Counter for holding the number of active queries
  2853 + active: 0,
  2854 +
  2855 + // Determines if an XMLHttpRequest was successful or not
  2856 + httpSuccess: function( xhr ) {
  2857 + try {
  2858 + // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
  2859 + return !xhr.status && location.protocol == "file:" ||
  2860 + ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223 ||
  2861 + jQuery.browser.safari && xhr.status == undefined;
  2862 + } catch(e){}
  2863 + return false;
  2864 + },
  2865 +
  2866 + // Determines if an XMLHttpRequest returns NotModified
  2867 + httpNotModified: function( xhr, url ) {
  2868 + try {
  2869 + var xhrRes = xhr.getResponseHeader("Last-Modified");
  2870 +
  2871 + // Firefox always returns 200. check Last-Modified date
  2872 + return xhr.status == 304 || xhrRes == jQuery.lastModified[url] ||
  2873 + jQuery.browser.safari && xhr.status == undefined;
  2874 + } catch(e){}
  2875 + return false;
  2876 + },
  2877 +
  2878 + httpData: function( xhr, type, filter ) {
  2879 + var ct = xhr.getResponseHeader("content-type"),
  2880 + xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
  2881 + data = xml ? xhr.responseXML : xhr.responseText;
  2882 +
  2883 + if ( xml && data.documentElement.tagName == "parsererror" )
  2884 + throw "parsererror";
  2885 +
  2886 + // Allow a pre-filtering function to sanitize the response
  2887 + if( filter )
  2888 + data = filter( data, type );
  2889 +
  2890 + // If the type is "script", eval it in global context
  2891 + if ( type == "script" )
  2892 + jQuery.globalEval( data );
  2893 +
  2894 + // Get the JavaScript object, if JSON is used.
  2895 + if ( type == "json" )
  2896 + data = eval("(" + data + ")");
  2897 +
  2898 + return data;
  2899 + },
  2900 +
  2901 + // Serialize an array of form elements or a set of
  2902 + // key/values into a query string
  2903 + param: function( a ) {
  2904 + var s = [];
  2905 +
  2906 + // If an array was passed in, assume that it is an array
  2907 + // of form elements
  2908 + if ( a.constructor == Array || a.jquery )
  2909 + // Serialize the form elements
  2910 + jQuery.each( a, function(){
  2911 + s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );
  2912 + });
  2913 +
  2914 + // Otherwise, assume that it's an object of key/value pairs
  2915 + else
  2916 + // Serialize the key/values
  2917 + for ( var j in a )
  2918 + // If the value is an array then the key names need to be repeated
  2919 + if ( a[j] && a[j].constructor == Array )
  2920 + jQuery.each( a[j], function(){
  2921 + s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );
  2922 + });
  2923 + else
  2924 + s.push( encodeURIComponent(j) + "=" + encodeURIComponent( jQuery.isFunction(a[j]) ? a[j]() : a[j] ) );
  2925 +
  2926 + // Return the resulting serialization
  2927 + return s.join("&").replace(/%20/g, "+");
  2928 + }
  2929 +
  2930 +});
  2931 +jQuery.fn.extend({
  2932 + show: function(speed,callback){
  2933 + return speed ?
  2934 + this.animate({
  2935 + height: "show", width: "show", opacity: "show"
  2936 + }, speed, callback) :
  2937 +
  2938 + this.filter(":hidden").each(function(){
  2939 + this.style.display = this.oldblock || "";
  2940 + if ( jQuery.css(this,"display") == "none" ) {
  2941 + var elem = jQuery("<" + this.tagName + " />").appendTo("body");
  2942 + this.style.display = elem.css("display");
  2943 + // handle an edge condition where css is - div { display:none; } or similar
  2944 + if (this.style.display == "none")
  2945 + this.style.display = "block";
  2946 + elem.remove();
  2947 + }
  2948 + }).end();
  2949 + },
  2950 +
  2951 + hide: function(speed,callback){
  2952 + return speed ?
  2953 + this.animate({
  2954 + height: "hide", width: "hide", opacity: "hide"
  2955 + }, speed, callback) :
  2956 +
  2957 + this.filter(":visible").each(function(){
  2958 + this.oldblock = this.oldblock || jQuery.css(this,"display");
  2959 + this.style.display = "none";
  2960 + }).end();
  2961 + },
  2962 +
  2963 + // Save the old toggle function
  2964 + _toggle: jQuery.fn.toggle,
  2965 +
  2966 + toggle: function( fn, fn2 ){
  2967 + return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
  2968 + this._toggle.apply( this, arguments ) :
  2969 + fn ?
  2970 + this.animate({
  2971 + height: "toggle", width: "toggle", opacity: "toggle"
  2972 + }, fn, fn2) :
  2973 + this.each(function(){
  2974 + jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
  2975 + });
  2976 + },
  2977 +
  2978 + slideDown: function(speed,callback){
  2979 + return this.animate({height: "show"}, speed, callback);
  2980 + },
  2981 +
  2982 + slideUp: function(speed,callback){
  2983 + return this.animate({height: "hide"}, speed, callback);
  2984 + },
  2985 +
  2986 + slideToggle: function(speed, callback){
  2987 + return this.animate({height: "toggle"}, speed, callback);
  2988 + },
  2989 +
  2990 + fadeIn: function(speed, callback){
  2991 + return this.animate({opacity: "show"}, speed, callback);
  2992 + },
  2993 +
  2994 + fadeOut: function(speed, callback){
  2995 + return this.animate({opacity: "hide"}, speed, callback);
  2996 + },
  2997 +
  2998 + fadeTo: function(speed,to,callback){
  2999 + return this.animate({opacity: to}, speed, callback);
  3000 + },
  3001 +
  3002 + animate: function( prop, speed, easing, callback ) {
  3003 + var optall = jQuery.speed(speed, easing, callback);
  3004 +
  3005 + return this[ optall.queue === false ? "each" : "queue" ](function(){
  3006 + if ( this.nodeType != 1)
  3007 + return false;
  3008 +
  3009 + var opt = jQuery.extend({}, optall), p,
  3010 + hidden = jQuery(this).is(":hidden"), self = this;
  3011 +
  3012 + for ( p in prop ) {
  3013 + if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
  3014 + return opt.complete.call(this);
  3015 +
  3016 + if ( p == "height" || p == "width" ) {
  3017 + // Store display property
  3018 + opt.display = jQuery.css(this, "display");
  3019 +
  3020 + // Make sure that nothing sneaks out
  3021 + opt.overflow = this.style.overflow;
  3022 + }
  3023 + }
  3024 +
  3025 + if ( opt.overflow != null )
  3026 + this.style.overflow = "hidden";
  3027 +
  3028 + opt.curAnim = jQuery.extend({}, prop);
  3029 +
  3030 + jQuery.each( prop, function(name, val){
  3031 + var e = new jQuery.fx( self, opt, name );
  3032 +
  3033 + if ( /toggle|show|hide/.test(val) )
  3034 + e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
  3035 + else {
  3036 + var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
  3037 + start = e.cur(true) || 0;
  3038 +
  3039 + if ( parts ) {
  3040 + var end = parseFloat(parts[2]),
  3041 + unit = parts[3] || "px";
  3042 +
  3043 + // We need to compute starting value
  3044 + if ( unit != "px" ) {
  3045 + self.style[ name ] = (end || 1) + unit;
  3046 + start = ((end || 1) / e.cur(true)) * start;
  3047 + self.style[ name ] = start + unit;
  3048 + }
  3049 +
  3050 + // If a +=/-= token was provided, we're doing a relative animation
  3051 + if ( parts[1] )
  3052 + end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
  3053 +
  3054 + e.custom( start, end, unit );
  3055 + } else
  3056 + e.custom( start, val, "" );
  3057 + }
  3058 + });
  3059 +
  3060 + // For JS strict compliance
  3061 + return true;
  3062 + });
  3063 + },
  3064 +
  3065 + queue: function(type, fn){
  3066 + if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
  3067 + fn = type;
  3068 + type = "fx";
  3069 + }
  3070 +
  3071 + if ( !type || (typeof type == "string" && !fn) )
  3072 + return queue( this[0], type );
  3073 +
  3074 + return this.each(function(){
  3075 + if ( fn.constructor == Array )
  3076 + queue(this, type, fn);
  3077 + else {
  3078 + queue(this, type).push( fn );
  3079 +
  3080 + if ( queue(this, type).length == 1 )
  3081 + fn.call(this);
  3082 + }
  3083 + });
  3084 + },
  3085 +
  3086 + stop: function(clearQueue, gotoEnd){
  3087 + var timers = jQuery.timers;
  3088 +
  3089 + if (clearQueue)
  3090 + this.queue([]);
  3091 +
  3092 + this.each(function(){
  3093 + // go in reverse order so anything added to the queue during the loop is ignored
  3094 + for ( var i = timers.length - 1; i >= 0; i-- )
  3095 + if ( timers[i].elem == this ) {
  3096 + if (gotoEnd)
  3097 + // force the next step to be the last
  3098 + timers[i](true);
  3099 + timers.splice(i, 1);
  3100 + }
  3101 + });
  3102 +
  3103 + // start the next in the queue if the last step wasn't forced
  3104 + if (!gotoEnd)
  3105 + this.dequeue();
  3106 +
  3107 + return this;
  3108 + }
  3109 +
  3110 +});
  3111 +
  3112 +var queue = function( elem, type, array ) {
  3113 + if ( elem ){
  3114 +
  3115 + type = type || "fx";
  3116 +
  3117 + var q = jQuery.data( elem, type + "queue" );
  3118 +
  3119 + if ( !q || array )
  3120 + q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );
  3121 +
  3122 + }
  3123 + return q;
  3124 +};
  3125 +
  3126 +jQuery.fn.dequeue = function(type){
  3127 + type = type || "fx";
  3128 +
  3129 + return this.each(function(){
  3130 + var q = queue(this, type);
  3131 +
  3132 + q.shift();
  3133 +
  3134 + if ( q.length )
  3135 + q[0].call( this );
  3136 + });
  3137 +};
  3138 +
  3139 +jQuery.extend({
  3140 +
  3141 + speed: function(speed, easing, fn) {
  3142 + var opt = speed && speed.constructor == Object ? speed : {
  3143 + complete: fn || !fn && easing ||
  3144 + jQuery.isFunction( speed ) && speed,
  3145 + duration: speed,
  3146 + easing: fn && easing || easing && easing.constructor != Function && easing
  3147 + };
  3148 +
  3149 + opt.duration = (opt.duration && opt.duration.constructor == Number ?
  3150 + opt.duration :
  3151 + jQuery.fx.speeds[opt.duration]) || jQuery.fx.speeds.def;
  3152 +
  3153 + // Queueing
  3154 + opt.old = opt.complete;
  3155 + opt.complete = function(){
  3156 + if ( opt.queue !== false )
  3157 + jQuery(this).dequeue();
  3158 + if ( jQuery.isFunction( opt.old ) )
  3159 + opt.old.call( this );
  3160 + };
  3161 +
  3162 + return opt;
  3163 + },
  3164 +
  3165 + easing: {
  3166 + linear: function( p, n, firstNum, diff ) {
  3167 + return firstNum + diff * p;
  3168 + },
  3169 + swing: function( p, n, firstNum, diff ) {
  3170 + return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
  3171 + }
  3172 + },
  3173 +
  3174 + timers: [],
  3175 + timerId: null,
  3176 +
  3177 + fx: function( elem, options, prop ){
  3178 + this.options = options;
  3179 + this.elem = elem;
  3180 + this.prop = prop;
  3181 +
  3182 + if ( !options.orig )
  3183 + options.orig = {};
  3184 + }
  3185 +
  3186 +});
  3187 +
  3188 +jQuery.fx.prototype = {
  3189 +
  3190 + // Simple function for setting a style value
  3191 + update: function(){
  3192 + if ( this.options.step )
  3193 + this.options.step.call( this.elem, this.now, this );
  3194 +
  3195 + (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
  3196 +
  3197 + // Set display property to block for height/width animations
  3198 + if ( this.prop == "height" || this.prop == "width" )
  3199 + this.elem.style.display = "block";
  3200 + },
  3201 +
  3202 + // Get the current size
  3203 + cur: function(force){
  3204 + if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null )
  3205 + return this.elem[ this.prop ];
  3206 +
  3207 + var r = parseFloat(jQuery.css(this.elem, this.prop, force));
  3208 + return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
  3209 + },
  3210 +
  3211 + // Start an animation from one number to another
  3212 + custom: function(from, to, unit){
  3213 + this.startTime = now();
  3214 + this.start = from;
  3215 + this.end = to;
  3216 + this.unit = unit || this.unit || "px";
  3217 + this.now = this.start;
  3218 + this.pos = this.state = 0;
  3219 + this.update();
  3220 +
  3221 + var self = this;
  3222 + function t(gotoEnd){
  3223 + return self.step(gotoEnd);
  3224 + }
  3225 +
  3226 + t.elem = this.elem;
  3227 +
  3228 + jQuery.timers.push(t);
  3229 +
  3230 + if ( jQuery.timerId == null ) {
  3231 + jQuery.timerId = setInterval(function(){
  3232 + var timers = jQuery.timers;
  3233 +
  3234 + for ( var i = 0; i < timers.length; i++ )
  3235 + if ( !timers[i]() )
  3236 + timers.splice(i--, 1);
  3237 +
  3238 + if ( !timers.length ) {
  3239 + clearInterval( jQuery.timerId );
  3240 + jQuery.timerId = null;
  3241 + }
  3242 + }, 13);
  3243 + }
  3244 + },
  3245 +
  3246 + // Simple 'show' function
  3247 + show: function(){
  3248 + // Remember where we started, so that we can go back to it later
  3249 + this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
  3250 + this.options.show = true;
  3251 +
  3252 + // Begin the animation
  3253 + this.custom(0, this.cur());
  3254 +
  3255 + // Make sure that we start at a small width/height to avoid any
  3256 + // flash of content
  3257 + if ( this.prop == "width" || this.prop == "height" )
  3258 + this.elem.style[this.prop] = "1px";
  3259 +
  3260 + // Start by showing the element
  3261 + jQuery(this.elem).show();
  3262 + },
  3263 +
  3264 + // Simple 'hide' function
  3265 + hide: function(){
  3266 + // Remember where we started, so that we can go back to it later
  3267 + this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
  3268 + this.options.hide = true;
  3269 +
  3270 + // Begin the animation
  3271 + this.custom(this.cur(), 0);
  3272 + },
  3273 +
  3274 + // Each step of an animation
  3275 + step: function(gotoEnd){
  3276 + var t = now();
  3277 +
  3278 + if ( gotoEnd || t > this.options.duration + this.startTime ) {
  3279 + this.now = this.end;
  3280 + this.pos = this.state = 1;
  3281 + this.update();
  3282 +
  3283 + this.options.curAnim[ this.prop ] = true;
  3284 +
  3285 + var done = true;
  3286 + for ( var i in this.options.curAnim )
  3287 + if ( this.options.curAnim[i] !== true )
  3288 + done = false;
  3289 +
  3290 + if ( done ) {
  3291 + if ( this.options.display != null ) {
  3292 + // Reset the overflow
  3293 + this.elem.style.overflow = this.options.overflow;
  3294 +
  3295 + // Reset the display
  3296 + this.elem.style.display = this.options.display;
  3297 + if ( jQuery.css(this.elem, "display") == "none" )
  3298 + this.elem.style.display = "block";
  3299 + }
  3300 +
  3301 + // Hide the element if the "hide" operation was done
  3302 + if ( this.options.hide )
  3303 + this.elem.style.display = "none";
  3304 +
  3305 + // Reset the properties, if the item has been hidden or shown
  3306 + if ( this.options.hide || this.options.show )
  3307 + for ( var p in this.options.curAnim )
  3308 + jQuery.attr(this.elem.style, p, this.options.orig[p]);
  3309 + }
  3310 +
  3311 + if ( done )
  3312 + // Execute the complete function
  3313 + this.options.complete.call( this.elem );
  3314 +
  3315 + return false;
  3316 + } else {
  3317 + var n = t - this.startTime;
  3318 + this.state = n / this.options.duration;
  3319 +
  3320 + // Perform the easing function, defaults to swing
  3321 + this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
  3322 + this.now = this.start + ((this.end - this.start) * this.pos);
  3323 +
  3324 + // Perform the next step of the animation
  3325 + this.update();
  3326 + }
  3327 +
  3328 + return true;
  3329 + }
  3330 +
  3331 +};
  3332 +
  3333 +jQuery.extend( jQuery.fx, {
  3334 + speeds:{
  3335 + slow: 600,
  3336 + fast: 200,
  3337 + // Default speed
  3338 + def: 400
  3339 + },
  3340 + step: {
  3341 + scrollLeft: function(fx){
  3342 + fx.elem.scrollLeft = fx.now;
  3343 + },
  3344 +
  3345 + scrollTop: function(fx){
  3346 + fx.elem.scrollTop = fx.now;
  3347 + },
  3348 +
  3349 + opacity: function(fx){
  3350 + jQuery.attr(fx.elem.style, "opacity", fx.now);
  3351 + },
  3352 +
  3353 + _default: function(fx){
  3354 + fx.elem.style[ fx.prop ] = fx.now + fx.unit;
  3355 + }
  3356 + }
  3357 +});
  3358 +// The Offset Method
  3359 +// Originally By Brandon Aaron, part of the Dimension Plugin
  3360 +// http://jquery.com/plugins/project/dimensions
  3361 +jQuery.fn.offset = function() {
  3362 + var left = 0, top = 0, elem = this[0], results;
  3363 +
  3364 + if ( elem ) with ( jQuery.browser ) {
  3365 + var parent = elem.parentNode,
  3366 + offsetChild = elem,
  3367 + offsetParent = elem.offsetParent,
  3368 + doc = elem.ownerDocument,
  3369 + safari2 = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
  3370 + css = jQuery.curCSS,
  3371 + fixed = css(elem, "position") == "fixed";
  3372 +
  3373 + // Use getBoundingClientRect if available
  3374 + if ( elem.getBoundingClientRect ) {
  3375 + var box = elem.getBoundingClientRect();
  3376 +
  3377 + // Add the document scroll offsets
  3378 + add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
  3379 + box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
  3380 +
  3381 + // IE adds the HTML element's border, by default it is medium which is 2px
  3382 + // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
  3383 + // IE 7 standards mode, the border is always 2px
  3384 + // This border/offset is typically represented by the clientLeft and clientTop properties
  3385 + // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
  3386 + // Therefore this method will be off by 2px in IE while in quirksmode
  3387 + add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
  3388 +
  3389 + // Otherwise loop through the offsetParents and parentNodes
  3390 + } else {
  3391 +
  3392 + // Initial element offsets
  3393 + add( elem.offsetLeft, elem.offsetTop );
  3394 +
  3395 + // Get parent offsets
  3396 + while ( offsetParent ) {
  3397 + // Add offsetParent offsets
  3398 + add( offsetParent.offsetLeft, offsetParent.offsetTop );
  3399 +
  3400 + // Mozilla and Safari > 2 does not include the border on offset parents
  3401 + // However Mozilla adds the border for table or table cells
  3402 + if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
  3403 + border( offsetParent );
  3404 +
  3405 + // Add the document scroll offsets if position is fixed on any offsetParent
  3406 + if ( !fixed && css(offsetParent, "position") == "fixed" )
  3407 + fixed = true;
  3408 +
  3409 + // Set offsetChild to previous offsetParent unless it is the body element
  3410 + offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
  3411 + // Get next offsetParent
  3412 + offsetParent = offsetParent.offsetParent;
  3413 + }
  3414 +
  3415 + // Get parent scroll offsets
  3416 + while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
  3417 + // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
  3418 + if ( !/^inline|table.*$/i.test(css(parent, "display")) )
  3419 + // Subtract parent scroll offsets
  3420 + add( -parent.scrollLeft, -parent.scrollTop );
  3421 +
  3422 + // Mozilla does not add the border for a parent that has overflow != visible
  3423 + if ( mozilla && css(parent, "overflow") != "visible" )
  3424 + border( parent );
  3425 +
  3426 + // Get next parent
  3427 + parent = parent.parentNode;
  3428 + }
  3429 +
  3430 + // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
  3431 + // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
  3432 + if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
  3433 + (mozilla && css(offsetChild, "position") != "absolute") )
  3434 + add( -doc.body.offsetLeft, -doc.body.offsetTop );
  3435 +
  3436 + // Add the document scroll offsets if position is fixed
  3437 + if ( fixed )
  3438 + add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
  3439 + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
  3440 + }
  3441 +
  3442 + // Return an object with top and left properties
  3443 + results = { top: top, left: left };
  3444 + }
  3445 +
  3446 + function border(elem) {
  3447 + add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
  3448 + }
  3449 +
  3450 + function add(l, t) {
  3451 + left += parseInt(l, 10) || 0;
  3452 + top += parseInt(t, 10) || 0;
  3453 + }
  3454 +
  3455 + return results;
  3456 +};
  3457 +
  3458 +
  3459 +jQuery.fn.extend({
  3460 + position: function() {
  3461 + var left = 0, top = 0, results;
  3462 +
  3463 + if ( this[0] ) {
  3464 + // Get *real* offsetParent
  3465 + var offsetParent = this.offsetParent(),
  3466 +
  3467 + // Get correct offsets
  3468 + offset = this.offset(),
  3469 + parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();
  3470 +
  3471 + // Subtract element margins
  3472 + // note: when an element has margin: auto the offsetLeft and marginLeft
  3473 + // are the same in Safari causing offset.left to incorrectly be 0
  3474 + offset.top -= num( this, 'marginTop' );
  3475 + offset.left -= num( this, 'marginLeft' );
  3476 +
  3477 + // Add offsetParent borders
  3478 + parentOffset.top += num( offsetParent, 'borderTopWidth' );
  3479 + parentOffset.left += num( offsetParent, 'borderLeftWidth' );
  3480 +
  3481 + // Subtract the two offsets
  3482 + results = {
  3483 + top: offset.top - parentOffset.top,
  3484 + left: offset.left - parentOffset.left
  3485 + };
  3486 + }
  3487 +
  3488 + return results;
  3489 + },
  3490 +
  3491 + offsetParent: function() {
  3492 + var offsetParent = this[0].offsetParent;
  3493 + while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
  3494 + offsetParent = offsetParent.offsetParent;
  3495 + return jQuery(offsetParent);
  3496 + }
  3497 +});
  3498 +
  3499 +
  3500 +// Create scrollLeft and scrollTop methods
  3501 +jQuery.each( ['Left', 'Top'], function(i, name) {
  3502 + var method = 'scroll' + name;
  3503 +
  3504 + jQuery.fn[ method ] = function(val) {
  3505 + if (!this[0]) return;
  3506 +
  3507 + return val != undefined ?
  3508 +
  3509 + // Set the scroll offset
  3510 + this.each(function() {
  3511 + this == window || this == document ?
  3512 + window.scrollTo(
  3513 + !i ? val : jQuery(window).scrollLeft(),
  3514 + i ? val : jQuery(window).scrollTop()
  3515 + ) :
  3516 + this[ method ] = val;
  3517 + }) :
  3518 +
  3519 + // Return the scroll offset
  3520 + this[0] == window || this[0] == document ?
  3521 + self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
  3522 + jQuery.boxModel && document.documentElement[ method ] ||
  3523 + document.body[ method ] :
  3524 + this[0][ method ];
  3525 + };
  3526 +});
  3527 +// Create innerHeight, innerWidth, outerHeight and outerWidth methods
  3528 +jQuery.each([ "Height", "Width" ], function(i, name){
  3529 +
  3530 + var tl = i ? "Left" : "Top", // top or left
  3531 + br = i ? "Right" : "Bottom"; // bottom or right
  3532 +
  3533 + // innerHeight and innerWidth
  3534 + jQuery.fn["inner" + name] = function(){
  3535 + return this[ name.toLowerCase() ]() +
  3536 + num(this, "padding" + tl) +
  3537 + num(this, "padding" + br);
  3538 + };
  3539 +
  3540 + // outerHeight and outerWidth
  3541 + jQuery.fn["outer" + name] = function(margin) {
  3542 + return this["inner" + name]() +
  3543 + num(this, "border" + tl + "Width") +
  3544 + num(this, "border" + br + "Width") +
  3545 + (margin ?
  3546 + num(this, "margin" + tl) + num(this, "margin" + br) : 0);
  3547 + };
  3548 +
  3549 +});})();
  3550 +
  3551 +var JQ = jQuery.noConflict();
0 3552 \ No newline at end of file
... ...
plugins/multiselect/sql/script.sql 0 โ†’ 100644
  1 +ALTER TABLE `document_fields`
  2 + ADD `has_inetlookup` tinyint(1) default NULL;
  3 +
  4 +ALTER TABLE `document_fields`
  5 + ADD `inetlookup_type` varchar(255) default NULL;
0 6 \ No newline at end of file
... ...
plugins/multiselect/templates/ktcore/metadata/admin/basic_overview.smarty 0 โ†’ 100644
  1 +<p class="descriptiveText">{i18n}Fieldsets bring together different fields into a collection
  2 +of related information.{/i18n}</p>
  3 +
  4 +<p><a class="ktAction ktAdd ktActionDescribed" href="{addQS context=$context}fieldset_action=newfield{/addQS}">{i18n}Add New Field{/i18n}</a>
  5 +<a href="{addQS context=$context}fieldset_action=newfield{/addQS}">{i18n}Add New Field{/i18n}</a></p>
  6 +
  7 +{if (!empty($fields))}
  8 +<table class="kt_collection narrow" cellspacing="0">
  9 + <thead>
  10 + <tr>
  11 + <th>{i18n}Field Name{/i18n}</th>
  12 + <th class="centered">{i18n}Edit{/i18n}</th>
  13 + <th class="centered">{i18n}Delete{/i18n}</th>
  14 + <th>{i18n}Type Description{/i18n}</th>
  15 + <th colspan="2">{i18n}Position{/i18n}</th>
  16 + </tr>
  17 + </thead>
  18 + <tbody>
  19 + {foreach name=fieldlist from=$fields item=oField}
  20 + <tr>
  21 + <td class="title">
  22 + {$oField->getName()}
  23 + </td>
  24 + <td class="centered">
  25 + <a href="{addQS context=$context}fieldset_action=managefield&fFieldId={$oField->getId()}{/addQS}" class="ktAction ktEdit">{i18n}edit{/i18n}</a>
  26 + </td>
  27 + <td class="centered">
  28 + <a href="{addQS context=$context}fieldset_action=deletefield&fFieldId={$oField->getId()}{/addQS}" class="ktAction ktDelete">{i18n}delete{/i18n}</a>
  29 + </td>
  30 + <td>
  31 + <span class="descriptiveText">{if $oField->getHasInetLookup()}{$oField->getInetLookupTypeFriendlyName()}{else}{$oField->getTypeDescription()}{/if}</span>
  32 + </td>
  33 + <td>
  34 + {if !$smarty.foreach.fieldlist.first}
  35 + <a href="{addQS context=$context}fieldset_action=orderUp&fFieldId={$oField->getId()}{/addQS}" class="ktAction ktMoveUp">{i18n}Reorder up{/i18n}</a>
  36 + {/if}
  37 + </td>
  38 + <td>
  39 + {if !$smarty.foreach.fieldlist.last}
  40 + <a href="{addQS context=$context}fieldset_action=orderDown&fFieldId={$oField->getId()}{/addQS}" class="ktAction ktMoveDown">{i18n}Reorder down{/i18n}</a>
  41 + {/if}
  42 + </td>
  43 + </tr>
  44 + {/foreach}
  45 + </tbody>
  46 +</table>
  47 +{/if}
... ...
plugins/multiselect/templates/ktcore/search2/adv_query_builder.smarty 0 โ†’ 100644
  1 +
  2 +
  3 +{literal}
  4 +<style>
  5 +fieldset { border: 1px dotted #999; }
  6 +legend { border: 1px dotted #999;}
  7 +.metadatadate { width: 80px; font-size;12px }
  8 +.datediff { width: 30px}
  9 +.filesize { width: 60px }
  10 +</style>
  11 +<script>
  12 +var meta_workflows = {/literal}{$metainfo.workflow_str}{literal};
  13 +var meta_fieldsets = {/literal}{$metainfo.fieldset_str}{literal};
  14 +var meta_fields = {/literal}{$metainfo.fields_str}{literal};
  15 +var meta_users = {/literal}{$metainfo.users_str}{literal};
  16 +var meta_mimetypes = {/literal}{$metainfo.mimetypes_str}{literal};
  17 +var meta_documenttypes = {/literal}{$metainfo.documenttypes_str}{literal};
  18 +var criteria = [ {fields: 0, visible: 0}];
  19 +
  20 +function selectorChange(groupid)
  21 +{
  22 + var fields = $('fields' + groupid);
  23 + var workflows = $('workflows' + groupid);
  24 + var fieldsets = $('fieldsets' + groupid);
  25 + var selector = $('selector' + groupid);
  26 +
  27 + switch(selector.selectedIndex)
  28 + {
  29 + case 0: fields.selectedIndex=0; break;
  30 + case 1: fieldsets.selectedIndex=0; break;
  31 + case 2: workflows.selectedIndex=0; break;
  32 + }
  33 +
  34 + workflows.style.display = (selector.selectedIndex == 2)?'block':'none';
  35 + fieldsets.style.display = (selector.selectedIndex == 1)?'block':'none';
  36 + fields.style.display = (selector.selectedIndex == 0)?'block':'none';
  37 +
  38 + var wlist = $('workflow_states' + groupid);
  39 + wlist.selectedIndex = 0;
  40 + $('workflow_states_wrapper' + groupid).style.display = 'none';
  41 +
  42 + var fslist = $('fieldset_fields' + groupid);
  43 + fslist.selectedIndex = 0;
  44 + $('fieldset_fields_wrapper' + groupid).style.display = 'none';
  45 +}
  46 +
  47 +function fieldChange(groupid)
  48 +{
  49 + fields = $('fields' + groupid);
  50 +
  51 + fid = fields.selectedIndex - 1;
  52 + if (fid<0) return;
  53 +
  54 + name = meta_fields[fid].name;
  55 + alias = meta_fields[fid].alias;
  56 + type = meta_fields[fid].type;
  57 +
  58 + addField(groupid, name, alias, type);
  59 +}
  60 +
  61 +function delField(groupid, fid)
  62 +{
  63 + el = $('field' + groupid + '_' + fid);
  64 + el.innerHTML = '';
  65 + if (--criteria[groupid].visible == 0)
  66 + {
  67 + $('criteria_nofields' + groupid).style.display = 'block';
  68 + }
  69 +}
  70 +
  71 +function createUserList(groupid, fid)
  72 +{
  73 + var html = "<table><tr><td width=\"140\">";
  74 +
  75 + html += "<SELECT style=\"width: 140px \" id=\"field" + groupid + "_" + fid + "op\">";
  76 + html += "<option value=\"is\">{/literal}{i18n}is{/i18n}{literal}";
  77 + html += "<option value=\"is not\">{/literal}{i18n}is not{/i18n}{literal}";
  78 + html += "</SELECT>"
  79 +
  80 + html += "<td>"
  81 +
  82 + html += "<SELECT id=\"field" + groupid + "_" + fid + "start\">";
  83 + for(i=0;i<meta_users.length;i++)
  84 + {
  85 + html += "<option value=\"" + meta_users[i].name + "\">" + meta_users[i].name;
  86 + }
  87 + html += "</SELECT>";
  88 + html += "<td width=\"100%\">&nbsp;";
  89 + html += "</table>";
  90 +
  91 + return html;
  92 +}
  93 +
  94 +function createDocTypes(groupid, fid)
  95 +{
  96 + var html = "<table><tr><td width=\"140\">";
  97 +
  98 + html += "<SELECT style=\"width: 140px \" id=\"field" + groupid + "_" + fid + "op\">";
  99 + html += "<option value=\"is\">{/literal}{i18n}is{/i18n}{literal}";
  100 + html += "<option value=\"is not\">{/literal}{i18n}is not{/i18n}{literal}";
  101 + html += "</SELECT>"
  102 +
  103 + html += "<td>"
  104 +
  105 + html += "<SELECT id=\"field" + groupid + "_" + fid + "start\">";
  106 + for(i=0;i<meta_documenttypes.length;i++)
  107 + {
  108 + html += "<option value=\"" + meta_documenttypes[i].name + "\">" + meta_documenttypes[i].name;
  109 + }
  110 + html += "</SELECT>";
  111 + html += "<td width=\"100%\">&nbsp;";
  112 + html += "</table>";
  113 +
  114 + return html;
  115 +}
  116 +
  117 +function createMimeTypes(groupid, fid)
  118 +{
  119 + var html = "<table><tr><td width=\"140\">";
  120 +
  121 + html += "<SELECT style=\"width: 140px \" id=\"field" + groupid + "_" + fid + "op\">";
  122 + html += "<option value=\"is\">{/literal}{i18n}is{/i18n}{literal}";
  123 + html += "<option value=\"is not\">{/literal}{i18n}is not{/i18n}{literal}";
  124 + html += "</SELECT>"
  125 +
  126 + html += "<td>"
  127 +
  128 + html += "<SELECT id=\"field" + groupid + "_" + fid + "start\">";
  129 + for(i=0;i<meta_mimetypes.length;i++)
  130 + {
  131 + html += "<option value=\"" + meta_mimetypes[i] + "\">" + meta_mimetypes[i];
  132 + }
  133 + html += "</SELECT>";
  134 + html += "<td width=\"100%\">&nbsp;";
  135 + html += "</table>";
  136 +
  137 + return html;
  138 +}
  139 +
  140 +function onBetweenOpChange(groupid, fid)
  141 +{
  142 + var op = document.getElementById('field' + groupid + '_' + fid + 'op');
  143 + var end = document.getElementById('field' + groupid + '_' + fid + 'end');
  144 + var range1 = document.getElementById('field' + groupid + '_' + fid + 'range1');
  145 + var range2 = document.getElementById('field' + groupid + '_' + fid + 'range2');
  146 + switch (op.value)
  147 + {
  148 + case 'between':
  149 + case 'not between':
  150 + range2.style.visibility = range1.style.visibility = 'visible';
  151 + break;
  152 + default:
  153 + range2.style.visibility = range1.style.visibility = 'hidden';
  154 + break;
  155 + }
  156 +}
  157 +
  158 +function initDate(groupid, fid)
  159 +{
  160 + var startname = "field"+ groupid + '_' + fid +"start";
  161 + var endname = "field"+ groupid + '_' + fid +"end";
  162 + var now = new Date();
  163 + var yesterday = now.getTime() - 60 * 60 * 24 * 1000;
  164 + var df = new Ext.form.DateField({format : "Y-m-d", fieldClass: 'metadatadate', name: startname, value: new Date(yesterday)});
  165 + var df2 = new Ext.form.DateField({format : "Y-m-d", fieldClass: 'metadatadate', name: endname, value: now});
  166 + df.render(startname);
  167 + df2.render(endname);
  168 +}
  169 +
  170 +function createRange(groupid, fid, type)
  171 +{
  172 + var html = "<table><tr><td width=\"140\">";
  173 +
  174 + html += "<SELECT style=\"width: 140px\" id=\"field" + groupid + "_" + fid + "op\" onchange=\"onBetweenOpChange("+ groupid + "," + fid +")\">";
  175 +
  176 + switch(type)
  177 + {
  178 + case 'DATE':
  179 + html += "<option value=\"\>\">{/literal}{i18n}after{/i18n}{literal}";
  180 + html += "<option value=\"between\">{/literal}{i18n}between{/i18n}{literal}";
  181 + html += "<option value=\"<\">{/literal}{i18n}before{/i18n}{literal}";
  182 + html += "<option value=\"is\">{/literal}{i18n}on{/i18n}{literal}";
  183 + html += "<option value=\"is not\">{/literal}{i18n}not on{/i18n}{literal}";
  184 + break;
  185 + default:
  186 + html += "<option value=\"is\">=";
  187 + html += "<option value=\"is not\">!=";
  188 + html += "<option value=\"\>\">\>";
  189 + html += "<option value=\"\>=\">\>=";
  190 + html += "<option value=\"\<\">\<";
  191 + html += "<option value=\"\<=\">\<=";
  192 + html += "<option value=\"between\">{/literal}{i18n}between{/i18n}{literal}";
  193 + break;
  194 + }
  195 + html += "</SELECT>";
  196 +
  197 + html += "<td valign=top width=\"100\"><div id=\"field"+ groupid + '_' + fid +"start\"></div>";
  198 + html += "<td valign=top width=\"50\" id=\"field"+ groupid + '_' + fid+"range1\" style=\"visibility: hidden\">&nbsp;and&nbsp;";
  199 + html += "<td valign=top width=\"100\" id=\"field"+ groupid + '_' + fid+"range2\" style=\"visibility: hidden\">";
  200 + html += "<div id=\"field"+ groupid + '_' + fid + "end\"></div>";
  201 + html += "<td width=\"100%\">&nbsp;";
  202 + html += "</table>";
  203 + return html;
  204 +}
  205 +
  206 +function createDate(groupid, fid)
  207 +{
  208 + return createRange(groupid, fid, 'DATE');
  209 +}
  210 +
  211 +function initInt(groupid, fid)
  212 +{
  213 + var startname = "field"+ groupid + '_' + fid +"start";
  214 + var endname = "field"+ groupid + '_' + fid +"end";
  215 +
  216 + var nf = new Ext.form.NumberField( {allowNegative: false, decimalPrecision : 0, name: startname});
  217 + nf.render(startname);
  218 + var nf2 = new Ext.form.NumberField( {allowNegative: false, decimalPrecision : 0, name: endname});
  219 + nf2.render(endname);
  220 +}
  221 +
  222 +function createInt(groupid, fid)
  223 +{
  224 + return createRange(groupid, fid, 'INT');
  225 +}
  226 +
  227 +function createFloat(groupid, fid)
  228 +{
  229 + return createRange(groupid, fid, 'FLOAT');
  230 +}
  231 +
  232 +function getElByName(groupid, name)
  233 +{
  234 + form = $('form' + groupid)
  235 + for(var i=0;i<form.elements.length;i++)
  236 + {
  237 + if (form.elements[i].name == name)
  238 + {
  239 + return form.elements[i];
  240 + }
  241 + }
  242 +
  243 + var item = $(name);
  244 + if (item != null)
  245 + {
  246 + return item;
  247 + }
  248 +
  249 + return null;
  250 +}
  251 +
  252 +function onDateDiffChange(groupid, fid)
  253 +{
  254 + var prefix = 'field' + groupid + '_' + fid;
  255 + var period=1;
  256 + switch($(prefix + 'period').selectedIndex)
  257 + {
  258 + case 1: period = 30; break;
  259 + case 2: period = 365; break;
  260 + }
  261 +
  262 + $(prefix + 'start').value = parseInt(getElByName(groupid, prefix + 'input').value) * period;
  263 +}
  264 +
  265 +function initDateDiff(groupid, fid)
  266 +{
  267 + var startname = "field"+ groupid + '_' + fid +"input";
  268 + var nf = new Ext.form.NumberField( {allowNegative: false, fieldClass: 'datediff', decimalPrecision : 0, name: startname, value: "1"});
  269 + nf.render(startname);
  270 +
  271 + nf.on('change', function(){ onDateDiffChange(groupid, fid); });
  272 +}
  273 +
  274 +function initFilesize(groupid, fid)
  275 +{
  276 + var startname = "field"+ groupid + '_' + fid +"input";
  277 + var nf = new Ext.form.NumberField( {allowNegative: false, fieldClass: 'filesize', decimalPrecision : 0, name: startname, value: "0"});
  278 + nf.render(startname);
  279 +
  280 + nf.on('change', function(){ onFilesizeChange(groupid, fid); });
  281 +}
  282 +
  283 +function onFilesizeChange(groupid, fid)
  284 +{
  285 + var prefix = 'field' + groupid + '_' + fid;
  286 + var factor=1;
  287 + switch($(prefix + 'factor').selectedIndex)
  288 + {
  289 + case 1: factor = 1024; break;
  290 + case 2: factor = 1024*1024; break;
  291 + case 3: factor = 1024*1024*1024; break;
  292 + }
  293 +
  294 + $(prefix + 'start').value = parseInt(getElByName(groupid, prefix + 'input').value) * factor;
  295 +}
  296 +
  297 +function createFilesize(groupid, fid)
  298 +{
  299 + var html = "<table><tr><td width=\"140\"";
  300 +
  301 + html += "<SELECT style=\"width: 140px\" id=\"field" + groupid + "_" + fid + "op\">";
  302 + html += "<option value=\"\<\">\<";
  303 + html += "<option value=\"\<=\">\<=";
  304 + html += "<option value=\"\>\">\>";
  305 + html += "<option value=\"\>=\">\>=";
  306 + html += "<option value=\"=\">=";
  307 + html += "<option value=\"!=\">!=";
  308 + html += "</SELECT>"
  309 +
  310 +
  311 + html += "<td valign=top width=\"50px\"><div id=\"field"+ groupid + '_' + fid +"input\"></div>";
  312 + html += "<td>";
  313 + html += "<SELECT id=\"field" + groupid + "_" + fid + "factor\" onchange=\"onFilesizeChange( " + groupid + "," + fid + ")\">";
  314 + html += "<option>{/literal}{i18n}bytes{/i18n}{literal}";
  315 + html += "<option>{/literal}{i18n}kilobytes{/i18n}{literal}";
  316 + html += "<option>{/literal}{i18n}megabytes{/i18n}{literal}";
  317 + html += "<option>{/literal}{i18n}gigabytes{/i18n}{literal}";
  318 + html += "</SELECT>";
  319 + html += "<input style=\"display: none\" value=\"0\" id=\"field" + groupid + "_" + fid + "start\">";
  320 + html += "<td width=\"100%\">&nbsp;";
  321 +
  322 + html += "</table>";
  323 + return html;
  324 +}
  325 +
  326 +function createDateDiff(groupid, fid)
  327 +{
  328 + var html = "<table><tr><td width=\"140\">";
  329 +
  330 + html += "<SELECT style=\"width: 140px\" id=\"field" + groupid + "_" + fid + "op\">";
  331 + html += "<option value=\"\<\">{/literal}{i18n}less than{/i18n}{literal}";
  332 + html += "<option value=\"\>\">{/literal}{i18n}greater than{/i18n}{literal}";
  333 + html += "</SELECT>"
  334 +
  335 +
  336 + html += "<td valign=top width=\"50px\"><div id=\"field"+ groupid + '_' + fid +"input\"></div>";
  337 + html += "<td>";
  338 + html += "<SELECT id=\"field" + groupid + "_" + fid + "period\" onchange=\"onDateDiffChange( " + groupid + "," + fid + ")\">";
  339 + html += "<option>{/literal}{i18n}days{/i18n}{literal}";
  340 + html += "<option>{/literal}{i18n}months{/i18n}{literal}";
  341 + html += "<option>{/literal}{i18n}years{/i18n}{literal}";
  342 + html += "</SELECT>";
  343 + html += "<td>ago"
  344 + html += "<input style=\"display: none\" value=\"1\" id=\"field" + groupid + "_" + fid + "start\">";
  345 + html += "<td width=\"100%\">&nbsp;";
  346 +
  347 + html += "</table>";
  348 + return html;
  349 +}
  350 +
  351 +function createSelect(groupid, fid, options)
  352 +{
  353 + var html = "<table><tr><td width=\"90\" valign=top>";
  354 +
  355 + // by dp start // to create the select element with multiselect functionality
  356 + var fieldsetid=$('fieldsets' + groupid).selectedIndex-1;
  357 + var fieldid=$('fieldset_fields' + groupid).selectedIndex;
  358 + if(meta_fieldsets[fieldsetid].fields[fieldid].control == "inetlookup")
  359 + {
  360 + html += "<select id=\"field"+ groupid + "_" + fid +"op\" style=\"width: 140px\">";
  361 + html += "<option value=\"contains\">{/literal}{i18n}is{/i18n}{literal}";
  362 + html += "<option value=\"does not contain\">{/literal}{i18n}is not{/i18n}{literal}";
  363 + html += "</select>&nbsp;&nbsp;";
  364 +
  365 + html += "</td>";
  366 +
  367 + html += "<td valign=top>";
  368 + html += "<select id=\"field"+ groupid + "_" + fid +"join\" style=\"width: 80px\">";
  369 + html += "<option value=\"AND\">{/literal}{i18n}all{/i18n}{literal}";
  370 + html += "<option value=\"OR\">{/literal}{i18n}any{/i18n}{literal}";
  371 + html += "</select>&nbsp;&nbsp;";
  372 + html += "</td>";
  373 +
  374 + html += "<td valign=top>";
  375 + if(meta_fieldsets[fieldsetid].fields[fieldid].inetlookup_type == "multiwithlist")
  376 + {
  377 + html += "<select class=\"inetlookup\" multiple=\"multiple\" size=\"4\" name=\"field"+ groupid + "_" + fid +"start[]\" id=\"field"+ groupid + "_" + fid +"start\">";
  378 + for(i=0;i<options.length;i++)
  379 + {
  380 + html += "<option value=\"" + options[i].name + "\">" + options[i].name;
  381 + }
  382 + html += "</select>";
  383 + }
  384 + else if(meta_fieldsets[fieldsetid].fields[fieldid].inetlookup_type == "multiwithcheckboxes")
  385 + {
  386 +
  387 + for(i=0;i<options.length;i++)
  388 + {
  389 + html += "<input class=\"inetlookup\" type=\"checkbox\" name=\"field"+ groupid + "_" + fid +"start[]\" id=\"field"+ groupid + "_" + fid +"start\" value=\""+options[i].name+"\" /> "+options[i].name+"<BR />";
  390 + //html += "<option value=\"" + options[i].name + "\">" + options[i].name;
  391 + }
  392 + //html += "</select>";
  393 + }
  394 +
  395 + html += "</td></tr></table>";
  396 + }// by dp end // to create the select element with multiselect functionality
  397 + else
  398 + {
  399 + html += "<select id=\"field"+ groupid + "_" + fid +"op\" style=\"width: 140px\">";
  400 + html += "<option value=\"is\">{/literal}{i18n}is{/i18n}{literal}";
  401 + html += "<option value=\"is not\">{/literal}{i18n}is not{/i18n}{literal}";
  402 + html += "</select>&nbsp;&nbsp;";
  403 +
  404 + html += "</td>";
  405 +
  406 + html += "<td valign=top>";
  407 + html += "<select name=\"field"+ groupid + "_" + fid +"start\" id=\"field"+ groupid + "_" + fid +"start\">";
  408 + for(i=0;i<options.length;i++)
  409 + {
  410 + html += "<option value=\"" + options[i].name + "\">" + options[i].name;
  411 + }
  412 + html += "</select>";
  413 + html += "</td></tr></table>";
  414 + }
  415 +
  416 +
  417 + return html;
  418 +}
  419 +
  420 +function createText(groupid, fid, type)
  421 +{
  422 + var html = "<table><tr><td width=\"140\">";
  423 + html += "<select style=\"width: 140px\" id=\"field"+ groupid + "_" + fid +"op\"\>";
  424 + var readonly = '';
  425 + switch(type)
  426 + {
  427 + case 'STRINGMATCH':
  428 + readonly = 'readonly';
  429 + html += "<option value=\"is\">{/literal}{i18n}is{/i18n}{literal}";
  430 + html += "<option value=\"is not\">{/literal}{i18n}is not{/i18n}{literal}";
  431 + break;
  432 + case 'STRING':
  433 + html += "<option value=\"is\">{/literal}{i18n}is{/i18n}{literal}";
  434 + html += "<option value=\"is not\">{/literal}{i18n}is not{/i18n}{literal}";
  435 + html += "<option value=\"contains\">{/literal}{i18n}contains{/i18n}{literal}";
  436 + html += "<option value=\"does not contain\">{/literal}{i18n}does not contain{/i18n}{literal}";
  437 + html += "<option value=\"like\">{/literal}{i18n}like{/i18n}{literal}";
  438 + html += "<option value=\"not like\">{/literal}{i18n}not like{/i18n}{literal}";
  439 + html += "<option value=\"starts with\">{/literal}{i18n}starts with{/i18n}{literal}";
  440 + html += "<option value=\"ends with\">{/literal}{i18n}ends with{/i18n}{literal}";
  441 + break;
  442 + case 'FULLTEXT':
  443 + html += "<option value=\"contains\">{/literal}{i18n}contains{/i18n}{literal}";
  444 + html += "<option value=\"does not contain\">{/literal}{i18n}does not contain{/i18n}{literal}";
  445 + break;
  446 + }
  447 +
  448 + html += "</select>&nbsp;&nbsp;";
  449 + html += "<td>"
  450 +
  451 + html += "<input id=\"field"+ groupid + "_" + fid +"start\" " + readonly + ">";
  452 +
  453 + html += "</table>";
  454 +
  455 + return html;
  456 +}
  457 +
  458 +function createBool(groupid, fid)
  459 +{
  460 + var html = "<select style=\"width: 140px\" id=\"field"+ groupid + "_" + fid +"op\"\>";
  461 + html += "<option value=\"is\">{/literal}{i18n}is{/i18n}{literal}";
  462 + html += "<option value=\"is not\">{/literal}{i18n}is not{/i18n}{literal}";
  463 + html += "</select>&nbsp;&nbsp;";
  464 + html += "<select id=\"field"+ groupid + "_" + fid +"start\"\>";
  465 + html += "<option value=\"true\">{/literal}{i18n}True{/i18n}{literal}";
  466 + html += "<option value=\"false\">{/literal}{i18n}False{/i18n}{literal}";
  467 + html += "</select>&nbsp;&nbsp;";
  468 +
  469 + return html;
  470 +}
  471 +
  472 +function addFieldTypeSelection(groupid, fid, type, options)
  473 +{
  474 + var html = '';
  475 + var callback = null;
  476 + var params = null;
  477 + switch(type)
  478 + {
  479 + case 'FILESIZE':
  480 + html = createFilesize(groupid, fid);
  481 + return {html: html, init: initFilesize};
  482 + case 'MIMETYPES':
  483 + html = createMimeTypes(groupid, fid);
  484 + break;
  485 + case 'DOCTYPES':
  486 + html = createDocTypes(groupid, fid);
  487 + break;
  488 + case 'BOOL':
  489 + html = createBool(groupid, fid);
  490 + break;
  491 + case 'STRING':
  492 + if (options != null && options.length != 0)
  493 + {
  494 + html = createSelect(groupid, fid, options);
  495 + break;
  496 + }
  497 + // want to fall through
  498 + case 'FULLTEXT':
  499 + case 'STRINGMATCH':
  500 + html = createText(groupid, fid, type);
  501 + break;
  502 + case 'USERLIST':
  503 + html = createUserList(groupid, fid);
  504 + break;
  505 + case 'DATE':
  506 + html = createDate(groupid, fid);
  507 + return {html: html, init: initDate};
  508 + case 'INT':
  509 + html = createInt(groupid, fid);
  510 + return {html: html, init: initInt};
  511 + case 'FLOAT':
  512 + html = createFloat(groupid, fid);
  513 + return {html: html, init: initFloat};
  514 + case 'DATEDIFF':
  515 + html = createDateDiff(groupid, fid);
  516 + return {html: html, init: initDateDiff};
  517 + default:
  518 + html += 'unknown: ' + type;
  519 + }
  520 +
  521 + return {html: html, init: callback};
  522 +
  523 +}
  524 +
  525 +function removeCriteriaGroup(groupid)
  526 +{
  527 + $("groupwrapper" + groupid).innerHTML = '';
  528 +
  529 + criteria[groupid].fields = 0;
  530 +}
  531 +
  532 +function initAddField(groupid)
  533 +{
  534 + if (criteria[groupid].visible == 0)
  535 + {
  536 + $('criteria_nofields' + groupid).style.display = 'none';
  537 + if (groupid > 0)
  538 + {
  539 + $('removeCriteriaGroup' + groupid).style.display = 'block';
  540 + }
  541 + }
  542 + var fid = ++criteria[groupid].fields;
  543 + criteria[groupid].visible++;
  544 + return fid;
  545 +}
  546 +
  547 +
  548 +function addMetadataField(groupid)
  549 +{
  550 + var fid = initAddField(groupid);
  551 +
  552 + var fieldsetid=$('fieldsets' + groupid).selectedIndex-1;
  553 + var fieldid=$('fieldset_fields' + groupid).selectedIndex;
  554 +
  555 + var fieldsetname = meta_fieldsets[fieldsetid].name;
  556 + var fieldname = meta_fieldsets[fieldsetid].fields[fieldid].name;
  557 + var fieldtype = meta_fieldsets[fieldsetid].fields[fieldid].datatype;
  558 + var fieldoptions = meta_fieldsets[fieldsetid].fields[fieldid].options;
  559 +
  560 + var html = "<table width=\"650\">";
  561 + html += "<tr>";
  562 + html += "<td width=\"120\" valign=top><nobr><B>" + fieldsetname + ':</B></nobr><br><nobr><i>' + fieldname + '</i></nobr>';
  563 + html += "<div id=\"field" + groupid + "_" + fid + "expr\" style=\"display: none\">[\"" + fieldsetname + "\"][\""+fieldname + "\"]</div>";
  564 + html += "<td><nobr>";
  565 +
  566 + var rec = addFieldTypeSelection(groupid, fid, fieldtype, fieldoptions);
  567 +
  568 + html += rec.html;
  569 +
  570 + html += "<td width=\"55\">";
  571 +
  572 + html += "<input type=\"button\" value=\"{/literal}{i18n}remove{/i18n}{literal}\" onclick=\"delField(" + groupid + "," + fid + ")\">";
  573 +
  574 + html += "</table>";
  575 +
  576 + var el = new Ext.Element(document.createElement('div'));
  577 + el.dom.id = "field" + groupid + "_" + fid;
  578 + el.id = el.dom.id;
  579 + el.dom.innerHTML = html;
  580 + el.appendTo('criteria_fields' + groupid);
  581 +
  582 + if (rec.init != null)
  583 + {
  584 + rec.init(groupid, fid);
  585 + }
  586 + return fid;
  587 +}
  588 +
  589 +function addWorkflowStateField(groupid)
  590 +{
  591 + var wid=$('workflows' + groupid).selectedIndex-1;
  592 + var sid=$('workflow_states' + groupid).selectedIndex;
  593 +
  594 + var workflowname = meta_workflows[wid].name;
  595 + var statename = meta_workflows[wid].states[sid].name;
  596 +
  597 + var fid = addField(groupid, 'Workflow', 'Workflow', 'STRINGMATCH');
  598 + $('field' + groupid + '_' + fid + 'start').value = workflowname;
  599 +
  600 +
  601 + fid = addField(groupid, 'Workflow State', 'WorkflowState', 'STRINGMATCH');
  602 + $('field' + groupid + '_' + fid + 'start').value = statename;
  603 +
  604 + $('groupop' + groupid).selectedIndex = 0;
  605 +}
  606 +
  607 +
  608 +function addField(groupid, display, exprname, type)
  609 +{
  610 + var fid = initAddField(groupid);
  611 + var rec = {init:null};
  612 +
  613 + var html = "<table width=\"650\">";
  614 + html += "<tr>";
  615 + html += "<td width=\"120\" valign=top>" + display;
  616 + html += "<div id=\"field" + groupid + "_" + fid + "expr\" style=\"display: none\">" + exprname + "</div>";
  617 + html += "<td valign=top><nobr>";
  618 +
  619 + rec = addFieldTypeSelection(groupid, fid, type, null);
  620 +
  621 + html += rec.html;
  622 +
  623 + html += "<td width=\"55\" valign=top>";
  624 + html += "<input type=\"button\" value=\"{/literal}{i18n}remove{/i18n}{literal}\" onclick=\"delField(" + groupid + "," + fid + ")\">";
  625 + html += "</table>";
  626 +
  627 + var el = new Ext.Element(document.createElement('div'));
  628 + el.dom.id = "field" + groupid + "_" + fid;
  629 + el.id = el.dom.id;
  630 + el.dom.innerHTML = html;
  631 + el.appendTo('criteria_fields' + groupid);
  632 +
  633 + var el = $('field' + groupid + '_' + fid + 'start');
  634 +
  635 + if (el != null)
  636 + {
  637 + var map = new Ext.KeyMap(el,
  638 + {
  639 + stopEvent: true,
  640 + key: Ext.EventObject.ENTER,
  641 + fn: function() {
  642 + butSearchClick();
  643 + }
  644 + });
  645 + }
  646 +
  647 + var el = $('field' + groupid + '_' + fid + 'end');
  648 +
  649 + if (el != null)
  650 + {
  651 + var map = new Ext.KeyMap(el,
  652 + {
  653 + stopEvent: true,
  654 + key: Ext.EventObject.ENTER,
  655 + fn: function() {
  656 + butSearchClick();
  657 + }
  658 + });
  659 + }
  660 +
  661 +
  662 + if (rec.init != null)
  663 + {
  664 + rec.init(groupid, fid);
  665 + }
  666 + return fid;
  667 +}
  668 +
  669 +
  670 +
  671 +function fieldsetsChange(groupid)
  672 +{
  673 + var fieldsets = $('fieldsets' + groupid);
  674 + var fsid = fieldsets.selectedIndex -1;
  675 + if (fsid < 0)
  676 + {
  677 + $('fieldset_fields_wrapper' + groupid).style.display = 'none';
  678 + return;
  679 + }
  680 +
  681 + $('fieldset_fields_wrapper' + groupid).style.display = 'block';
  682 + $('fieldset_name' + groupid).innerHTML = '<nobr><B>' + meta_fieldsets[fsid].name + ' Fields:</b></nobr>';
  683 +
  684 + var fslist = $('fieldset_fields' + groupid);
  685 +
  686 + for(i=fslist.options.length-1;i>=0;i--)
  687 + {
  688 + fslist.remove(i);
  689 + }
  690 + var fields = meta_fieldsets[fsid].fields;
  691 + for (i=0;i<fields.length;i++)
  692 + {
  693 + var opt = new Option(fields[i].name, fields[i].id);
  694 + fslist.options[fslist.options.length] = opt;
  695 + }
  696 +}
  697 +function workflowsChange(groupid)
  698 +{
  699 + var workflows = $('workflows' + groupid);
  700 + var wid = workflows.selectedIndex -1;
  701 +
  702 + if (wid < 0)
  703 + {
  704 + $('workflow_states_wrapper' + groupid).style.display = 'none';
  705 + return;
  706 + }
  707 +
  708 + $('workflow_states_wrapper' + groupid).style.display = 'block';
  709 + $('workflow_name' + groupid).innerHTML = '<nobr><B>' +meta_workflows[wid].name + ' States:</b></nobr>';
  710 +
  711 + var wlist = $('workflow_states' + groupid);
  712 +
  713 + for(i=wlist.options.length-1;i>=0;i--)
  714 + {
  715 + wlist.remove(i);
  716 + }
  717 + var states = meta_workflows[wid].states;
  718 + for (i=0;i<states.length;i++)
  719 + {
  720 + var opt = new Option(states[i].name, states[i].id);
  721 + wlist.options[wlist.options.length] = opt;
  722 + }
  723 +}
  724 +function addCriteriaSet()
  725 +{
  726 + cs = criteria.length;
  727 +
  728 + criteria[cs] = {fields:0, visible:0};
  729 +
  730 + var wrapping = $('groupwrapping');
  731 + var wrapperTemplate = $('groupwrapper0');
  732 +
  733 + var content = wrapperTemplate.innerHTML;
  734 +
  735 + var words = ['groupwrapper0','groupop0','criteria0','criteria_nofields0','criteria_fields0','fieldsets0','selector0','workflows0',
  736 + 'fieldset_fields_wrapper0','fieldset_name0','fieldset_fields0','workflow_states_wrapper0','workflow_name0','workflow_states0',
  737 + 'selectorChange(0)','fieldChange(0)','fieldsetsChange(0)','workflowsChange(0)', 'fields0', 'form0', 'addMetadataField(0)', 'addWorkflowStateField(0)',
  738 + 'removeCriteriaGroup0', 'removeCriteriaGroup(0)'];
  739 +
  740 + for(i=0;i<words.length;i++)
  741 + {
  742 + var oldword = words[i];
  743 + var newword = oldword.replace('0', cs);
  744 + content = content.replace(oldword, newword);
  745 + }
  746 +
  747 + var el = new Ext.Element(document.createElement('div'));
  748 + el.dom.id = "groupwrapper" + cs;
  749 + el.id = el.dom.id;
  750 + el.dom.innerHTML = content;
  751 + el.appendTo(wrapping);
  752 +
  753 + $('selector' + cs).selectedIndex = 0;
  754 + $('groupop' + cs).selectedIndex = 1;
  755 + $('criteria_fields' + cs).innerHTML = '';
  756 + $('criteria_nofields' + cs).style.display = 'block';
  757 + $('removeCriteriaGroup' + cs).style.display = 'block';
  758 +
  759 + selectorChange(cs);
  760 +}
  761 +
  762 +function buildExpression()
  763 +{
  764 + mainOp = $('allop').value;
  765 +
  766 + var main_str = '';
  767 + var gv = 0;
  768 + for(var gid=0;gid<criteria.length;gid++)
  769 + {
  770 + if (criteria[gid].fields == 0)
  771 + {
  772 + continue;
  773 + }
  774 +
  775 + criteriaOp = $('groupop' + gid).value;
  776 + var set_str = '';
  777 +
  778 + var fv =0;
  779 + for(fid=1;fid<=criteria[gid].fields;fid++)
  780 + {
  781 + if ($('field' + gid + '_' + fid).innerHTML == '')
  782 + {
  783 + continue;
  784 + }
  785 + // by dp start // to build the expression with the multiselect field values
  786 + if (document.getElementById('field' + gid + '_' + fid + 'start').className == "inetlookup") {
  787 + var innerOp = $('field' + gid + '_' + fid + 'join').value;
  788 +
  789 + if (fv++ > 0) set_str += ' ' + criteriaOp + ' ';
  790 +
  791 + var fieldname = $('field' + gid + '_' + fid + 'expr').innerHTML;
  792 + var fieldop = $('field' + gid + '_' + fid + 'op').value;
  793 +
  794 + var start = getElByName(gid, 'field' + gid + '_' + fid + 'start');
  795 +
  796 + var count = 0;
  797 + var expr = expr = "";
  798 + if(typeof(start.options) == "undefined")
  799 + {
  800 + var chkMultiElems = document.getElementsByTagName("input");
  801 + for (ii = 0; ii < chkMultiElems.length; ii++) {
  802 + if(chkMultiElems[ii].type == "checkbox" && chkMultiElems[ii].className == "inetlookup" && chkMultiElems[ii].checked == true)
  803 + {
  804 + start = chkMultiElems[ii];
  805 + if ((count) > 0) expr += ' ' + innerOp + ' ';
  806 +
  807 + expr += fieldname + ' ' + fieldop + ' "' + start.value.replace(/\"/g, "'") + '"';
  808 +
  809 + count++;
  810 + }
  811 + }
  812 + }
  813 + else
  814 + {
  815 + for (ii = 0; ii < start.options.length; ii++) {
  816 + if (start.options[ii].selected) {
  817 + if ((count) > 0) expr += ' ' + innerOp + ' ';
  818 +
  819 + expr += fieldname + ' ' + fieldop + ' "' + start.options[ii].value.replace(/\"/g, "'") + '"';
  820 + count++;
  821 + }
  822 + }
  823 + }
  824 + if (expr != '')
  825 + {
  826 + expr = '(' + expr + ')';
  827 + }
  828 + }// by dp start // to build the expression with the multiselect field values
  829 + else {
  830 + if (fv++ > 0) set_str += ' ' + criteriaOp + ' ';
  831 +
  832 + var fieldname = $('field' + gid + '_' + fid + 'expr').innerHTML;
  833 + var fieldop = $('field' + gid + '_' + fid + 'op').value;
  834 +
  835 + var start = getElByName(gid, 'field' + gid + '_' + fid + 'start');
  836 + var end = getElByName(gid, 'field' + gid + '_' + fid + 'end');
  837 +
  838 + var expr = expr = fieldname + ' ' + fieldop + ' "' + start.value.replace(/\"/g, "'") + '"';
  839 + switch (fieldop)
  840 + {
  841 + case 'between':
  842 + case 'BETWEEN':
  843 + expr += ' AND "' + end.value.replace(/\"/g, "'") + '"';
  844 + break;
  845 + default:
  846 + break;
  847 + }
  848 + }
  849 +
  850 + set_str += expr;
  851 + }
  852 +
  853 + if (set_str != '')
  854 + {
  855 + set_str = '(' + set_str + ')';
  856 +
  857 + if (gv++ > 0) main_str += ' ' + mainOp + ' ';
  858 +
  859 + main_str += set_str;
  860 + }
  861 + }
  862 + return main_str;
  863 +}
  864 +
  865 +function butSearchClick()
  866 +{
  867 + var expr = buildExpression();
  868 +
  869 + if (expr == '')
  870 + {
  871 + alert('{/literal}{i18n}Please select some search criteria{/i18n}{literal}');
  872 + return;
  873 + }
  874 +
  875 + var txtQuery = document.getElementById('txtQuery');
  876 + txtQuery.value=expr;
  877 +
  878 +
  879 + var frm = document.getElementById('frmQuickSearch');
  880 + frm.submit();
  881 +}
  882 +
  883 +</script>
  884 +{/literal}
  885 +
  886 +<fieldset>
  887 + <legend>{i18n}Advanced Search{/i18n}</legend>
  888 +
  889 +{capture assign=options}
  890 +<a href="{$rootUrl}/search2.php?action=queryBuilder">{i18n}Search Criteria Editor{/i18n}</a>
  891 +{/capture}
  892 +
  893 +{i18n arg_options=$options}The #options# may also be used to create more complex search criteria expressions.{/i18n}
  894 +<br><br>
  895 +{capture assign=options}
  896 +<select id="allop">
  897 +<option value="AND">{i18n}all{/i18n}
  898 +<option value="OR" SELECTED>{i18n}any{/i18n}
  899 +</select>
  900 +{/capture}
  901 +
  902 +
  903 +{i18n arg_options=$options}Return items which match #options# of the criteria groups specified.{/i18n}
  904 +
  905 +<div id="groupwrapping">
  906 +<div id="groupwrapper0">
  907 + <fieldset>
  908 + <legend>{i18n}Criteria Group{/i18n}</legend>
  909 +
  910 + {capture assign=options}
  911 + <select id="groupop0">
  912 + <option value="AND">{i18n}all{/i18n}
  913 + <option value="OR" SELECTED>{i18n}any{/i18n}
  914 + </select>
  915 + {/capture}
  916 +
  917 + {i18n arg_options=$options}Return items which match #options# of the criteria specified below.{/i18n}
  918 + <br>
  919 +
  920 + <div id="criteria0">
  921 + <form id="form0" onsubmit="return false;">
  922 +
  923 + <table width="100%">
  924 + <tr>
  925 + <td width="50%" valign="top">
  926 + <br>
  927 + <div id="criteria_nofields0" style="color: brown">{i18n}No criteria have been selected for the criteria group.{/i18n}
  928 + <p>
  929 + <input type=button value="{i18n}Remove Criteria Group{/i18n}" onclick="removeCriteriaGroup(0)" id="removeCriteriaGroup0" style="display: none">
  930 + </div>
  931 + <div id="criteria_fields0">
  932 +
  933 + </div>
  934 + </td>
  935 + <td valign="top">
  936 + <table >
  937 + <tr>
  938 + <td valign=top>
  939 + <select id="selector0" style="width: 200px" onchange="selectorChange(0)">
  940 + <option value="0">{i18n}Available Criteria{/i18n}
  941 + <option value="1">{i18n}Available Fieldsets{/i18n}
  942 + <option value="2">{i18n}Available Workflows{/i18n}
  943 + </select>
  944 + <br>
  945 + <div>
  946 + <select id="fields0" size="5" style="width: 200px; height: 100px; display: block" onclick="fieldChange(0)">
  947 + <option value="" selected>--- {i18n}Select some criteria{/i18n} ---
  948 + {foreach from=$metainfo.fields item=field}
  949 + <option>{$field.display}
  950 + {/foreach}
  951 + </select>
  952 + <select id="fieldsets0" size="5" style="width: 200px; height: 100px; display: none" onclick="fieldsetsChange(0)">
  953 + <option value="" selected>--- {i18n}Select a fieldset{/i18n} ---
  954 + {foreach from=$metainfo.fieldsets item=fieldset}
  955 + <option>{$fieldset.name}
  956 + {/foreach}
  957 + </select>
  958 + <select id="workflows0" size="5" style="width: 200px; height: 100px; display: none" onclick="workflowsChange(0)" >
  959 + <option value="" selected>--- {i18n}Select a workflow{/i18n} ---
  960 + {foreach from=$metainfo.workflows item=workflow}
  961 + <option>{$workflow.name}
  962 + {/foreach}
  963 + </select>
  964 + </div>
  965 +
  966 + <td valign=top>
  967 + <div id="fieldset_fields_wrapper0" style="display: none"">
  968 + <div id="fieldset_name0"></div>
  969 + <select id="fieldset_fields0" size=5 style="width: 150px" onclick="addMetadataField(0)">
  970 + </select>
  971 +
  972 + </div>
  973 + <div id="workflow_states_wrapper0" style="display: none">
  974 + <div id="workflow_name0"></div>
  975 + <select id="workflow_states0" size=5 style="width: 150px" onclick="addWorkflowStateField(0)">
  976 + </select>
  977 +
  978 + </div>
  979 + </td>
  980 + <tr>
  981 + <td colspan=5>
  982 + {i18n}Click on a field above to add it to the criteria group.{/i18n}
  983 + </td>
  984 + </tr>
  985 + </table>
  986 + </td>
  987 + </tr>
  988 + </table>
  989 + </form>
  990 + </div>
  991 + </fieldset>
  992 +</div>
  993 +</div>
  994 +<div id="">
  995 +<input type=button value="{i18n}Add another set of criteria{/i18n}" onclick="addCriteriaSet()">
  996 +<input type=button value="{i18n}Search{/i18n}" onclick="butSearchClick()">
  997 +</div>
  998 +
  999 +
  1000 +</fieldset>
  1001 +</div>
... ...
plugins/multiselect/templates/manage_field.smarty 0 โ†’ 100644
  1 +{capture assign=sCSS}
  2 +{literal}
  3 +.twocolumn {
  4 + width: 60%;
  5 + margin-right: 1em;
  6 + float: left;
  7 + min-width: 28em;
  8 +}
  9 +
  10 +.second {
  11 + width: 30%;
  12 + margin-right: 0;
  13 +}
  14 +
  15 +{/literal}
  16 +{/capture}
  17 +{$context->oPage->requireCSSStandalone($sCSS)}
  18 +
  19 +<h2>{i18n arg_field_name=$field_name}Manage Field: #field_name#{/i18n}</h2>
  20 +
  21 +<p class="descriptiveText">{i18n}This page will allow you to manage the different
  22 +aspects of this particular field.{/i18n}</p>
  23 +
  24 +{if ($field->getHasLookup() or $field->getHasInetLookup())}
  25 + <div class="twocolumn">
  26 +{/if}
  27 + {$form->render()}
  28 +{if ($field->getHasLookup() or $field->getHasInetLookup())}
  29 + </div>
  30 + <div class="twocolumn second">
  31 + <fieldset>
  32 + <legend>{i18n}Extra Options{/i18n}</legend>
  33 +
  34 + <p class="descriptiveText">{i18n}Different fields have different actions and options available.{/i18n}</p>
  35 +
  36 + <p>
  37 + <a class="ktAction ktAdd ktActionDescribed" href="{addQS context=$context}fieldset_action=addlookupvalues{/addQS}">{i18n}Add Lookup Values{/i18n}</a>
  38 + <a href="{addQS context=$context}fieldset_action=addlookupvalues{/addQS}">{i18n}Add Lookup Values{/i18n}</a>
  39 + </p>
  40 +
  41 +
  42 + <p>
  43 + <a class="ktAction ktEdit ktActionDescribed" href="{addQS context=$context}fieldset_action=managelookups{/addQS}">{i18n}Manage Lookup Values{/i18n}</a>
  44 + <a href="{addQS context=$context}fieldset_action=managelookups{/addQS}">{i18n}Manage Lookup Values{/i18n}</a>
  45 + </p>
  46 + {if $field->getHasLookupTree()}
  47 + <p>
  48 + <a class="ktAction ktEdit ktActionDescribed" href="{addQS context=$context}fieldset_action=managetree{/addQS}">{i18n}Manage Lookup Tree Structure{/i18n}</a>
  49 + <a href="{addQS context=$context}fieldset_action=managetree{/addQS}">{i18n}Manage Lookup Tree Structure{/i18n}</a>
  50 + </p>
  51 + {/if}
  52 + </fieldset>
  53 + </div>
  54 +{/if}
  55 +<hr class="floatClear" />
... ...
plugins/multiselect/templates/multiselect/selection.smarty 0 โ†’ 100644
  1 +<div class="field {if ($has_errors)}error{/if}">
  2 + <label for="{$name}">{$label}{if ($required === true)}<span class="required">({i18n}Required{/i18n})</span>{/if}</label>
  3 + <p class="descriptiveText">{$description}</p>
  4 + {if empty($vocab)}
  5 + <div class="ktInfoMessage"><span>{$context->sEmptyMessage}</span></div>
  6 + {else}
  7 + <select name="{$name}{* multiselect change start *}{if $options.multi}[]{/if}{* multiselect change end *}"
  8 + {if $has_id}id="{$id}"{/if}
  9 + {if $options.multi}multiple="true"{/if}
  10 + >
  11 + {if $options.initial_string}
  12 + <option value="">{$options.initial_string}</option>
  13 + {/if}
  14 + {foreach item=lookup key=lookup_key from=$vocab}
  15 + {* multiselect change start *}
  16 + {if $options.multi}
  17 + {capture assign=selected}{""}{/capture}
  18 + {foreach item=value1 key=key from=$value}
  19 + {if $value1 == $lookup_key}
  20 + {capture assign=selected}selected='selected'{/capture}
  21 + {/if}
  22 + {/foreach}
  23 + <option value="{$lookup_key|sanitize}" {$selected} >{$lookup|sanitize}</option>
  24 + {else}{* multiselect change end *}
  25 + <option value="{$lookup_key|sanitize}" {if ($value == $lookup_key)}selected="selected"{/if}>{$lookup|sanitize}</option>
  26 + {* multiselect change start *}{/if}{* multiselect change end *}
  27 + {/foreach}
  28 + </select>
  29 +{/if}
  30 + </div>
0 31 \ No newline at end of file
... ...
plugins/multiselect/templates/multiselect/simple_selection.smarty 0 โ†’ 100644
  1 +<div class="field {if ($has_errors)}error{/if}">
  2 + <label for="{$name}">{$label}{if ($required === true)}<span class="required">({i18n}Required{/i18n})</span>{/if}</label>
  3 + <p class="descriptiveText">{$description}</p>
  4 + {if empty($vocab)}
  5 + <div class="ktInfoMessage"><span>{$context->sEmptyMessage}</span></div>
  6 + {else}
  7 +
  8 + {* radio or checkboxes *}
  9 + {if $options.multi}
  10 + {foreach item=lookup key=lookup_key from=$vocab}
  11 + <input type="checkbox" name="{$name}[]" value="{$lookup_key}" {if $context->selected($lookup_key)}checked="true"{/if}>{$lookup} <br />
  12 + {/foreach}
  13 + {else}
  14 + {if $options.initial_string}
  15 + <input type="radio" name="{$name}" {if $context->selected('')}checked="true"{/if}>{$options.initial_string} <br />
  16 + {/if}
  17 + {foreach item=lookup key=lookup_key from=$vocab}
  18 + <input type="radio" name="{$name}" value="{$lookup_key}" {if $context->selected($lookup_key)}checked="true"{/if}>{$lookup} <br />
  19 + {/foreach}
  20 + {/if}
  21 +
  22 + {/if}
  23 + </div>
0 24 \ No newline at end of file
... ...
resources/js/constructed_search.js
... ... @@ -120,10 +120,18 @@ function do_addNewCriteria(destination_cell, crit_id, table_id, req) {
120 120 for (var i=0; i<inputs.length; i++) {
121 121 var obj = inputs[i];
122 122 obj.name = "boolean_search[subgroup]["+table_id+"][values]["+crit_id+"][data]["+obj.name+"]";
  123 + if(obj.getAttribute("type") == "checkbox" && obj.getAttribute("class") == "multiple")
  124 + {
  125 + obj.name = obj.name+"[]";
  126 + }
123 127 }
124 128 for (var i=0; i<selects.length; i++) {
125 129 var obj = selects[i];
126 130 obj.name = "boolean_search[subgroup]["+table_id+"][values]["+crit_id+"][data]["+obj.name+"]";
  131 + if(obj.getAttribute("multiple") == "multiple")
  132 + {
  133 + obj.name = obj.name+"[]";
  134 + }
127 135 }
128 136 simpleLog('DEBUG','criteria addition complete.');
129 137 }
... ...
resources/js/constructed_search_postprocess.js
... ... @@ -37,12 +37,20 @@ function processRow(tablerow, parent_table) {
37 37 for (var i=1; i<inputs.length-1; i++) {
38 38 var obj = inputs[i];
39 39 obj.name = "boolean_search[subgroup]["+table_id+"][values]["+crit_id+"][data]["+obj.name+"]";
  40 + if(obj.getAttribute("type") == "checkbox" && obj.getAttribute("class") == "multiple")
  41 + {
  42 + obj.name = obj.name+"[]";
  43 + }
40 44 }
41 45  
42 46 for (var i=0; i<selects.length; i++) {
43 47 var obj = selects[i];
44 48 obj.name = "boolean_search[subgroup]["+table_id+"][values]["+crit_id+"][data]["+obj.name+"]";
45   - }
  49 + if(obj.getAttribute("multiple") == "multiple")
  50 + {
  51 + obj.name = obj.name+"[]";
  52 + }
  53 + }
46 54 }
47 55  
48 56 }
... ...
search2/search/search.inc.php
... ... @@ -253,12 +253,19 @@ class SearchHelper
253 253 foreach($fields as $field)
254 254 {
255 255 if ($fo++ >0) $fieldset_str .= ',';
256   - $fid = $field['id'];
257   - $name= searchfix($field['name']);
258   - $desc = searchfix($field['description']);
259   - $datatype=$field['datatype'];
260   - $control=$field['control'];
261   - $fieldset_str .= "\n\t\t{id:\"$fid\", name:\"$name\", description:\"$desc\", datatype:\"$datatype\", control:\"$control\", options: [";
  256 + $fid = $field['id'];
  257 + $name= searchfix($field['name']);
  258 + $desc = searchfix($field['description']);
  259 + $datatype=$field['datatype'];
  260 + $control=$field['control'];
  261 +
  262 + if(KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin') && isset($field['inetlookup_type']) && $field['inetlookup_type'] != "") {
  263 + $inetlookup_type=$field['inetlookup_type'];
  264 + $fieldset_str .= "\n\t\t{id:\"$fid\", name:\"$name\", description:\"$desc\", datatype:\"$datatype\", control:\"$control\", inetlookup_type:\"$inetlookup_type\" , options: [";
  265 + } else {
  266 + $fieldset_str .= "\n\t\t{id:\"$fid\", name:\"$name\", description:\"$desc\", datatype:\"$datatype\", control:\"$control\", options: [";
  267 + }
  268 +
262 269 $options = $field['options'];
263 270 $oo = 0;
264 271 if (!is_array($options))
... ... @@ -453,20 +460,40 @@ class SearchHelper
453 460 if ($fieldsetID < 0)
454 461 {
455 462 $documentTypeID = sanitizeForSQL(-$fieldsetID);
456   - $sql = "SELECT
457   - df.id, df.name, df.data_type, df.has_lookup, df.has_lookuptree, df.description
  463 +
  464 + if(KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin')) {
  465 + $sql = "SELECT
  466 + df.id, df.name, df.data_type, df.has_lookup,df.has_inetlookup, df.inetlookup_type , df.has_lookuptree, df.description
458 467 FROM
459 468 document_type_fields_link dtfl
460   - INNER JOIN document_fields df on dtfl.field_id=df.id
  469 + INNER JOIN document_fields df on dtfl.field_id=df.id
461 470 WHERE
462 471 dtfl.document_type_id=$documentTypeID
463 472 ORDER BY
464 473 df.name";
465   - }
  474 + } else {
  475 +
  476 + $sql = "SELECT
  477 + df.id, df.name, df.data_type, df.has_lookup, df.has_lookuptree, df.description
  478 + FROM
  479 + document_type_fields_link dtfl
  480 + INNER JOIN document_fields df on dtfl.field_id=df.id
  481 + WHERE
  482 + dtfl.document_type_id=$documentTypeID
  483 + ORDER BY
  484 + df.name";
  485 + }
  486 + }
466 487 else
467 488 {
468 489 $fieldsetID = sanitizeForSQL($fieldsetID);
469   - $sql = "SELECT id, name, data_type, has_lookup, has_lookuptree, description FROM document_fields WHERE parent_fieldset=$fieldsetID ORDER BY name";
  490 + if(KTPluginUtil::pluginIsActive('inet.multiselect.lookupvalue.plugin'))
  491 + {
  492 + $sql = "SELECT id, name, data_type, has_lookup,has_inetlookup, inetlookup_type, has_lookuptree, description FROM document_fields WHERE parent_fieldset=$fieldsetID ORDER BY name";
  493 + } else {
  494 + $sql = "SELECT id, name, data_type, has_lookup, has_lookuptree, description FROM document_fields WHERE parent_fieldset=$fieldsetID ORDER BY name";
  495 + }
  496 +
470 497 }
471 498  
472 499 $rs = DBUtil::getResultArray($sql);
... ... @@ -487,14 +514,23 @@ class SearchHelper
487 514 $options = array();
488 515 $haslookup =$item['has_lookup'] + 0 > 0;
489 516 $hastree = ($item['has_lookuptree']+0 > 1);
490   -
491   - if ($haslookup || $hastree)
  517 + $hasinetlookup=$item['has_inetlookup'] + 0 > 0;
  518 +
  519 + if ($haslookup || $hastree || $hasinetlookup)
492 520 {
493 521 $type = 'lookup';
494 522 $sql = "select id, name from metadata_lookup where document_field_id=$fieldid";
495 523 $options = DBUtil::getResultArray($sql);
496 524  
497 525 }
  526 +
  527 + $inetlookup_type = "";
  528 + if($hasinetlookup)
  529 + {
  530 + $type = 'inetlookup';
  531 + $inetlookup_type = $item['inetlookup_type'];
  532 + }
  533 +
498 534 /*if ($hastree)
499 535 {
500 536 $type = 'lookup';
... ... @@ -515,6 +551,7 @@ class SearchHelper
515 551 'description'=>$item['description'],
516 552 'datatype'=>$item['data_type'],
517 553 'control'=>$type,
  554 + 'inetlookup_type' => $inetlookup_type,
518 555 'options'=>$options
519 556 );
520 557  
... ... @@ -775,7 +812,7 @@ function resolveSearchShortcuts($result)
775 812 {
776 813 $id = $row['id'];
777 814 $linked_id = $row['linked_folder_id'];
778   -
  815 +
779 816 $shortFolder = new FolderShortcutResultItem($id, $result['folders'][$linked_id]);
780 817 $shortFolder->parentId = $row['parent_id'];
781 818 $shortFolder->linkedId = $row['linked_folder_id'];
... ...
setup/wizard/lib/services/windowsOpenOffice.php
... ... @@ -42,10 +42,121 @@
42 42  
43 43 class windowsOpenOffice extends windowsService {
44 44  
  45 + // utility
  46 + public $util;
  47 + // path to office
  48 + private $path;
  49 + // host
  50 + private $host;
  51 + // pid running
  52 + private $pidFile;
  53 + // port to bind to
  54 + private $port;
  55 + // bin folder
  56 + private $bin;
  57 + // office executable
  58 + private $soffice;
  59 + // office log file
  60 + private $log;
  61 + private $options;
  62 + private $winservice;
45 63  
46 64 public function __construct() {
47   - $this->name = "KTOpenOfficeTest";
  65 + $this->name = "openoffice";
  66 + $this->util = new InstallUtil();
48 67 }
  68 +
  69 + public function load() {
  70 + // hack for testing
  71 + $this->setPort("8100");
  72 + $this->setHost("127.0.0.1");
  73 + $this->setLog("openoffice.log");
  74 + $this->setBin("C:\Program Files (x86)\OpenOffice.org 3\program\soffice.bin");
  75 + $this->setBin("C:\Program Files (x86)\ktdms\openoffice\program\soffice.bin");
  76 + $this->setBin("C:\Program Files (x86)\ktdms\openoffice.2.4\program\soffice.bin");
  77 + $this->setWinservice("winserv.exe");
  78 + $this->setOption();
  79 + }
  80 +
  81 + private function setPort($port = "8100") {
  82 + $this->port = $port;
  83 + }
  84 +
  85 + public function getPort() {
  86 + return $this->port;
  87 + }
  88 +
  89 + private function setHost($host = "127.0.0.1") {
  90 + $this->host = $host;
  91 + }
  92 +
  93 + public function getHost() {
  94 + return $this->host;
  95 + }
  96 +
  97 + private function setLog($log = "openoffice.log") {
  98 + $this->log = $log;
  99 + }
  100 +
  101 + public function getLog() {
  102 + return $this->log;
  103 + }
  104 +
  105 + private function setBin($bin = "soffice") {
  106 + $this->bin = $bin;
  107 + }
  108 +
  109 + public function getBin() {
  110 + return $this->bin;
  111 + }
  112 +
  113 + private function setWinservice($winservice = "winserv.exe") {
  114 + $this->winservice = SYS_BIN_DIR . $winservice;
  115 + }
  116 +
  117 + public function getWinservice() {
  118 + return $this->winservice;
  119 + }
  120 +
  121 + private function setOption() {
  122 + $this->options = "-displayname {$this->name} -start auto \"{$this->bin}\" -headless -invisible "
  123 + . "-accept=socket,host={$this->host},port={$this->port};urp;";
  124 + }
  125 +
  126 + public function getOption() {
  127 + return $this->options;
  128 + }
  129 +
  130 + public function install() {
  131 + $status = $this->status();
  132 +
  133 + if($status == '') {
  134 + $cmd = "\"{$this->winservice}\" install $this->name $this->options";
  135 + $response = $this->util->pexec($cmd);
  136 + return $response;
  137 + }
  138 + else {
  139 + return $status;
  140 + }
  141 + }
  142 +
  143 +// public function start() {
  144 +// $state = $this->status();
  145 +// if($state != 'STARTED') {
  146 +// $cmd = 'sc start ' . $this->name;
  147 +// $response = $this->util->pexec($cmd);
  148 +//
  149 +// return $response;
  150 +// } elseif ($state == '') {
  151 +// // Start Service
  152 +// return true;
  153 +// } else {
  154 +// // Service Running Already
  155 +// return true;
  156 +// }
  157 +//
  158 +// return false;
  159 +// }
49 160  
50 161 }
51 162 ?>
52 163 \ No newline at end of file
... ...
setup/wizard/lib/services/windowsScheduler.php
... ... @@ -181,12 +181,17 @@ class windowsScheduler extends windowsService {
181 181 fclose($fp);
182 182 }
183 183 }
184   - $response = win32_create_service(array(
185   - 'service' => $this->name,
186   - 'display' => $this->name,
187   - 'path' => $this->getSchedulerScriptPath()
188   - ));
189   - return $response;
  184 +
  185 + // TODO what if it does not exist? check how the dmsctl.bat does this
  186 + if (function_exists('win32_create_service'))
  187 + {
  188 + $response = win32_create_service(array(
  189 + 'service' => $this->name,
  190 + 'display' => $this->name,
  191 + 'path' => $this->getSchedulerScriptPath()
  192 + ));
  193 + return $response;
  194 + }
190 195 }
191 196 return $state;
192 197 }
... ...
templates/ktcore/forms/widgets/selection.smarty
... ... @@ -9,8 +9,17 @@
9 9 <option value="">{$options.initial_string}</option>
10 10 {/if}
11 11 {foreach item=lookup key=lookup_key from=$vocab}
12   -
13   - <option value="{$lookup_key|sanitize}" {if $context->selected($lookup_key)}selected="selected"{/if}>{$lookup|sanitize}</option>
  12 + {if $options.multi}
  13 + {capture assign=selected}{""}{/capture}
  14 + {foreach item=value1 key=key from=$value}
  15 + {if $value1 == $lookup_key}
  16 + {capture assign=selected}selected='selected'{/capture}
  17 + {/if}
  18 + {/foreach}
  19 + <option value="{$lookup_key|sanitize}" {$selected} >{$lookup|sanitize}</option>
  20 + {else}
  21 + <option value="{$lookup_key|sanitize}" {if ($value == $lookup_key)}selected="selected"{/if}>{$lookup|sanitize}</option>
  22 + {* multiselect change start *}{/if}
14 23 {/foreach}
15 24 </select>
16 25 {/if}
... ...