Commit 123491ecf05758ad4776d6b4fa7156862c57467d

Authored by Charl Joseph Mert
1 parent 638ee683

KTS-4605 Conditional Metadata not working in KTAPI get_metadata(SUP-2537)

PT:2630614

Resolved javascript conflict for large text and conditional fields on the same page.
Also fixed the bulk upload pages conditional list constraining on ajax load.

Committed by: Charl Joseph Mert
Reviewed by: Megan Watson
lib/metadata/fieldset.inc.php
... ... @@ -186,6 +186,18 @@ class KTFieldset extends KTEntity {
186 186 ), $aOptions);
187 187 }
188 188  
  189 + function &getConditionalFieldsets($aOptions = null) {
  190 + $aOptions = KTUtil::meldOptions(
  191 + $aOptions,
  192 + array('multi' => true,)
  193 + );
  194 + return KTEntityUtil::getByDict('KTFieldset', array(
  195 + 'is_conditional' => true,
  196 + 'disabled' => false,
  197 + ), $aOptions);
  198 + }
  199 +
  200 +
189 201 function &getForDocumentType($oDocumentType, $aOptions = null) {
190 202 $bIds = KTUtil::arrayGet($aOptions, 'ids');
191 203 if (is_object($oDocumentType)) {
... ...
lib/metadata/fieldsetregistry.inc.php
... ... @@ -92,7 +92,7 @@ class KTFieldsetRegistry {
92 92 *
93 93 */
94 94 function getHtmlFields($oFieldset, $idPre = 'metadata_') {
95   - $fields = $oFieldset->getFields();
  95 + $fields = $oFieldset->getFields();
96 96 $textAreaIds = array();
97 97  
98 98 foreach($fields as $field) {
... ... @@ -103,7 +103,6 @@ class KTFieldsetRegistry {
103 103  
104 104 return $textAreaIds;
105 105 }
106   -
107 106  
108 107 /*
109 108 * Returns an array of fieldIds which belong to a generic fieldset
... ... @@ -156,6 +155,11 @@ class KTFieldsetRegistry {
156 155 }
157 156  
158 157 foreach ($newfields as $oField) {
  158 + // If a conditional field hasn't been set up properly this will throw errors.
  159 + // TODO: display a message indicating that admin must complete the setup.
  160 + if (PEAR::isError($oField)) {
  161 + continue;
  162 + }
159 163 $fname = 'metadata_' . $oField->getId();
160 164 $value = null;
161 165  
... ...
plugins/ktcore/KTWidgets.php
... ... @@ -973,7 +973,8 @@ class KTCoreTextAreaWidget extends KTWidget {
973 973 $oTemplate = $oTemplating->loadTemplate('ktcore/forms/widgets/base');
974 974  
975 975 $this->aJavascript[] = 'thirdpartyjs/jquery/jquery-1.3.2.js';
976   - $this->aJavascript[] = 'thirdpartyjs/tinymce/jscripts/tiny_mce/tiny_mce.js';
  976 + $this->aJavascript[] = 'thirdpartyjs/jquery/jquery_noconflict.js';
  977 + $this->aJavascript[] = 'thirdpartyjs/tinymce/jscripts/tiny_mce/tiny_mce.js';
977 978 $this->aJavascript[] = 'resources/js/kt_tinymce_init.js';
978 979  
979 980 if (!empty($this->aJavascript)) {
... ...
plugins/multiselect/BulkUpload.php
... ... @@ -141,7 +141,8 @@ class InetBulkUploadFolderAction extends KTFolderAction {
141 141 $aJavascript[] = 'thirdpartyjs/tinymce/jscripts/tiny_mce/tiny_mce.js';
142 142 $aJavascript[] = 'resources/js/kt_tinymce_init.js';
143 143 $aJavascript[] = 'thirdpartyjs/tinymce/jscripts/tiny_mce/jquery.tinymce.js';
144   -
  144 + $aJavascript[] = 'resources/js/conditional_selection.js';
  145 +
145 146 $this->oPage->requireJSResources($aJavascript);
146 147  
147 148 //FIXME: Might really not need to load these styles, will check l8r
... ...
presentation/lookAndFeel/knowledgeTree/ajaxConditional.php
... ... @@ -45,6 +45,11 @@ require_once(KT_LIB_DIR . "/util/ktutil.inc");
45 45 require_once(KT_LIB_DIR . "/dispatcher.inc.php");
46 46 require_once(KT_LIB_DIR . '/widgets/fieldsetDisplay.inc.php');
47 47  
  48 +require_once(KT_LIB_DIR . "/metadata/fieldsetregistry.inc.php");
  49 +require_once(KT_LIB_DIR . "/widgets/widgetfactory.inc.php");
  50 +require_once(KT_LIB_DIR . "/validation/validatorfactory.inc.php");
  51 +
  52 +
48 53 /*
49 54 * example code - tests the frontend behaviour. remember to check ajaxConditional.php
50 55 *
... ... @@ -102,6 +107,82 @@ class AjaxConditionalDispatcher extends KTStandardDispatcher {
102 107  
103 108 return $sWidgets;
104 109 }
  110 +
  111 +
  112 +
  113 +
  114 + function _getFieldIdForMetadataId($iMetadata) {
  115 + $sTable = 'metadata_lookup';
  116 + $sQuery = "SELECT document_field_id FROM " . $sTable . " WHERE id = ?";
  117 + $aParams = array($iMetadata);
  118 +
  119 + $res = DBUtil::getOneResultKey(array($sQuery, $aParams), 'document_field_id');
  120 + if (PEAR::isError($res)) {
  121 + return false;
  122 + }
  123 + return $res;
  124 + }
  125 +
  126 + //http://localhost/knowledgetree/presentation/lookAndFeel/knowledgeTree/ajaxConditional.php?action=getConditionalData&masterid=6&type=connections
  127 + //http://localhost/knowledgetree/presentation/lookAndFeel/knowledgeTree/ajaxConditional.php?action=getConditionalData&masterid=6&type=lookups
  128 + //$type can be lookups or connections
  129 + function do_getConditionalData(){
  130 + $iMetadata = $_GET['masterid'];
  131 + $type = $_GET['type'];
  132 +
  133 + $oFReg =& KTFieldsetRegistry::getSingleton();
  134 + $oFieldSets = KTFieldset::getConditionalFieldsets();
  135 +
  136 + foreach ($oFieldSets as $oFieldset) {
  137 +
  138 + $aLookups = array();
  139 + $aConnections = array();
  140 +
  141 + foreach($oFieldset->getFields() as $oField) {
  142 + $c = array();
  143 +
  144 + foreach($oField->getEnabledValues() as $oMetadata) {
  145 + $a = array();
  146 + // print '<pre>';
  147 +
  148 + $nvals = KTMetadataUtil::getNextValuesForLookup($oMetadata->getId());
  149 + if($nvals) {
  150 + foreach($nvals as $i=>$aVals) {
  151 + $a = array_merge($a, $aVals);
  152 +
  153 + foreach($aVals as $id) {
  154 + $field = $this->_getFieldIdForMetadataId($id);
  155 + // print 'id ' . $id . ' is in field ' . $field . "<br/>";
  156 + if(!in_array($field, $c)) {
  157 + $c[] = $field;
  158 + }
  159 + }
  160 + }
  161 + }
  162 +
  163 + $aLookups[$oMetadata->getId()] = $a;
  164 + }
  165 + $aConnections[$oField->getId()] = $c;
  166 + }
  167 +
  168 + //exit(0);
  169 +
  170 + $oJSON = new Services_JSON;
  171 + switch ($type) {
  172 + case 'lookups':
  173 + return $oJSON->encode($aLookups);
  174 + break;
  175 + case 'connections' :
  176 + return $oJSON->encode($aConnections);
  177 + break;
  178 + default:
  179 + return $oJSON->encode($aLookups);
  180 + }
  181 +
  182 + return false;
  183 + }
  184 + }
  185 +
105 186 }
106 187  
107 188 $oDispatcher = new AjaxConditionalDispatcher();
... ...
resources/js/conditional_selection.js
1   -// 'lookups' and 'connections' are produced by the master conditional widget
  1 +// depricated: 'lookups' and 'connections' are produced by the master conditional widget
  2 +// 'lookups' and 'connections' are now dynamically callable via ajax request to get a json response
  3 +
2 4 var NOSELECTION = 'No selection.';
3 5  
4 6 function ConditionalSelection() {
... ... @@ -27,135 +29,159 @@ function getId(elm) {
27 29  
28 30 ConditionalSelection.prototype = {
29 31 'initialize' : function(masterId) {
  32 +
30 33 // make clones of the original nodes to keep the options in
31 34 var fieldLookups = {};
32 35 var current = {};
  36 +
  37 + /*
33 38 var lookups = eval('lookups_' + masterId);
34 39 var connections = eval('connections_' + masterId);
35   -
36   - // initialize - build various tables
37   - forEach(getElementsByTagAndClassName(null, 'is_conditional_' + masterId),
38   - function(elm) {
39   - var fieldId = getId(elm);
40   - for(var i=0; i<elm.options.length; i++) {
41   - var oElm = elm.options[i];
42   - var lookupId = oElm.id.substring('lookup_'.length);
43   - fieldLookups[lookupId] = {'parent':fieldId, 'value':oElm.innerHTML};
44   -
45   - if(oElm.selected && oElm.value) {
46   - current[fieldId] = oElm.value;
47   - }
48   - }
49   - });
50   -
51   - // the following function are defined inline, as they depend on the
52   - // 'lookups' and 'connections' being specified above
53   -
54   - function clearConnected(fieldId) {
55   - if(!fieldId in connections || !connections[fieldId].length) {
56   - return;
57   - }
58   - for(var i=0; i<connections[fieldId].length; i++) {
59   - var field = $('field_'+connections[fieldId][i]);
60   - replaceChildNodes(field, OPTION(null, NOSELECTION));
61   - field.disabled = true;
62   - clearConnected(connections[fieldId][i]);
63   - }
64   - }
  40 + */
  41 +
  42 + var lookups = null;
  43 + var connections = null;
  44 +
  45 + // Making the conditional selection rules dynamically envokable. This enables conditional metadata fields to be used as ajax loaded dom elements.
  46 + // Needed for the Bulk Upload metadata page.
  47 +
  48 + jQuery.getJSON('presentation/lookAndFeel/knowledgeTree/ajaxConditional.php?action=getConditionalData&masterid=' + masterId + '&type=lookups',
  49 + function(json){
  50 + lookups = json;
  51 +
  52 + jQuery.getJSON('presentation/lookAndFeel/knowledgeTree/ajaxConditional.php?action=getConditionalData&masterid=' + masterId + '&type=connections',
  53 + function(json){
  54 + connections = json;
  55 +
  56 + // initialize - build various tables
  57 + forEach(getElementsByTagAndClassName(null, 'is_conditional_' + masterId),
  58 + function(elm) {
  59 + var fieldId = getId(elm);
  60 + for(var i=0; i<elm.options.length; i++) {
  61 + var oElm = elm.options[i];
  62 + var lookupId = oElm.id.substring('lookup_'.length);
  63 + fieldLookups[lookupId] = {'parent':fieldId, 'value':oElm.innerHTML};
  64 +
  65 + if(oElm.selected && oElm.value) {
  66 + current[fieldId] = oElm.value;
  67 + }
  68 + }
  69 + });
  70 +
  71 + // the following function are defined inline, as they depend on the
  72 + // 'lookups' and 'connections' being specified above
  73 +
  74 + function clearConnected(fieldId) {
  75 + if(!fieldId in connections || !connections[fieldId].length) {
  76 + return;
  77 + }
  78 + for(var i=0; i<connections[fieldId].length; i++) {
  79 + var field = $('field_'+connections[fieldId][i]);
  80 + replaceChildNodes(field, OPTION(null, NOSELECTION));
  81 + field.disabled = true;
  82 + clearConnected(connections[fieldId][i]);
  83 + }
  84 + }
  85 +
  86 +
  87 + function clearInvalid(fieldId) {
  88 + if(!fieldId in connections || !connections[fieldId].length) {
  89 + return;
  90 + }
  91 +
  92 + var parentField = $('field_'+fieldId);
  93 + var selectedId = getId(parentField.options[parentField.selectedIndex]);
  94 + var options = lookups[selectedId];
  95 +
  96 + if(parentField.options[parentField.selectedIndex].innerHTML == NOSELECTION) {
  97 + clearConnected(fieldId);
  98 + } else {
  99 + for(var i=0; i<connections[fieldId].length; i++) {
  100 + var field = $('field_'+connections[fieldId][i]);
  101 + var newOptions = [];
  102 + var selected = null;
  103 +
  104 + for(var j=0; j<field.options.length; j++) {
  105 + var opt = field.options[j];
  106 + if(!(opt.innerHTML != NOSELECTION && !in_array(options, getId(opt)))) {
  107 + newOptions.push(opt);
  108 + }
  109 +
  110 + if(j == field.selectedIndex && opt.id && in_array(options, getId(opt))) {
  111 + selected = opt.id;
  112 + }
  113 + }
  114 +
  115 + field.selectedIndex = 0;
  116 + replaceChildNodes(field, null);
  117 +
  118 +
  119 + for(var j=0; j<newOptions.length; j++) {
  120 + var opt = newOptions[j];
  121 + appendChildNodes(field, opt);
  122 +
  123 + if(selected != null) {
  124 + if(opt.id && opt.id == selected) { // || j == 0 && field.selectedIndex == 0) {
  125 + field.selectedIndex = j;
  126 + }
  127 + }
  128 + }
  129 +
  130 + if(selected == null) {
  131 + field.selectedIndex = 0;
  132 + field.options[0].selected = 'selected';
  133 + }
  134 +
  135 +
  136 + clearInvalid(connections[fieldId][i]);
  137 + }
  138 + }
  139 + }
  140 +
  141 + // instead of clearing here, we remove the non-applicable options
  142 + // this should handle the case with existing selections
  143 + clearInvalid(masterId);
  144 +
  145 +
  146 + function populateForSelection(selectedId) {
  147 + if(selectedId in lookups) {
  148 + for(var i=0; i<lookups[selectedId].length; i++) {
  149 + var lookupId = lookups[selectedId][i];
  150 + var lookupInfo = fieldLookups[lookupId];
  151 +
  152 + var parent = $('field_' + lookupInfo['parent']);
  153 + appendChildNodes(parent,
  154 + OPTION({'value':lookupInfo['value'], 'id':'lookup_' + lookupId},
  155 + lookupInfo['value']));
  156 + parent.disabled = false;
  157 + }
  158 + }
  159 + }
  160 +
  161 +
  162 + forEach(getElementsByTagAndClassName(null, 'is_conditional_' + masterId), function(elm) {
  163 + // check if this field connects to anything else
  164 + var fieldId = elm.id.substring('field_'.length);
  165 + if(fieldId in connections && connections[fieldId].length) {
  166 + var controller = true;
  167 + }
  168 +
  169 + if(controller) {
  170 + connect(elm, 'onchange',
  171 + function() {
  172 + var selectedId = elm.options[elm.selectedIndex].id.substring('lookup_'.length);
  173 + var touched = [];
  174 + clearConnected(fieldId);
  175 + populateForSelection(selectedId);
  176 + });
  177 + }
  178 + });
  179 +
  180 + //---------- End Inner Functions
  181 + });
  182 + });
  183 +
65 184  
66   -
67   - function clearInvalid(fieldId) {
68   - if(!fieldId in connections || !connections[fieldId].length) {
69   - return;
70   - }
71   -
72   - var parentField = $('field_'+fieldId);
73   - var selectedId = getId(parentField.options[parentField.selectedIndex]);
74   - var options = lookups[selectedId];
75   -
76   - if(parentField.options[parentField.selectedIndex].innerHTML == NOSELECTION) {
77   - clearConnected(fieldId);
78   - } else {
79   - for(var i=0; i<connections[fieldId].length; i++) {
80   - var field = $('field_'+connections[fieldId][i]);
81   - var newOptions = [];
82   - var selected = null;
83   -
84   - for(var j=0; j<field.options.length; j++) {
85   - var opt = field.options[j];
86   - if(!(opt.innerHTML != NOSELECTION && !in_array(options, getId(opt)))) {
87   - newOptions.push(opt);
88   - }
89   -
90   - if(j == field.selectedIndex && opt.id && in_array(options, getId(opt))) {
91   - selected = opt.id;
92   - }
93   - }
94   -
95   - field.selectedIndex = 0;
96   - replaceChildNodes(field, null);
97   -
98   -
99   - for(var j=0; j<newOptions.length; j++) {
100   - var opt = newOptions[j];
101   - appendChildNodes(field, opt);
102   -
103   - if(selected != null) {
104   - if(opt.id && opt.id == selected) { // || j == 0 && field.selectedIndex == 0) {
105   - field.selectedIndex = j;
106   - }
107   - }
108   - }
109   -
110   - if(selected == null) {
111   - field.selectedIndex = 0;
112   - field.options[0].selected = 'selected';
113   - }
114   -
115   -
116   - clearInvalid(connections[fieldId][i]);
117   - }
118   - }
119   - }
120   -
121   - // instead of clearing here, we remove the non-applicable options
122   - // this should handle the case with existing selections
123   - clearInvalid(masterId);
124   -
125   -
126   - function populateForSelection(selectedId) {
127   - if(selectedId in lookups) {
128   - for(var i=0; i<lookups[selectedId].length; i++) {
129   - var lookupId = lookups[selectedId][i];
130   - var lookupInfo = fieldLookups[lookupId];
131   -
132   - var parent = $('field_' + lookupInfo['parent']);
133   - appendChildNodes(parent,
134   - OPTION({'value':lookupInfo['value'], 'id':'lookup_' + lookupId},
135   - lookupInfo['value']));
136   - parent.disabled = false;
137   - }
138   - }
139   - }
140   -
141   -
142   - forEach(getElementsByTagAndClassName(null, 'is_conditional_' + masterId), function(elm) {
143   - // check if this field connects to anything else
144   - var fieldId = elm.id.substring('field_'.length);
145   - if(fieldId in connections && connections[fieldId].length) {
146   - var controller = true;
147   - }
148   -
149   - if(controller) {
150   - connect(elm, 'onchange',
151   - function() {
152   - var selectedId = elm.options[elm.selectedIndex].id.substring('lookup_'.length);
153   - var touched = [];
154   - clearConnected(fieldId);
155   - populateForSelection(selectedId);
156   - });
157   - }
158   - });
159 185 }
160 186 }
161 187  
... ...