Commit cd31c401 authored by Aaron Harder's avatar Aaron Harder

Merge branch 'master' into feature/3.0/pending

* master:
  feature/mtc-836 removed console.log calls
  made adding on the back of the url more flexible.
  added functionality to bl-selector with no extension and with hash and/or query.
  FSE-589 removed underscore replaces
  FSE-589 updated add path name to replace with hyphen instead of underscore
  reverting to regular collections.testPath
  all collections changes are important
  Issue 20 if err getting slingData, change to just resourceType rather than compiling/rendering hbs with error data
  fixes to component queries and queries without wildcard endings
  all collections changes are important
  track number of items with template id. added help text
  updating POST to work through the AEM proxy
  lots of enhancments to data mapping UI. support for --params in bl:querys
  data mapping ui enhancments. updating restub primaryType order
  temporarily removing fieldMapping
  add option to allow local children for a bl:q
  respect sourcemapping even for parent pages being created
  wip
  wip
parents f861388e 92a7767a
......@@ -49,6 +49,7 @@ module.exports = function restubFromBlQuery(params, cb){
var slingTemplatePath = querySpecification.slingTemplate;
var slingTemplateContent;
var sourceMapping = querySpecification.sourceMapping;
var allowLocalChildren = querySpecification.allowLocalChildren || false;
if(!queryPath){cb("No 'bl:query' property found at path: " + path); return;}
if(!_.isArray(resourceTypes)){cb("Must be an array. Bad 'resourceTypes' value at bl:query path: " + path); return;}
......@@ -236,7 +237,7 @@ module.exports = function restubFromBlQuery(params, cb){
allNewNodes.push({name:_path.join(curParentPath, "jcr:content", "jcr:primaryType"), value:"cq:PageContent"})
allNewNodes.push({name:_path.join(curTargetPath, "jcr:content", "jcr:title"), value: global.bl.prettyName(parentPart)})
}
var templateContentResult = templateContent({resourceType: resourceTypes[idx], targetPath: _path.join(targetPath,curParentPath) , prefix: curParentPath + jcrContentNode});
var templateContentResult = templateContent({resourceType: resourceTypes[idx], targetPath: (sourceMapping ? sourcePath : _path.join(targetPath,curParentPath)) , prefix: curParentPath + jcrContentNode});
if(_.isArray(templateContentResult)){
allNewNodes = allNewNodes.concat(templateContentResult);
}else{
......@@ -252,6 +253,7 @@ module.exports = function restubFromBlQuery(params, cb){
var resourceType = resourceTypes[curParentParts.length];
if(pageMode){
allNewNodes.push({name:_path.join(curTargetPath, "jcr:primaryType"), value:"cq:Page"})
if(slingTemplateContent){
_.each(slingTemplateContent, (templateItem)=>{
allNewNodes.push({name:_path.join(curTargetPath, templateItem.name), value:templateItem.value});
......@@ -259,7 +261,6 @@ module.exports = function restubFromBlQuery(params, cb){
}else{
allNewNodes.push({name:_path.join(curTargetPath, "jcr:content", "jcr:primaryType"), value:"cq:PageContent"})
}
allNewNodes.push({name:_path.join(curTargetPath, "jcr:primaryType"), value:"cq:Page"})
allNewNodes.push({name:_path.join(curTargetPath, "jcr:content", "jcr:title"), value: global.bl.prettyName(curTargetPath.split("/").slice(-1)[0])})
allNewNodes.push({name:_path.join(curTargetPath, "jcr:content", "bl:autoStubbed"), value: sourcePath})
}else{
......@@ -286,30 +287,32 @@ module.exports = function restubFromBlQuery(params, cb){
//********** Delete superfluous nodes ********************************************//
_.each(existingTargetChildren, (existingChild, childSubPath)=>{
if(pageMode ? _.get(existingChild, "jcr:content.bl:autoStubbed") : existingChild["bl:autoStubbed"]){
let currentIsValid=false;
if(!allowLocalChildren){
_.each(existingTargetChildren, (existingChild, childSubPath)=>{
if(pageMode ? _.get(existingChild, "jcr:content.bl:autoStubbed") : existingChild["bl:autoStubbed"]){
let currentIsValid=false;
// TODO: for multi-segment target paths, make sure not to delete parent folders that have children which shouldn't be deleted
if(!templatedValidSources.includes(childSubPath)){
allNewNodes.push({name:childSubPath + "@Delete", value: "true"})
// TODO: for multi-segment target paths, make sure not to delete parent folders that have children which shouldn't be deleted
if(!templatedValidSources.includes(childSubPath)){
allNewNodes.push({name:childSubPath + "@Delete", value: "true"})
if(pageMode){
deactivations.push(_path.join(targetPath, childSubPath));
if(pageMode){
deactivations.push(_path.join(targetPath, childSubPath));
}
log.debug("DELETE THIS:", childSubPath, existingChild, allNewNodes);
}
log.debug("DELETE THIS:", childSubPath, existingChild, allNewNodes);
}
}
// do you need to allow more free-form mappings? and if free-form, how do you reverse-map? build a regex to rewrite the pattern as a regex. /\{(\:?[\w]+)\}/g => ([^\/]+)
// do you need to allow more free-form mappings? and if free-form, how do you reverse-map? build a regex to rewrite the pattern as a regex. /\{(\:?[\w]+)\}/g => ([^\/]+)
// what you need is to find the existing entries that were previously auto-stubbed, but no longer belong and must be deleted. That's where you apply this:
// 1. must match regex derived from "targetNode" pattern. 2. must be auto-stubbed 3. must match expected resource type? and 4. no longer exists in source list (i.e. in "validSourcePages").
// what you need is to find the existing entries that were previously auto-stubbed, but no longer belong and must be deleted. That's where you apply this:
// 1. must match regex derived from "targetNode" pattern. 2. must be auto-stubbed 3. must match expected resource type? and 4. no longer exists in source list (i.e. in "validSourcePages").
// TODO: auto-delete the parent folder, if it is auto-stubbed and has no children anymore.
// TODO: auto-delete the parent folder, if it is auto-stubbed and has no children anymore.
});
});
}
// TODO: Any other possible operations besides add and delete? ... what about "reorder"? and possibly "rename"?
......
......@@ -36,10 +36,13 @@
{{/each}}
}
var blMaps = {{as-json blMaps}}
var $form=$("#{{dialogConfig.modalId}}").find("form")
$form.data("widgets", widgets);
$form.data("dialog-config", dialogConfig)
$form.data("dialog-config", dialogConfig);
$form.data("blMaps", blMaps);
})()
</script>
......
......@@ -23,6 +23,8 @@ module.exports.process=function(data,$,cb){
var saveTarget=req.query.slingPath;
var modalId = req.query.modalId || "bl-edit-dialog";
var missingNodes = [], localFields; // missingNodes: someday, maybe for data-mapped or template-inherited content, use this to fill in missing parents
let blRefs = {};
let blMaps = {};
var requestedComponent=$.componentRegistry.get(rtype);
if(!requestedComponent){throw new Error("No component found of type '" + rtype + "'");}
......@@ -52,12 +54,16 @@ module.exports.process=function(data,$,cb){
$.sc.getSling(slingUri, {leaveMangledNames: true},function(err, slingData){
var msg;
var pageMatch=slingUri.match(/(.*)\/jcr:content\/?([^\.]+)?(.*)/);
if(err && !pageMatch){
msg="ERROR loading sling for dialog: " + slingUri;
$.log.error(msg, {error:err, stack:err.stack}); $.handleError(new Error(msg), res, req);
return;
if(err){
if(!pageMatch){
msg="ERROR loading sling for dialog: " + slingUri;
$.log.error(msg, {error:err, stack:err.stack}); $.handleError(new Error(msg), res, req);
return;
}
slingData = {"sling:resourceType":rtype};
}
if(inheritFrom){
......@@ -125,6 +131,9 @@ module.exports.process=function(data,$,cb){
}
if(slingData){
let templatedFields = [];
//this is to account for fields that might write objects
//rather than just a single value
_.each(localFields, function(key){
......@@ -132,13 +141,33 @@ module.exports.process=function(data,$,cb){
var keySegments = key.split('/');
keySegments.pop();
var deepKey = keySegments.join('/');
if(!_.includes(localFields, deepKey)){
if(deepKey && !_.includes(localFields, deepKey)){
localFields.push(deepKey);
}
}
if(_.includes(key,'bl:map')){
let relativeSlingPath = key.split('bl:map')[0];
relativeSlingPath += 'bl:map';
if(!blMaps[relativeSlingPath]){
blMaps[relativeSlingPath] = _.get(slingData, relativeSlingPath.split('/'));
}
}
if(key.indexOf('/bl:templated/') > -1){
let splitParts = key.split('/bl:map/bl:templated/');
let relativeSlingPath = splitParts.join('/');
let templateValueParts = splitParts[0].split('/').concat(['bl:map', 'bl:templated', splitParts[1]]);
let templateValue = _.get(slingData, templateValueParts);
_.set(slingData, relativeSlingPath.split('/'), templateValue);
templatedFields.push(relativeSlingPath);
}
});
slingData["bl:local"]=localFields;
slingData["bl:local"]=localFields;
slingData["bl:lock-mode"]=true;
slingData["bl:templated"]=templatedFields;
}
renderDialog(slingData);
......@@ -202,7 +231,6 @@ module.exports.process=function(data,$,cb){
_.each(requestedComponent.allWidgets, function(config){
if(usedKeys.includes(config.key)){throw new Error("Dialog contains a widget with an already-used key or name in object: " + JSON.stringify(config))}
usedKeys.push(config.key);
if(!hasField && !holderWidgetTypes.includes(config.widget)){
hasField=true;
}
......@@ -227,8 +255,6 @@ module.exports.process=function(data,$,cb){
dialogBody = fieldTemplate.compiled(slingData);
}
var dialogConfig={
slingType: rtype,
saveTarget: saveTarget,
......@@ -240,17 +266,16 @@ module.exports.process=function(data,$,cb){
addParentType: addParentType,
mergeMarker:req.query.mergeMarker,
title: req.query.title || _.get(requestedComponent,"title", "Not editable"),
modalId: modalId
modalId: modalId,
hasDataMap : _.size(blMaps) > 0
}
var mapping=blMapRender(slingData, slingPath);
var mapping=blMapRender(blMaps, slingData['sling:resourceType']);
var annotations = annotationsRender(slingData, slingPath);
dialogConfig.hasDataMap = slingData["bl:map"]?true:false;
var dialogContent = $.template({body:dialogBody, mapping, annotations, lock:inheritFrom?true:false, widgetConfigs:configs, dialogConfig: dialogConfig, title: dialogConfig.title });
var dialogContent = $.template({body:dialogBody, mapping, annotations, lock:inheritFrom?true:false, widgetConfigs:configs, dialogConfig: dialogConfig, title: dialogConfig.title, blMaps: blMaps});
res.send(dialogContent);
res.end();
}catch(err){
......
......@@ -8,39 +8,47 @@ var flatten=global.bl.flattenObject;
module.exports.process=function(data,$,cb){
"use strict";
var {req, res} = $.express;
var keys = _.keys(req.body);
var postFields=[{name:"bl:ref@Delete", value:true}];
_.each(keys, function(key){
var match=key.match(/^([^\_]*)\_type$/);
if(match){
let key=match[1];
let prefix="bl:map/" + key;
let type=req.body[key + "_type"];
let typeValue=req.body[key + "_type_value"];
let jsonKey = key + "_json5";
let jsonValue;
if(_.includes(keys, jsonKey)){
try{
jsonValue = json5.parse(req.body[jsonKey]);
}catch(err){
var mapEntries = req.body.maps;
console.log('mapEntries', mapEntries);
var postFields=[];
_.each(mapEntries, (mapEntry)=>{
var keys = _.keys(mapEntry.fields);
postFields.push({name:mapEntry.name + "@Delete", value:true});
console.log('keys', keys);
_.each(keys, function(key){
var match=key.match(/^([^\_]*)\_type$/);
if(match){
let key=match[1];
let prefix=mapEntry.name+"/" + key;
let type=mapEntry.fields[key + "_type"];
let typeValue=mapEntry.fields[key + "_type_value"];
let jsonKey = key + "_json5";
let jsonValue;
if(_.includes(keys, jsonKey)){
try{
jsonValue = json5.parse(mapEntry.fields[jsonKey]);
}catch(err){
}
}else if(mapEntry.fields[key + "_delete"]){
postFields.push({name:prefix + "@Delete", value: true})
}else{
jsonValue= {error:"Some custom non-JSON submission"};
}
}else if(req.body[key + "_delete"]){
postFields.push({name:prefix + "@Delete", value: true})
}else{
jsonValue= {error:"Some custom non-JSON submission"};
}
if(jsonValue){
if(typeValue){jsonValue[type] = typeValue;}
postFields.push({name:prefix + "/" + type, value: typeValue});
let vals=flatten(jsonValue, prefix, true);
vals = _.filter(vals, (val)=>!/^bl:map\/[^\/]*\/error$/.test(val.name)); // Filter out any auto-inserted bl-lookup error messages; don't write those to disk.
Array.prototype.push.apply(postFields, vals);
if(jsonValue){
if(typeValue){jsonValue[type] = typeValue;}
//postFields.push({name:prefix + "/" + type, value: typeValue});
let vals=flatten(jsonValue, {prefix, slingArrays: true});
vals = _.filter(vals, (val)=>!/^bl:map\/[^\/]*\/error$/.test(val.name)); // Filter out any auto-inserted bl-lookup error messages; don't write those to disk.
Array.prototype.push.apply(postFields, vals);
}
}
}
})
})
res.json({status:"success", postFields });
......
var _=require("lodash");
var blDialogRender=require("../../../widgets/mapping-widget/mapping-widget").renderDialogPage;
module.exports.process=function(data,$,cb){
var mappingWidget = global.bl.widgetRegistry.get("mapping-widget");
var {req, res} = $.express;
console.log('mapping-update body', req.body);
if(!req.body || !req.body.maps || !req.body.type){
cb("mapping-update expects posted parameters: maps and type")
}else{
res.send(blDialogRender(req.body.maps, req.body.type));
res.end();
cb(null, false);
}
}
const _=require("lodash");
module.exports.process = function(data, $, cb){
const res = $.express.res;
const req = $.express.req;
const sc = req.bl.sling;
const slingPath=req.query.slingPath;
let pageResults = [];
const sendResults = ()=>{
res.json(pageResults);
cb(null, false);
};
if(slingPath && _.includes(slingPath, 'jcr:content')){
sc.getSling(slingPath + '.infinity.json', (err, slingData)=>{
let rType = _.get(slingData, '_sling_resourceType');
if(!err && rType){
if(rType === 'foundation/components/parsys'){
//just list out every result
let index = 0;
_.each(slingData, (entry, nodeName)=>{
const compResType = entry['_sling_resourceType'];
if(_.isPlainObject(entry) && compResType){
//need the title of the component
var comp=$.componentRegistry.get(compResType);
if(comp){
pageResults.push({path: slingPath + "/" + nodeName, title: (comp.title || comp.type) + ' (' + index + ')', indexable: slingPath + "/-" + index});
index++;
}
}
});
}else{
//get that component type
var comp=$.componentRegistry.get(rType)
//get all of the includes
//get the include types and recurse down
_.each(_.get(comp, 'container.includes'), function(include){
if(include.name && _.get(slingData, include.name.split('/'))){
pageResults.push({path: slingPath + "/" + include.name, title: include.title || _.get($.componentRegistry.get(include.type), 'title') || include.name});
}
});
}
}
sendResults();
});
}else{
sendResults();
}
}
\ No newline at end of file
{{#if slingData}}
{{#component-config slingData}}
{{#if @component.hasDialog}}
{{dialog-content-mode @component.type .}}
{{else}}
<p> No fields defined.</p>
{{/if}}
{{/component-config}}
{{else}}
<p> No data found.</p>
{{/if}}
\ No newline at end of file
const _ = require('lodash');
module.exports.process=function(data, $, cb){
data.referenceMode=true;
const req=$.express.req;
const res=$.express.res;
const sc = req.bl.sling;
const slingPath=req.query.slingPath;
if(slingPath){
let url = slingPath;
let forceMetaType = false;
if(!_.includes(slingPath, 'jcr:content')){
url += '/jcr:content';
forceMetaType = true;
}
sc.getSling(url + '.infinity.json',{leaveMangledNames:true}, (err, slingData)=>{
if(slingData && forceMetaType){
var metaType = "blacklight/edit/page/resource-type";
var rtype = slingData['sling:resourceType'];
if(rtype){
var pageComponent=$.componentRegistry.get(rtype);
if(pageComponent){
var rTypeParts = rtype.split('/');
//is there a meta dialog defined for:
var discoveredMetaType =
//this page?
_.get(pageComponent, 'container.metaType') ||
//this module?
_.get(global.bl.modules.modelHelpers, _.join([rTypeParts[0], rTypeParts[1], 'pageMetaType'],'.')) ||
//this site?
_.get(global, 'bl.sites.' +rTypeParts[0] + '.helpers.pageMetaType') ||
//default
metaType;
}
}
slingData['sling:resourceType'] = _.isFunction(metaType) ? metaType($) : metaType;
}
if(slingData['sling:resourceType']){
data.slingData = slingData;
}
cb(false)
});
}else{
cb(false);
}
}
\ No newline at end of file
......@@ -66,13 +66,27 @@ document.addEventListener('DOMContentLoaded', function() {
//////////////////////////////////////////////////////////////////////////////////////////////////////////
function replaceSelector(url, desiredSelector){
var parts=url.split("/");
var name = parts.pop(); if(!name){name=parts.pop();}
var bits = name.split(".");
var base = bits.shift();
var extension = bits.pop();
parts.push(base + "." + desiredSelector + (desiredSelector?".":"") + extension);
return parts.join("/");
var mainParts = url.split(/(?=[?#])/g);
var baseUrl = mainParts[0];
var parts= baseUrl.split("/");
var name = parts.pop();
if(!name){
name=parts.pop();
}
var bits = name.split(".");
var base = bits.shift();
var extension = bits.pop() || "html";
parts.push(base + "." + desiredSelector + (desiredSelector?".":"") + extension);
var fullPath = parts.join("/");
//add back the hash and query if they exist.
var addOns = mainParts.slice(1);
if(addOns) {
fullPath = fullPath + addOns.join("");
}
return fullPath;
}
window.BL.replaceSelector = replaceSelector;
......@@ -316,7 +330,3 @@ document.addEventListener('DOMContentLoaded', function() {
window.BL.loadLibrary();
}, false);
\ No newline at end of file
var _=require("lodash");
var isImportantUpdate = /(.*)\/jcr:content\/(sling:resourceType|jcr:title)$/;
var removeBlQuery = /(.*)\/bl:query/;
var log=global.bl.logger.get("bl-edit.query-mapping");
var config = global.bl.config.environment;
......@@ -61,10 +60,14 @@ exports.process=function(model, $, cb){
_.each(message.updates, (update)=>{
var match=update.path.match(isImportantUpdate);
if(match){
if(!updatedCollectionItems.includes(match[1])){
updatedCollectionItems.push(match[1]);
let collectionPath = update.path.split('/jcr:content')[0];
if(!updatedCollectionItems.includes(collectionPath)){
updatedCollectionItems.push(collectionPath);
}
if (update.path.includes('sling:resourceType')) {
const componentPath = update.path.split('/sling:resourceType')[0];
if(!updatedCollectionItems.includes(componentPath)){
updatedCollectionItems.push(componentPath);
}
}
......@@ -106,7 +109,7 @@ exports.process=function(model, $, cb){
if(col){
var curPath = col.pathTemplate;
var queries=[curPath];
var paramKeys=_.keys(col.params); paramKeys.pop();
var paramKeys=_.keys(col.params);
_.each(paramKeys, (param)=>{
// console.log("REPLACE:", `/-${param}/`);
......@@ -161,7 +164,7 @@ exports.process=function(model, $, cb){
if(tasks.tasks.length){
queue.makeJob(tasks,(err,job)=>{
if(err){log.error("Couldn't add job to 'mapped-stubs' queue", err);}
else{
else{
console.log("Success adding job to 'mapped-stubs' queue:", job.id);
}
});
......
......@@ -7,7 +7,7 @@
<table class="highlight bordered"><tbody>
{{#each config.items}}
<tr><td>{{fieldLabel}}</td><td>{{get-template . "content"}}</td></tr>
<tr class="{{widget}}" data-name="{{name}}"><td>{{fieldLabel}}</td><td>{{get-template . "content"}}</td></tr>
{{/each}}
</tbody>
</table>
......
......@@ -144,10 +144,20 @@ module.exports=function($, window, page, $dialog){
/*************************************************************************************/
mappingPage.validate = function(callback){
var mapValidateUrl = page.appsMount + "blacklight/edit/dialogs/edit/mapping-process"
var mapValidateUrl = page.appsMount + "blacklight/edit/dialogs/edit/mapping-process";
var values = [];
var mapEntries = $mappingBody.find('.map-entry');
mapEntries.each(function(){
var data = {name: $(this).data('name'), fields: {}};
var formFields = $(this).find("input, textarea, select").serializeArray();
_.each(formFields, function(field){
data.fields[field.name] = field.value;
})
values.push(data);
});
var values = $mappingBody.find("input, textarea, select").serializeArray();
$.ajax({url: mapValidateUrl, data: values, method:"POST"})
$.ajax({url: mapValidateUrl, data: {maps: values}, method:"POST"})
.done(function(data){
let error="";
if(!data || !data.postFields){
......@@ -156,6 +166,14 @@ module.exports=function($, window, page, $dialog){
mappingPage.postFields = data.postFields;
callback(error);
});
}
/*************************************************************************************/
mappingPage.updateView = function(newHtml){
$mappingBody.html(newHtml);
activate();
dirty();
}
return mappingPage;
......
......@@ -14,105 +14,129 @@ var uniqueIdCounter = 0;
const mappingTypes=shared.mappingTypes;
/********************************************************************************************/
module.exports.renderDialogPage = function(slingData, slingPath){
module.exports.renderDialogPage = function(blMaps, resourceType){
"use strict";
var allMapsWidgets = [];
var result={directives:[]}
var mappingWidgets=[];
var mappingWidget = global.bl.widgetRegistry.get("mapping-widget");
var mappingWidgetTemplate = mappingWidget.getCompiledTemplate("field")
var itemCount=0;
var resourceType = _.get(slingData,"sling:resourceType");
var component = resourceType?global.bl.componentRegistry.get(resourceType):null;
var namedMaps = _.get(component,"named_maps");
var mapMenuId = "mapping_menu_" + uniqueIdCounter++;
var mapMenu=[];
var map=slingData["bl:map"];
_.each(map, (mapItem, key)=>{
if(key==="ci"){
result.componentMap=mapItem;
}else if(_.isPlainObject(mapItem)){
let type, typeVal, params={};
_.each(mapItem,(val,key)=>{
if(typeKeys.test(key)){
type=key;
typeVal = val;
}else{
if(!metaRegex.test(key)){
params[key] = val;
}
}
});
let item = {type, typeVal, params, key};
result.directives.push(item);
}
});
if(result.componentMap){
delete result.componentMap["bl:inherit-component"];
var componentInheritTemplate = mappingWidget.getCompiledTemplate("bl-inherit-component");
mappingWidgets.push(componentInheritTemplate({resourceType, "json5": JSON5.stringify(result.componentMap)}));
//add in a top level bl:map, if one not already present
if(!blMaps['bl:map']){
blMaps['bl:map'] = {
ci: {
'bl:inherit-component' : resourceType
}
}
}
_.each(result.directives, (directive)=>{
// console.log("----\ndirective:", id,"\n", directive.typeVal, "\n", JSON.stringify(directive.params, null, " "))
function dropMeta(obj){
if(!obj){return;}
var keys=Object.keys(obj);
// console.log("keys:", keys);
for(var i=0; i<keys.length; i++){
if(keys[i].indexOf(":")>-1){
delete obj[keys[i]];
}
if(_.isPlainObject(obj[keys[i]])){
dropMeta(obj[keys[i]]);
}
_.each(blMaps, (map, mapPath)=>{
var result={directives:[]}
var mappingWidgets=[];
var mappingWidget = global.bl.widgetRegistry.get("mapping-widget");
var mappingWidgetTemplate = mappingWidget.getCompiledTemplate("field")
var itemCount=0;
var mapMenuId = "mapping_menu_" + uniqueIdCounter++;
var mapMenu=[];
console.log('map', map);
_.each(map, (mapItem, key)=>{
if(key==="ci"){
result.componentMap=mapItem;
}else if(_.isPlainObject(mapItem) && key !== 'bl:templated'){
let type, typeVal, params={};
_.each(mapItem,(val,key)=>{
if(typeKeys.test(key)){
type=key;
typeVal = val;
}else{
if(!metaRegex.test(key)){
params[key] = val;
}
}
});
let item = {type, typeVal, params, key};
result.directives.push(item);
}
}
dropMeta(directive.params);
var template = customTypes.test(directive.type) ? "mapping-widget." + directive.type.replace(/:/,"-") : "";