Skip to content

Commit

Permalink
Merge pull request #55 from togostanza/fix-multiple-stanzas
Browse files Browse the repository at this point in the history
Fix an error when there are multiple stanzas on the same page
  • Loading branch information
darashi authored Jan 25, 2019
2 parents 8934714 + c1226f1 commit 9026ccd
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 161 deletions.
308 changes: 155 additions & 153 deletions provider/assets-src/js/stanza.js
Original file line number Diff line number Diff line change
@@ -1,189 +1,191 @@
import Handlebars from 'handlebars/dist/handlebars';

export default function Stanza(execute) {
const development = descriptor.development;

function template(name) {
const t = descriptor.templates[name];
if (!t) {
throw new Error(`template "${name}" is not found`);
export default function initialize(descriptor) {
return function Stanza(execute) {
const development = descriptor.development;

function template(name) {
const t = descriptor.templates[name];
if (!t) {
throw new Error(`template "${name}" is not found`);
}
return t;
}
return t;
}

function createStanzaHelper(element) {
const handlebars = Handlebars.create();
function createStanzaHelper(element) {
const handlebars = Handlebars.create();

return {
root: element.shadowRoot,
handlebars,

query(params) {
if (development) {
console.log("query: called", params);
}
const t = template(params.template);
const queryTemplate = handlebars.compile(t, {noEscape: true});
const query = queryTemplate(params.parameters);
const data = new URLSearchParams();
data.set("query", query);

if (development) {
console.log("query: query built:\n" + query);
console.log("query: sending to", params.endpoint);
}
return {
root: element.shadowRoot,
handlebars,

// NOTE specifying Content-Type explicitly because some browsers sends `application/x-www-form-urlencoded;charset=UTF-8` without this, and some endpoints may not support this form.
return fetch(params.endpoint, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/sparql-results+json"
},
body: data,
}).then((response) => {
query(params) {
if (development) {
console.log("query:", response.statusText, response);
console.log("query: called", params);
}
const t = template(params.template);
const queryTemplate = handlebars.compile(t, {noEscape: true});
const query = queryTemplate(params.parameters);
const data = new URLSearchParams();
data.set("query", query);

return response.json();
});
},

render(params) {
if (development) {
console.log("render: called", params)
}

const t = template(params.template);
const htmlTemplate = handlebars.compile(t);
const htmlFragment = htmlTemplate(params.parameters);

if (development) {
console.log("render: built:\n", htmlFragment)
}

const selector = params.selector || "main";
element.shadowRoot.querySelector(selector).innerHTML = htmlFragment;

if (development) {
console.log("render: wrote to \"" + selector + "\"")
}
},

select(selector) {
return this.root.querySelector(selector);
},

selectAll(selector) {
return this.root.querySelectorAll(selector);
},

grouping(rows, ...keys) {
const normalizedKeys = keys.reduce((acc, key) => {
if (key instanceof Array) {
return acc.concat({key: key, alias: key.join('_')});
} else if (key instanceof Object) {
return acc.concat(key);
} else {
return acc.concat({key: key, alias: key});
if (development) {
console.log("query: query built:\n" + query);
console.log("query: sending to", params.endpoint);
}
}, []);

return (function _grouping(rows, keys) {
const [currentKey, ...remainKeys] = keys;
// NOTE specifying Content-Type explicitly because some browsers sends `application/x-www-form-urlencoded;charset=UTF-8` without this, and some endpoints may not support this form.
return fetch(params.endpoint, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "application/sparql-results+json"
},
body: data,
}).then((response) => {
if (development) {
console.log("query:", response.statusText, response);
}

return response.json();
});
},

function fetch(row, key) {
return key instanceof Array ? key.map((k) => row[k]) : row[currentKey.key];
render(params) {
if (development) {
console.log("render: called", params)
}

if (keys.length === 1) {
return rows.map((row) => fetch(row, currentKey.key));
const t = template(params.template);
const htmlTemplate = handlebars.compile(t);
const htmlFragment = htmlTemplate(params.parameters);

if (development) {
console.log("render: built:\n", htmlFragment)
}

return this.groupBy(rows, (row) => {
return fetch(row, currentKey.key);
}).map(([currentValue, remainValues]) => {
const nextKey = remainKeys[0];
const selector = params.selector || "main";
element.shadowRoot.querySelector(selector).innerHTML = htmlFragment;

return {
[currentKey.alias]: currentValue,
[nextKey.alias]: _grouping(remainValues, remainKeys)
};
if (development) {
console.log("render: wrote to \"" + selector + "\"")
}
},

select(selector) {
return this.root.querySelector(selector);
},

selectAll(selector) {
return this.root.querySelectorAll(selector);
},

grouping(rows, ...keys) {
const normalizedKeys = keys.reduce((acc, key) => {
if (key instanceof Array) {
return acc.concat({key: key, alias: key.join('_')});
} else if (key instanceof Object) {
return acc.concat(key);
} else {
return acc.concat({key: key, alias: key});
}
}, []);

return (function _grouping(rows, keys) {
const [currentKey, ...remainKeys] = keys;

function fetch(row, key) {
return key instanceof Array ? key.map((k) => row[k]) : row[currentKey.key];
}

if (keys.length === 1) {
return rows.map((row) => fetch(row, currentKey.key));
}

return this.groupBy(rows, (row) => {
return fetch(row, currentKey.key);
}).map(([currentValue, remainValues]) => {
const nextKey = remainKeys[0];

return {
[currentKey.alias]: currentValue,
[nextKey.alias]: _grouping(remainValues, remainKeys)
};
});
})(rows, normalizedKeys);
},

groupBy(array, func) {
const ret = [];

array.forEach((item) => {
const key = func(item);
const entry = ret.filter((e) => e[0] === key)[0];

if (entry) {
entry[1].push(item);
} else {
ret.push([key, [item]]);
}
});
})(rows, normalizedKeys);
},

groupBy(array, func) {
const ret = [];

array.forEach((item) => {
const key = func(item);
const entry = ret.filter((e) => e[0] === key)[0];

if (entry) {
entry[1].push(item);
} else {
ret.push([key, [item]]);
}
});
return ret;
},

return ret;
},
unwrapValueFromBinding(queryResult) {
const bindings = queryResult.results.bindings;

unwrapValueFromBinding(queryResult) {
const bindings = queryResult.results.bindings;
return bindings.map((binding) => {
const ret = {};

return bindings.map((binding) => {
const ret = {};
Object.keys(binding).forEach((key) => {
ret[key] = binding[key].value;
});

Object.keys(binding).forEach((key) => {
ret[key] = binding[key].value;
return ret;
});
}
};
}

return ret;
});
}
};
}

function update(element) {
const params = {};
descriptor.parameters.forEach((key) => {
params[key] = element.getAttribute(key);
});
execute(createStanzaHelper(element), params);
}
function update(element) {
const params = {};
descriptor.parameters.forEach((key) => {
params[key] = element.getAttribute(key);
});
execute(createStanzaHelper(element), params);
}

class StanzaElement extends HTMLElement {
constructor() {
super();
class StanzaElement extends HTMLElement {
constructor() {
super();

const shadow = this.attachShadow({mode: "open"});
const main = document.createElement("main");
shadow.appendChild(main);
const shadow = this.attachShadow({mode: "open"});
const main = document.createElement("main");
shadow.appendChild(main);

update(this);
}
update(this);
}

static get observedAttributes() {
return descriptor.parameters;
}
static get observedAttributes() {
return descriptor.parameters;
}

attributeChangedCallback(attrName, oldVal, newVal) {
let found = false;
descriptor.parameters.forEach(function(key) {
if (attrName == key) {
found = true;
attributeChangedCallback(attrName, oldVal, newVal) {
let found = false;
descriptor.parameters.forEach(function(key) {
if (attrName == key) {
found = true;
}
});
if (found) {
update(this);
}
});
if (found) {
update(this);
}
}
}

if ('customElements' in window && !window.customElements.get(descriptor.elementName)) {
window.customElements.define(descriptor.elementName, StanzaElement);
if ('customElements' in window && !window.customElements.get(descriptor.elementName)) {
window.customElements.define(descriptor.elementName, StanzaElement);
}
}
}
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default {
output: {
file: 'provider/assets/js/stanza.js',
format: 'iife',
name: 'Stanza',
name: 'TogoStanza.initialize',
sourcemap: true
},
plugins: [
Expand Down
18 changes: 11 additions & 7 deletions stanza/data/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@

<script src="../assets/js/stanza.js"></script>
<script>
const descriptor = {{.DescriptorJson}};
(function() {
const descriptor = {{.DescriptorJson}};

if ('Promise' in window && 'URLSearchParams' in window && 'fetch' in window) {
{{.IndexJs}}
} else {
const element = document.querySelector(descriptor.elementName);
if ('Promise' in window && 'URLSearchParams' in window && 'fetch' in window) {
const Stanza = TogoStanza.initialize(descriptor);

element.textContent = 'Your Web browser does not support the features required for the stanza to work.';
}
{{.IndexJs}}
} else {
const element = document.querySelector(descriptor.elementName);

element.textContent = 'Your Web browser does not support the features required for the stanza to work.';
}
})();
</script>

0 comments on commit 9026ccd

Please sign in to comment.