Created
August 28, 2015 23:09
-
-
Save SchizoDuckie/61129fbbe6b43d3bb69f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{ | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "name", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Search Engine Name", | |
"type": "text" | |
}, | |
"className": "col-xs-9", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.name }} </p></div>" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "mirror", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Base URL for site (exclude the final /)", | |
"type": "text" | |
}, | |
"className": "col-xs-9", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.mirror }} </p></div>" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "searchEndpoint", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Search page url (use %s to inject search query)", | |
"type": "text" | |
}, | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "testSearch", | |
"className": "cseProperty col-xs-3", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Test SearchQuery", | |
"type": "text" | |
} | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.searchEndpoint }} </p><p>{{ model.infoMessages.testSearch}}</p></div>" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "searchResultsContainer", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Results selector (CSS selector that returns a base element for each individual search result)", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.searchResultsContainer", | |
"className": "col-xs-9", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.searchResultsContainer }} </p><p>{{ model.infoMessages.testSearch}}</p></div>" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "loginRequired", | |
"className": "col-xs-5 inline-checkbox", | |
"type": "input", | |
"templateOptions": { | |
"label": "Login Required?", | |
"type": "checkbox" | |
} | |
}, { | |
"key": "magnetSupported", | |
"className": "col-xs-5 inline-checkbox", | |
"type": "input", | |
"templateOptions": { | |
"label": "Magnet URI supported?", | |
"type": "checkbox" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "releaseNameSelector", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Release name Selector (within base element)", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "releaseNameProperty", | |
"className": "cseProperty col-xs-3", | |
"type": "select", | |
"templateOptions": { | |
"required": true, | |
"label": "Attribute", | |
"valueProp": "name", | |
"options": "$mappings.options.attributeWhitelist" | |
} | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.releaseNameSelector }} </p><p>{{ model.infoMessages.releaseNameProperty}}</p></div>" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "loginPage", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"label": "URL of the login page (for when not logged in)", | |
"placeholder": "/login.php", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.loginPage", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "loginTestSelector", | |
"className": "cseProperty col-xs-3", | |
"type": "input", | |
"templateOptions": { | |
"requiredExpression": "model.loginRequired", | |
"label": "Selector that tests if we're not loggedin when executing a search", | |
"placeholder": "#loginform", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.loginTestSelector" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.loginPage }} </p><p>{{ model.infoMessages.loginTestSelector}}</p></div>" | |
}], | |
"hideExpression": "!model.loginRequired" | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "magnetUrlSelector", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"label": "magnet URL selector (hyperlink to the magnet url)", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "magnetUrlProperty", | |
"className": "cseProperty col-xs-3", | |
"type": "select", | |
"templateOptions": { | |
"label": "Attribute", | |
"valueProp": "name", | |
"options": "$mappings.options.attributeWhitelist" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.magnetUrlSelector }} </p><p>{{ model.infoMessages.magnetUrlProperty}}</p></div>" | |
}], | |
"hideExpression": "!model.magnetSupported" | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "torrentUrlSelector", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"label": ".torrent URL selector (hyperlink to the torrent file)", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "torrentUrlProperty", | |
"className": "cseProperty col-xs-3", | |
"type": "select", | |
"templateOptions": { | |
"label": "Attribute", | |
"valueProp": "name", | |
"options": "$mappings.options.attributeWhitelist" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.torrentUrlSelector }} </p><p>{{ model.infoMessages.torrentUrlProperty}}</p></div>" | |
}], | |
"hideExpression": "!model.magnetSupported" | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "sizeSelector", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Size Selector (element that has the Torrent's size)", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "sizeProperty", | |
"className": "cseProperty col-xs-3", | |
"type": "select", | |
"templateOptions": { | |
"required": true, | |
"label": "Attribute", | |
"valueProp": "name", | |
"options": "$mappings.options.attributeWhitelist" | |
}, | |
"asyncValidators": "$mappings.validators.attributeSelector" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.sizeSelector }} </p><p>{{ model.infoMessages.sizeProperty}}</p></div>" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "seederSelector", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Seeders Selector (element that has the 'seeders')", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "seederProperty", | |
"className": "cseProperty col-xs-3", | |
"type": "select", | |
"templateOptions": { | |
"required": true, | |
"label": "Attribute", | |
"valueProp": "name", | |
"options": "$mappings.options.attributeWhitelist" | |
}, | |
"asyncValidators": "$mappings.validators.attributeSelector" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.seederSelector }} </p><p>{{ model.infoMessages.seederProperty}}</p></div>" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "leecherSelector", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Leechers Selector (element that has the 'leechers')", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "leecherProperty", | |
"className": "cseProperty col-xs-3", | |
"type": "select", | |
"templateOptions": { | |
"required": true, | |
"label": "Attribute", | |
"valueProp": "name", | |
"options": "$mappings.options.attributeWhitelist" | |
}, | |
"asyncValidators": "$mappings.validators.attributeSelector" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.leecherSelector }} </p><p>{{ model.infoMessages.leecherProperty}}</p></div>" | |
}] | |
}, { | |
"className": "row", | |
"fieldGroup": [{ | |
"key": "detailUrlSelector", | |
"className": "cseSelector col-xs-6", | |
"type": "input", | |
"templateOptions": { | |
"required": true, | |
"label": "Detail URL Selector (page that opens in new tab and shows detail page for torrent)", | |
"type": "text" | |
}, | |
"asyncValidators": "$mappings.validators.propertySelector", | |
"modelOptions": "$mappings.modelOptions.keyup" | |
}, { | |
"key": "detailUrlProperty", | |
"className": "cseProperty col-xs-3", | |
"type": "select", | |
"templateOptions": { | |
"required": true, | |
"label": "Attribute", | |
"valueProp": "name", | |
"options": "$mappings.options.attributeWhitelist" | |
}, | |
"asyncValidators": "$mappings.validators.attributeSelector" | |
}, { | |
"className": "col-xs-3", | |
"template": "<div class='searchengineinfo'><i class='glyphicon glyphicon-ok'></i> {{ model.infoMessages.detailUrlSelector }} </p><p>{{ model.infoMessages.detailUrlProperty}}</p></div>" | |
}] | |
}] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ... | |
DuckieTV.controller('customSearchEngineDialogCtrl', ["$q", "$http", "FormlyLoader", | |
function($q, $http, FormlyLoader) { | |
var self = this; | |
FormlyLoader.setMapping('validators', { | |
searchResultsContainer: { | |
expression: function($viewValue, $modelValue, scope) { | |
return getCachedScraper().then(function(d) { | |
try { | |
var results = d.querySelectorAll($viewValue); | |
console.log("Results: ", results); | |
if (!results || results.length === 0) { | |
self.model.infoMessages[scope.options.key] = 'No results found.'; | |
throw new Error("no results found"); | |
} else { | |
firstResult = results[0]; | |
self.model.infoMessages[scope.options.key] = results.length + ' results found.'; | |
revalidateRowSelectors(); | |
return true; | |
} | |
} catch (E) { | |
self.model.infoMessages[scope.options.key] = E.message; | |
throw E; | |
} | |
}); | |
} | |
}, | |
propertySelector: { | |
expression: function($viewValue, $modelValue, scope) { | |
console.warn(scope.options.key + " validate!"); | |
return $q(function(resolve, reject) { | |
if (firstResult) { | |
try { | |
var property = self.model[scope.options.key.replace('Selector', 'Property')]; | |
console.warn("Property for " + scope.options.key + ": " + property, $viewValue, firstResult.querySelector($viewValue), firstResult.querySelector($viewValue)[self.model[property]], firstResult.querySelector($viewValue).getAttribute(property)); | |
var el = firstResult.querySelector($viewValue); | |
self.model.infoMessages[scope.options.key] = (property == 'href' || property == 'src') ? el.getAttribute(property) : el[property]; | |
} catch (E) { | |
self.model.infoMessages[scope.options.key] = E.message; | |
} | |
resolve(); | |
} else { | |
throw "no results."; | |
} | |
}); | |
} | |
}, | |
attributeSelector: { | |
expression: function($viewValue, $modelValue, scope) { | |
return $q(function(resolve) { | |
resolve(); | |
setTimeout(function() { | |
revalidateRowSelectors(); | |
}); | |
}); | |
} | |
}, | |
loginPage: { | |
expression: function($viewValue, $modelValue, scope) { | |
return $http.get(self.model.mirror + $viewValue).then(function(result) { | |
self.model.infoMessages[scope.options.key] = 'Login page found'; | |
}, function(err) { | |
throw "Page not found " + err.message; | |
}); | |
} | |
}, | |
loginTestSelector: { | |
expression: function($viewValue, $modelValue, scope) { | |
return getCachedScraper().then(function(d) { | |
try { | |
var results = d.querySelectorAll($viewValue); | |
console.log("Results: ", results); | |
if (!results || results.length === 0) { | |
self.model.infoMessages[scope.options.key] = 'No results found, but assuming loggedin'; | |
} else { | |
self.model.infoMessages[scope.options.key] = 'Not loggedin test OK'; | |
} | |
} catch (E) { | |
self.model.infoMessages[scope.options.key] = E.message; | |
throw E; | |
} | |
}); | |
} | |
} | |
}); | |
FormlyLoader.setMapping('options', { | |
attributeWhitelist: [{ | |
name: 'href', | |
}, { | |
name: 'innerText', | |
}, { | |
name: 'title', | |
}, { | |
name: 'src', | |
}, { | |
name: 'alt', | |
}] | |
}); | |
FormlyLoader.setMapping('modelOptions', { | |
keyup: { | |
"updateOn": "keyup", | |
"debounce": 200 | |
} | |
}); | |
FormlyLoader.load('CustomSearchEngine').then(function(fields) { | |
self.fields = fields; | |
console.log("Loaded!", fields); | |
}); | |
//. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Formly loader and config mapper. | |
* use setMapping and $parse strings to map individual properties to functions and arrays to remove duplicaton. | |
* | |
* | |
* Example in customSearchEngineCtrl.js | |
* | |
*/ | |
DuckieTV.factory('FormlyLoader', function($http, $parse) { | |
var config = { | |
basePath: 'templates/formly-forms/', | |
mappings: {} | |
}; | |
function recursivePropertyMap(field) { | |
if (field.fieldGroup) { | |
field.fieldGroup = field.fieldGroup.map(recursivePropertyMap); | |
return field; | |
} | |
return processMappings(field); | |
} | |
function processMappings(field) { | |
Object.keys(field).map(function(key) { | |
if (angular.isObject(field[key])) { | |
field[key] = processMappings(field[key]); | |
} else if (field[key].toString().indexOf('$mappings') === 0) { | |
var getter = $parse(field[key].split('$mappings.')[1]); | |
field[key] = getter(config.mappings); | |
} | |
}); | |
return field; | |
} | |
var service = { | |
setBasePath: function(path) { | |
config.basePath = path; | |
}, | |
setMapping: function(key, option) { | |
config.mappings[key] = option; | |
}, | |
load: function(form) { | |
return $http.get(config.basePath + form + '.json').then(function(result) { | |
return result.data.map(recursivePropertyMap); | |
}); | |
} | |
}; | |
return service; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment