refactor and add the ability to inject custom code

This commit is contained in:
Keegan
2015-10-12 01:49:56 -07:00
parent 8c958f1bae
commit 53e49339b5
12 changed files with 65 additions and 82 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ gulp.task('clean', function(done) {
}); });
gulp.task('browserify', ['clean'], function(done) { gulp.task('browserify', ['clean'], function(done) {
return browserify('src/scripts/config-page.js', { debug: true }) return browserify('src/scripts/config-page.js', { debug: false })
.transform(stringify(['.html', '.mustache'])) .transform(stringify(['.html', '.mustache']))
.bundle() .bundle()
.pipe(source('config-page.js')) .pipe(source('config-page.js'))
+13 -12
View File
@@ -51,20 +51,22 @@ function encodeDataUri(input) {
return 'data:text/html;base64,' + encodeURIComponent(out.join('')); return 'data:text/html;base64,' + encodeURIComponent(out.join(''));
} }
function Clay(config) { /**
* @param {array} config - the Clay config
* @param {function} [customFn] - custom code to run from the config page.
* Will run with api as context
* @constructor
*/
function Clay(config, customFn) {
this.config = config; this.config = config;
/** this.customFn = customFn || function() {};
* @type {{}}
* @private
*/
this._defaults = {};
} }
/** /**
* Generate the Data URI used by the config Page with settings injected * Generate the Data URI used by the config Page with settings injected
* @param {string} clayData - the entire HTML page as a data URI * @param {string} returnTo - used while developing on desktop.
*/ */
Clay.prototype.generateUrl = function() { Clay.prototype.generateUrl = function(returnTo) {
var settings; var settings;
try { try {
settings = JSON.parse(localStorage.getItem('clay-settings')) || {}; settings = JSON.parse(localStorage.getItem('clay-settings')) || {};
@@ -74,6 +76,8 @@ Clay.prototype.generateUrl = function() {
} }
// Show config page // Show config page
return encodeDataUri(configPageHtml return encodeDataUri(configPageHtml
.replace('$$CUSTOM_FN$$', this.customFn.toString().replace(/^.*?\{/, '{'))
.replace('$$RETURN_TO$$', returnTo || 'pebblejs://close#')
.replace('$$CONFIG$$', JSON.stringify(this.config)) .replace('$$CONFIG$$', JSON.stringify(this.config))
.replace('$$SETTINGS$$', JSON.stringify(settings)) .replace('$$SETTINGS$$', JSON.stringify(settings))
); );
@@ -86,10 +90,7 @@ Clay.prototype.getSettings = function(response) {
if (!settings) return {}; if (!settings) return {};
localStorage.setItem('clay-settings', JSON.stringify(settings)); localStorage.setItem('clay-settings', JSON.stringify(settings));
}; return settings;
Clay.prototype.getDefaults = function() {
return this._defaults;
}; };
module.exports = Clay; module.exports = Clay;
+3 -1
View File
@@ -6,13 +6,15 @@
<link rel="stylesheet" href="styles/config-page.css"> <link rel="stylesheet" href="styles/config-page.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script> <script>
window.returnTo = '$$RETURN_TO$$';
window.clayConfig = $$CONFIG$$; window.clayConfig = $$CONFIG$$;
window.claySettings = $$SETTINGS$$; window.claySettings = $$SETTINGS$$;
window.customFn = function() $$CUSTOM_FN$$;
</script> </script>
</head> </head>
<body> <body>
<form id="main-form"></form> <form id="main-form"></form>
<script src="../vendor/pebble-slate/dist/js/slate.min.js"></script> <script src="../vendor/pebble-slate/dist/js/slate.min.js"></script>
<script src="../tmp/config-page.js"></script> <script uglify src="../tmp/config-page.js"></script>
</body> </body>
</html> </html>
+40 -46
View File
@@ -20,40 +20,32 @@ var $ = require('zepto-browserify').$;
var config = $.extend(true, [], window.clayConfig || []); var config = $.extend(true, [], window.clayConfig || []);
var settings = $.extend(true, {}, window.claySettings || {}); var settings = $.extend(true, {}, window.claySettings || {});
var returnTo = window.returnTo || 'pebblejs://close#';
var customFn = window.customFn;
// Get query variables function submit(event) {
function getQueryParam(variable, defaultValue) { $.each(api.itemsByAppKey, function(appKey, item) {
var query = location.search.substring(1); settings[appKey] = item.get();
var vars = query.split('&'); });
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (pair[0] === variable) {
return decodeURIComponent(pair[1]);
}
}
return defaultValue || false;
}
function submit() {
// Set the return URL depending on the runtime environment // Set the return URL depending on the runtime environment
var return_to = getQueryParam('return_to', 'pebblejs://close#'); location.href = returnTo + encodeURIComponent(JSON.stringify(settings));
document.location = return_to + encodeURIComponent(JSON.stringify(settings)); event.preventDefault();
return false;
} }
/** /**
* *
* @param {string} key * @param {string} key
* @param {string|boolean} _default * @param {string|boolean} defaultValue
* @return {string|boolean} * @return {string|boolean}
*/ */
function getSetting(key, _default) { function getSetting(key, defaultValue) {
return typeof settings[key] !== 'undefined' ? settings[key] : (_default || ''); return typeof settings[key] !== 'undefined' ? settings[key] : (defaultValue || '');
} }
function setSetting(key, value) { // function setSetting(key, value) {
settings[key] = value; // settings[key] = value;
} // }
/** /**
* @param {Clay~Item} item * @param {Clay~Item} item
@@ -83,18 +75,20 @@ function processConfigItem(item, $parent) {
attributes: $.map(item.attributes || [], function(item, key) { attributes: $.map(item.attributes || [], function(item, key) {
return { return {
key: key, key: key,
// .replace('"', '&quot;'),
value: item.toString() value: item.toString()
// .replace('"', '&quot;')
}; };
}), })
value: typeof itemType.valueTransformer === 'function' ?
itemType.valueTransformer(getSetting(item.app_key, item.default), item) :
getSetting(item.app_key, item.default)
}); });
apiItem.$element = $(mustache.render(itemType.template, templateData)); apiItem.$element = $(mustache.render(itemType.template, templateData));
apiItem.$manipulatorTarget = apiItem.$element.find('[data-manipulator-target]'); apiItem.$manipulatorTarget = apiItem.$element.find('[data-manipulator-target]');
// this caters for situations where the manipulator target is the root element
if (!apiItem.$manipulatorTarget.length) {
apiItem.$manipulatorTarget = apiItem.$element;
}
// proxy event related methods
apiItem.on = function(events, handler) { apiItem.on = function(events, handler) {
return apiItem.$manipulatorTarget.on(events, $.proxy(handler, apiItem)); return apiItem.$manipulatorTarget.on(events, $.proxy(handler, apiItem));
}; };
@@ -105,28 +99,31 @@ function processConfigItem(item, $parent) {
apiItem.triggerHandler = apiItem.triggerHandler =
apiItem.$manipulatorTarget.triggerHandler.bind(apiItem.$manipulatorTarget); apiItem.$manipulatorTarget.triggerHandler.bind(apiItem.$manipulatorTarget);
// attach the manipulator methods the the apiItem // attach the manipulator methods to the apiItem
$.each(itemType.manipulator, function(methodName, method) { $.each(itemType.manipulator, function(methodName, method) {
apiItem[methodName] = method.bind(apiItem); apiItem[methodName] = method.bind(apiItem);
}); });
// set the value of the item via the manipulator to ensure consistency
apiItem.set(getSetting(item.app_key, item.value));
apiItem.config = item; apiItem.config = item;
if (item.id) { if (item.id) {
_interface.itemsById[item.id] = apiItem; api.itemsById[item.id] = apiItem;
} }
if (item.app_key) { if (item.app_key) {
_interface.itemsByAppKey[item.app_key] = apiItem; api.itemsByAppKey[item.app_key] = apiItem;
} }
_interface.items.push(apiItem); api.items.push(apiItem);
$parent.append(apiItem.$element); $parent.append(apiItem.$element);
} }
} }
var _interface = { var api = {
items: [], items: [],
itemsById: {}, itemsById: {},
itemsByAppKey: {} itemsByAppKey: {}
@@ -134,25 +131,22 @@ var _interface = {
var $mainForm = $('#main-form'); var $mainForm = $('#main-form');
_interface.getItemByAppKey = function(key) { api.getItemByAppKey = function(key) {
return _interface.itemsByAppKey[key]; return api.itemsByAppKey[key];
}; };
_interface.getItemById = function(key) { api.getItemById = function(key) {
return _interface.itemsById[key]; return api.itemsById[key];
}; };
_interface.getItemsByType = function(type) { api.getItemsByType = function(type) {
return _interface.items.filter(function(item) { return api.items.filter(function(item) {
return item.config.type === type; return item.config.type === type;
}); });
}; };
processConfigItem(config, $mainForm, 0); processConfigItem(config, $mainForm, 0);
$mainForm.on('submit', submit);
$mainForm.submit(submit); module.exports = api;
customFn.call(api);
module.exports = _interface;
window._interface = _interface;
console.log(_interface);
+2 -13
View File
@@ -25,22 +25,11 @@ module.exports = {
}, },
select: { select: {
template: require('../../templates/components/select.mustache'), template: require('../../templates/components/select.mustache'),
manipulator: manipulators.val, manipulator: manipulators.val
valueTransformer: function(rawValue, item) {
item.options.forEach(function(option, index) {
if (option.value === rawValue) {
item.options[index].selected = 'selected';
}
});
return rawValue;
}
}, },
toggle: { toggle: {
template: require('../../templates/components/toggle.mustache'), template: require('../../templates/components/toggle.mustache'),
manipulator: manipulators.checked, manipulator: manipulators.checked
valueTransformer: function(rawValue) {
return rawValue ? 'checked' : '';
}
}, },
submit: { submit: {
template: require('../../templates/components/submit.mustache'), template: require('../../templates/components/submit.mustache'),
+1 -1
View File
@@ -1,4 +1,4 @@
<label class="item"> <label class="item">
<span class="label">{{label}}</span> <span class="label">{{label}}</span>
<input data-manipulator-target type="text" class="item-color item-color-normal" value="{{value}}"> <input data-manipulator-target type="text" class="item-color item-color-normal">
</label> </label>
+1 -3
View File
@@ -1,3 +1 @@
<div data-manipulator-target class="item-container-footer"> <div data-manipulator-target class="item-container-footer"></div>
{{&content}}
</div>
+1 -1
View File
@@ -1,3 +1,3 @@
<div class="item-container-header"> <div class="item-container-header">
<h1 data-manipulator-target>{{&content}}</h1> <h1 data-manipulator-target></h1>
</div> </div>
-1
View File
@@ -3,7 +3,6 @@
<div class="item-input-wrapper"> <div class="item-input-wrapper">
<input data-manipulator-target <input data-manipulator-target
class="item-input" class="item-input"
value="{{value}}"
type="text" type="text"
{{#attributes}} {{key}}="{{value}}" {{/attributes}} {{#attributes}} {{key}}="{{value}}" {{/attributes}}
/> />
+1 -1
View File
@@ -2,7 +2,7 @@
<span class="label">{{label}}</span> <span class="label">{{label}}</span>
<select data-manipulator-target class="item-select"> <select data-manipulator-target class="item-select">
{{#options}} {{#options}}
<option value="{{value}}" {{selected}} class="item-select-option">{{&label}}</option> <option value="{{value}}" class="item-select-option">{{&label}}</option>
{{/options}} {{/options}}
</select> </select>
</label> </label>
+1 -1
View File
@@ -1,3 +1,3 @@
<div class="item-container-header"> <div class="item-container-header">
<h2 data-manipulator-target>{{&content}}</h2> <h2 data-manipulator-target></h2>
</div> </div>
+1 -1
View File
@@ -1,4 +1,4 @@
<label class="item"> <label class="item">
<span class="label">{{label}}</span> <span class="label">{{label}}</span>
<input data-manipulator-target type="checkbox" class="item-toggle" {{value}}> <input data-manipulator-target type="checkbox" class="item-toggle">
</label> </label>