Commit 41a76efb authored by Cédric Le Ninivin's avatar Cédric Le Ninivin

Initial Version in FileSystem Mode

parent 34853bdc
* Use Indexeddb to save URL list in service worker
* Improve storage organisation (breaks compatibility)
* Provide Diff Tool for collaboration
nav.navbar-default {
background-color: none;
}
\ No newline at end of file
/*globals window, document, RSVP, rJS, Handlebars,
location, console*/
/*jslint indent: 2, maxlen: 80*/
(function (window, document, RSVP, rJS, Handlebars, location, console) {
"use strict";
var CODE_CONTENT_KEY = "text_content";
function getExtension(url) {
var extension = url.split('.').pop();
if (extension.endsWith('/')) {
return ".html";
}
return "." + extension;
}
function createJio(gadget, jio_config) {
var jio_gadget;
return gadget.getDeclaredGadget("jio_gadget")
.push(function (jio_g) {
jio_gadget = jio_g;
if (jio_config === undefined)
jio_config = {type: "indexeddb", database: "cribjs"};
console.log(jio_config);
return jio_gadget.createJio(jio_config);
});
}
function createDAVJio(gadget, event) {
return createJio(gadget, {
type:"dav",
url: gadget.props.element.querySelector('.form-use-jio-dav .url').value,
basic_login: btoa(gadget.props.element.querySelector(".form-use-jio-dav .credential").value)
});
}
function displayURLList(gadget, event) {
return new RSVP.Queue()
.push(function () {
return gadget.getDeclaredGadget('crib_sw_gadget');
})
.push(function (crib_sw_gadget) {
return crib_sw_gadget.allDocs();
})
.push(function(data) {
var contentsElement = gadget.props.element.querySelector('.crib-url-list-content tbody'),
footer_element = gadget.props.element.querySelector('.crib-url-list-content tfoot'),
url_list = data.urls,
url_number = 0, cached_number = 0,
url, trElement, tdElement;
// Clear out the existing items from the list.
while (contentsElement.firstChild) {
contentsElement.removeChild(contentsElement.firstChild);
}
console.log(url_list);
// Add each cached URL to the list, one by one.
for (url in url_list) {
if (url_list.hasOwnProperty(url)) {
var element;
cached_number = url_list[url].cached ? cached_number + 1 : cached_number;
url_number += 1;
trElement = document.createElement('tr');
tdElement = document.createElement('td');
tdElement.innerHTML = (url_list[url].cached ? "<span>&#x2713;</span>" : "")
trElement.appendChild(tdElement);
tdElement = document.createElement('td');
element = document.createElement('a');
element.setAttribute('href', "#view=editor&url=" + url);
element.textContent = url;
tdElement.appendChild(element);
trElement.appendChild(tdElement);
tdElement = document.createElement('td');
element = document.createElement('a');
element.textContent = "Go";
element.setAttribute('href', url);
element.setAttribute('target', "_blank");
element.setAttribute("class", "btn btn-primary btn-xs");
tdElement.appendChild(element);
trElement.appendChild(tdElement);
contentsElement.appendChild(trElement);
}
};
while (footer_element.firstChild) {
footer_element.removeChild(footer_element.firstChild);
}
trElement = document.createElement('tr');
tdElement = document.createElement('td');
tdElement.innerHTML = "<span>" + cached_number + " &#x2713;</span>";
trElement.appendChild(tdElement);
tdElement = document.createElement('td');
tdElement.innerHTML = url_number + " URLs";
trElement.appendChild(tdElement);
tdElement = document.createElement('td');
trElement.appendChild(tdElement);
footer_element.appendChild(trElement);
})
.fail(function(error) {
// XXX An Error Should be thrown
console.log(error);
throw error;
});
}
function saveTextContent(gadget, event) {
var content,
url = gadget.props.element.querySelector("form.crib-editor-get .url").value,
mimetype = gadget.props.element.querySelector("form.crib-editor-save .mimetype").value;
console.log("saving content");
return new RSVP.Queue()
.push(function () {
return gadget.getDeclaredGadget('codeeditor');
})
.push(function (code_editor_gadget) {
return code_editor_gadget.getContent();
})
.push(function (data) {
content = data[CODE_CONTENT_KEY] || "";
return gadget.getDeclaredGadget('crib_sw_gadget');
})
.push(function (crib_gadget) {
return crib_gadget.put(url, {content:content, type:mimetype});
})
.push(function() {
gadget.props.element.querySelector(".crib-editor-save-status").textContent = "Saved " + url + " files at "+ Date ()
})
.fail(function(error) {
console.log(error);
gadget.props.element.querySelector(".crib-editor-save-status").textContent = error;
});
}
function getUrlTextContent(gadget, event, url) {
console.log("saving content");
return new RSVP.Queue()
.push(function () {
return gadget.getDeclaredGadget('crib_sw_gadget');
})
.push(function (crib_gadget) {
return RSVP.all([crib_gadget.get(url),
gadget.getDeclaredGadget('codeeditor')])
})
.push(function(data_list) {
//gadget.props.element.querySelector("form.crib-editor-save .content").value = data_list[0].responseText;
gadget.props.element.querySelector("form.crib-editor-save .mimetype").value = data_list[0].responseType;
return data_list[1].render({
key: CODE_CONTENT_KEY,
value: data_list[0].responseText,
mode: data_list[0].responseType
});
})
.fail(function(error) {
console.log(error);
});
}
function saveContentToJIO(gadget, event) {
var path_to_save, path_to_save_length, application_id, crib_sw_gadget,
jio_gadget, url_list = [], saved_number = 0;
path_to_save = gadget.props.element.querySelector('form.crib-save-to-jio .save-path').value
application_id = gadget.props.element.querySelector('form.crib-save-to-jio .save-id').value
path_to_save_length = path_to_save.length;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
gadget.getDeclaredGadget('crib_sw_gadget'),
gadget.getDeclaredGadget('jio_gadget')]);
})
.push(function (gadget_list) {
crib_sw_gadget = gadget_list[0];
jio_gadget = gadget_list[1];
return crib_sw_gadget.allDocs({cached_only: true});
})
.push(function(data) {
url_list = data.urls;
// This is buggy, it fails if the document already exists with dav storage
return RSVP.all(
[jio_gadget.put("/" + application_id + ".attachment/", {
// url: path_to_save
}),
jio_gadget.putAttachment("/", application_id, new Blob([JSON.stringify({url: path_to_save})],{type: "application/json"}))
]);
})
.push(function() {
var promise_list = [],
i, i_len, url;
for (i = 0, i_len = url_list.length; i < i_len; i += 1) {
url = new String(url_list[i]);
if (url.indexOf(path_to_save) === 0) {
saved_number += 1;
promise_list.push(jIO.util.ajax({
url: url,
dataType: "blob"
}));
};
};
return RSVP.all(promise_list);
})
.push(function(response_list) {
var promise_list = [],
i, i_len, url, response, extension;
for (i = 0, i_len = response_list.length; i < i_len; i += 1) {
response = response_list[i];
url = response.target.responseURL.substr(path_to_save_length)
extension = getExtension(url)
console.log("Will push attachment " + url + " to " + path_to_save);
promise_list.push(
jio_gadget.putAttachment("/" + application_id + ".attachment/", btoa(url) + extension,
response.target.response
)
);
};
return RSVP.all(promise_list)
})
.push(function() {
gadget.props.element.querySelector(".crib-save-to-jio-status").textContent = "Saved " + saved_number + " files at "+ Date ()
})
.fail(function(error) {
gadget.props.element.querySelector(".crib-save-to-jio-status").textContent = error;
console.log(error);
});
}
function loadContentFromJIO(gadget, event) {
var path_to_load, path_to_load_length, application_id, crib_sw_gadget,
jio_gadget, url_list = [];
path_to_load = gadget.props.element.querySelector('form.crib-load-from-jio .load-path').value
application_id = gadget.props.element.querySelector('form.crib-load-from-jio .load-id').value
path_to_load_length = path_to_load.length;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
gadget.getDeclaredGadget('crib_sw_gadget'),
gadget.getDeclaredGadget('jio_gadget')]);
})
.push(function (gadget_list) {
crib_sw_gadget = gadget_list[0];
jio_gadget = gadget_list[1];
return jio_gadget.allAttachments("/" + application_id + ".attachment/");
})
.push(function(response) {
var promise_list = [],
key, extension;
for (key in response) {
if (response.hasOwnProperty(key)) {
extension = getExtension(key);
console.log(key);
url_list.push(atob(key.substr(0, key.length - extension.length)))
promise_list.push(jio_gadget.getAttachment("/" + application_id + ".attachment/", key));
}
};
return RSVP.all(promise_list)
})
.push(function(response_list) {
var promise_list = [],
i, i_len, url, index, response, location, location_len;
location = document.location.origin;
location_len = location.length
console.log(url_list);
console.log(response_list);
for (i = 0, i_len = response_list.length; i < i_len; i += 1) {
url = url_list[i]
index = url.indexOf(location);
if (index != -1)
url = url.substr(index + location_len);
promise_list.push(
crib_sw_gadget.put(path_to_load + url, {blob: response_list[i]})
)
}
})
.push(function() {
gadget.props.element.querySelector(".crib-load-from-jio-status").textContent = "Loaded " + url_list.length + " files at "+ Date ()
})
.fail(function(error) {
gadget.props.element.querySelector(".crib-load-from-jio-status").textContent = error;
console.log(error);
});
}
function massRemoveFromCache(gadget, event) {
var url_list = gadget.props.element.querySelector("form.crib-mass-remove textarea").value.match(/[^\r\n]+/g),
url_list_length = url_list.length;
return new RSVP.Queue()
.push(function () {
return gadget.getDeclaredGadget('crib_sw_gadget');
})
.push(function (crib_gadget) {
var i,
promise_list = [];
for (i = 0; i < url_list_length; i += 1) {
console.log(url_list[i])
promise_list.push(crib_gadget.remove(url_list[i]));
};
return RSVP.all(promise_list);
})
.push(function() {
gadget.props.element.querySelector(".crib-mass-remove-status").textContent = "Removed " + url_list.length + " files at "+ Date ()
})
.fail(function(error) {
gadget.props.element.querySelector(".crib-mass-remove-status").textContent = error;
console.log(error);
});
}
function displayTabContent(gadget, state) {
var tab_content_list = gadget.props.element.querySelectorAll('.nav_content');
console.log(tab_content_list.length);
for (var i = 0; i < tab_content_list.length; i += 1 ){
console.log('working with:');
console.log(tab_content_list[i]);
if (tab_content_list[i].getAttribute('class').indexOf(state) === -1) {
tab_content_list[i].setAttribute('style', 'display:none;');
} else {
tab_content_list[i].setAttribute('style', '');
}
}
}
rJS(window)
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
});
})
.ready(function (g) {
return createJio(g);
})
.allowPublicAcquisition("editor_saveContent", function () {
return saveTextContent(this, undefined);
})
.declareMethod('render', function (options) {
var promise_list = [],
gadget = this;
gadget.props.element.querySelector('form.crib-save-to-jio .save-path').value = document.location.origin;
gadget.props.element.querySelector('form.crib-load-from-jio .load-path').value = document.location.origin;
gadget.props.options = options;
// Add promise for list Cache content
if (options.url !== undefined) {
gadget.props.element.querySelector("form.crib-editor-get .url").value = options.url;
promise_list.push(getUrlTextContent(gadget, undefined, options.url))
}
displayTabContent(gadget, options.view || 'cribjs');
promise_list.push(displayURLList(gadget, undefined));
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-url-list-content"),
'submit',
false,
function (event) {displayURLList(gadget, event)}
));
// promise to get content from URL
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-editor-get"),
'submit',
false,
function (event) {
var url = gadget.props.element.querySelector("form.crib-editor-get .url").value;
return getUrlTextContent(gadget, event, url);
}
));
// promise to save content
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-editor-save"),
'submit',
false,
function (event) {saveTextContent(gadget, event)}
));
// promise to save content to jIO
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-save-to-jio"),
'submit',
false,
function (event) {saveContentToJIO(gadget, event)}
));
// promise to load content from jIO
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-load-from-jio"),
'submit',
false,
function (event) {loadContentFromJIO(gadget, event)}
));
// promise to remove content from cache
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-mass-remove"),
'submit',
false,
function (event) {massRemoveFromCache(gadget, event)}
));
// promise to use dav storage for jIO
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".form-use-jio-dav"),
'submit',
false,
function (event) {createDAVJio(gadget, event)}
));
// promise to use local storage for jIO
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".form-use-jio-local"),
'submit',
false,
function (event) {createJio(gadget, {type: "indexeddb", database: "cribjs"})}
));
return RSVP.all(promise_list);
})
}(window, document, RSVP, rJS, Handlebars, location, console));
\ No newline at end of file
html body nav.navbar-default {
background-color: transparent;
}
html body .navbar-default .navbar-nav>li>a {
color: #337ab7;
}
html body .navbar-default .navbar-brand {
color: #337ab7;
}
\ No newline at end of file
/*global window, rJS, RSVP, URI, location,
loopEventListener*/
/*jslint nomen: true, indent: 2, maxerr: 3*/
(function (window, rJS, RSVP) {
"use strict";
function setERP5Configuration(gadget) {
var old_date = new Date(),
configuration = {};
// We are looking for documents modified in the past 3 month
old_date.setMonth(old_date - 2);
old_date.setDay(1);
configuration = {
type: "replicate",
// XXX This drop the signature lists...
query: {
query: 'portal_type:"Web Page" '
// XX Synchonizing the whole module is too much, here is a way to start quietly
// Supsended until modification_date is handled for synchronization
+ ' AND modification_date:>="'
+ today.toISOString(),
limit: [0, 1234567890]
},
use_remote_post: true,
conflict_handling: 1,
check_local_modification: true,
check_local_creation: true,
check_local_deletion: false,
check_remote_modification: true,
check_remote_creation: true,
check_remote_deletion: true,
local_sub_storage: {
type: "query",
sub_storage: {
type: "uuid",
sub_storage: {
type: "indexeddb",
database: "officejs"
}
}
},
remote_sub_storage: {
type: "erp5",
url: (new URI("hateoas"))
.absoluteTo(location.href)
.toString(),
default_view_reference: "jio_view"
}
};
return gadget.setSetting('jio_storage_description', configuration)
.push(function () {
return gadget.setSetting('jio_storage_name', "ERP5");
})
.push(function () {
return gadget.reload();
});
}
function setLocalConfiguration(gadget) {
var configuration = {
type: "query",
sub_storage: {
type: "uuid",
sub_storage: {
type: "indexeddb",
database: "officejs"
}
}
};
return gadget.setSetting('jio_storage_description', configuration)
.push(function () {
return gadget.reload();
});
}
function setDAVConfiguration(gadget) {
return gadget.redirect({page: 'jio_dav_configurator'});
}
var gadget_klass = rJS(window);
gadget_klass
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.deferred = RSVP.defer();
});
})
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("translateHtml", "translateHtml")
.declareAcquiredMethod("redirect", "redirect")
.declareAcquiredMethod("reload", "reload")
.declareAcquiredMethod("setSetting", "setSetting")
.declareMethod("render", function () {
var gadget = this;
return gadget.updateHeader({
title: "Storage Configuration"
}).push(function () {
return gadget.props.deferred.resolve();
});
})
/////////////////////////////////////////
// Form submit
/////////////////////////////////////////
.declareService(function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.props.deferred.promise;
})
.push(function () {
return RSVP.all([
loopEventListener(
gadget.props.element.querySelector('form.select-erp5-form'),
'submit',
true,
function () {
return setERP5Configuration(gadget);
}
),
loopEventListener(
gadget.props.element.querySelector('form.select-local-form'),
'submit',
true,
function () {
return setLocalConfiguration(gadget);
}
),
loopEventListener(
gadget.props.element.querySelector('form.select-dav-form'),
'submit',
true,
function () {
return setDAVConfiguration(gadget);
}
)
]);
});
});
}(window, rJS, RSVP));
\ No newline at end of file
nav.navbar-default {
background-color: none;
}
\ No newline at end of file
/*globals window, document, RSVP, rJS, Handlebars, console*/
/*jslint indent: 2, maxlen: 80*/
(function (window, document, RSVP, rJS, Handlebars, console) {
"use strict";
function callCribSWGadget(gadget, method, param_list) {
var called = false;
return new RSVP.Queue()
.push(function () {
return gadget.getDeclaredGadget("crib_sw_gadget");
})
.push(function (crib_sw_gadget) {
return crib_sw_gadget[method].apply(crib_sw_gadget, param_list);
})
.push(function (result) {
return result;
}, function (error) {
throw error;
});
}
rJS(window)
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
});
})
.allowPublicAcquisition("crib_sw_allDocs", function (param_list) {
return callCribSWGadget(this, "allDocs", param_list);
})
.allowPublicAcquisition("crib_sw_remove", function (param_list) {
return callCribSWGadget(this, "remove", param_list);
})
.allowPublicAcquisition("crib_sw_put", function (param_list) {
return callCribSWGadget(this, "put", param_list);
})
.allowPublicAcquisition("crib_sw_get", function (param_list) {
return callCribSWGadget(this, "get", param_list);
})
.declareMethod('render', function (options) {
var promise_list = [],
gadget = this;
gadget.props.options = options;
// Add promise for list Cache content
// promise to use dav storage for jIO
return RSVP.Queue()
.push(function () {
return gadget.getDeclaredGadget('crib_ide_gadget');
})
.push(function (crib_ide_gadget) {
return crib_ide_gadget.render();
});
})
}(window, document, RSVP, rJS, console));
\ No newline at end of file
html body nav.navbar-default {
background-color: transparent;
}
/*Test*/
html body .navbar-default .navbar-nav>li>a {
color: #337ab7;
}
html body .navbar-default .navbar-brand {
color: #337ab7;
}
iframe {
width: 100%;
height: 100%;
top: 0;
bottom: 0;
position: fixed;
}
\ No newline at end of file
/*globals window, document, RSVP, rJS,
loopEventListener, jQuery, URI, location, XMLHttpRequest, console*/
/*jslint indent: 2, maxlen: 80*/
(function (window, document, RSVP, rJS, loopEventListener,
XMLHttpRequest, location, console) {
"use strict";
var MAIN_SCOPE = "m";
function renderMainGadget(gadget, url, options) {
return gadget.declareGadget(url, {
scope: MAIN_SCOPE
})
.push(function (page_gadget) {
if (page_gadget.render === undefined) {
return [page_gadget];
}
return RSVP.all([
page_gadget,
page_gadget.render(options)
]);
})
.push(function (all_result) {
return all_result[0];
});
}
function callCribSWGadget(gadget, method, param_list) {
var called = false;
return new RSVP.Queue()
.push(function () {
return gadget.getDeclaredGadget("crib_sw_gadget");
})
.push(function (crib_sw_gadget) {
return crib_sw_gadget[method].apply(crib_sw_gadget, param_list);
})
.push(function (result) {
return result;
}, function (error) {
throw error;
});
}
/*
function initHeaderOptions(gadget) {
gadget.props.header_argument_list = {
panel_action: true,
title: gadget.props.application_title || "OfficeJS"
};
}
*/
function route(my_root_gadget, my_scope, my_method, my_param_list) {
return RSVP.Queue()
.push(function () {
return my_root_gadget.getDeclaredGadget(my_scope);
})
.push(function (my_gadget) {
if (my_param_list) {
return my_gadget[my_method].apply(my_gadget, my_param_list);
}
return my_gadget[my_method]();
});
}
/*
function updateHeader(gadget) {
return gadget.getDeclaredGadget("header")
.push(function (header_gadget) {
return header_gadget.render(gadget.props.header_argument_list);
});
}
function increaseLoadingCounter(gadget) {
return new RSVP.Queue()
.push(function () {
gadget.props.loading_counter += 1;
if (gadget.props.loading_counter === 1) {
return gadget.getDeclaredGadget("header")
.push(function (header_gadget) {
return header_gadget.notifyLoading();
});
}
});
}
function decreaseLoadingCounter(gadget) {
return new RSVP.Queue()
.push(function () {
gadget.props.loading_counter -= 1;
if (gadget.props.loading_counter < 0) {
gadget.props.loading_counter = 0;
// throw new Error("Unexpected negative loading counter");
}
if (gadget.props.loading_counter === 0) {
return gadget.getDeclaredGadget("header")
.push(function (header_gadget) {
return header_gadget.notifyLoaded();
});
}
});
}
*/
function callJioGadget(gadget, method, param_list) {
var called = false;
return new RSVP.Queue()
.push(function () {
called = true;
return increaseLoadingCounter(gadget);
})
.push(function () {
return gadget.getDeclaredGadget("jio_gadget");
})
.push(function (jio_gadget) {
return jio_gadget[method].apply(jio_gadget, param_list);
})
.push(function (result) {
return decreaseLoadingCounter(gadget)
.push(function () {
return result;
});
}, function (error) {
if (called) {
return decreaseLoadingCounter(gadget)
.push(function () {
throw error;
});
}
throw error;
});
}
function displayErrorContent(gadget, error) {
// Do not break the application in case of errors.
// Display it to the user for now,
// and allow user to go back to the frontpage
var error_text = "";
if (error instanceof RSVP.CancellationError) {
return;
}
if (error.target instanceof XMLHttpRequest) {
error_text = error.target.toString() + " " +
error.target.status + " " +
error.target.statusText + "\n" +
error.target.responseURL + "\n\n" +
error.target.getAllResponseHeaders();
} else if (error instanceof Error) {
error_text = error.toString();
} else {
error_text = JSON.stringify(error);
}
console.error(error);
if (error instanceof Error) {
console.error(error.stack);
}
// XXX Improve error rendering
gadget.props.content_element.innerHTML = "<br/><br/><br/><pre></pre>";
gadget.props.content_element.querySelector('pre').textContent =
"Error: " + error_text;
// XXX Notify error
}
function displayError(gadget, error) {
return new RSVP.Queue()
.push(function () {
return displayErrorContent(gadget, error);
})
.push(function () {
return gadget.dropGadget(MAIN_SCOPE)
.push(undefined, function () {
// Do not crash the app if the pg gadget in not defined
// ie, keep the original error on screen
return;
});
});
}
function getSetting(gadget, key, default_value) {
return gadget.getDeclaredGadget("setting_gadget")
.push(function (jio_gadget) {
return jio_gadget.get("setting");
})
.push(function (doc) {
return doc[key] || default_value;
}, function (error) {
if (error.status_code === 404) {
return default_value;
}
throw error;
});
}
function setSetting(gadget, key, value) {
var jio_gadget;
return gadget.getDeclaredGadget("setting_gadget")
.push(function (result) {
jio_gadget = result;
return jio_gadget.get("setting");
})
.push(undefined, function (error) {
if (error.status_code === 404) {
return {};
}
throw error;
})
.push(function (doc) {
doc[key] = value;
return jio_gadget.put('setting', doc);
});
}
//////////////////////////////////////////
// Page rendering
//////////////////////////////////////////
rJS(window)
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.content_element = element.querySelector('.gadget-content');
});
})
// Configure setting storage
.ready(function (g) {
return g.getDeclaredGadget("setting_gadget")
.push(function (jio_gadget) {
return jio_gadget.createJio({
type: "indexeddb",
database: "setting"
});
});
})
.ready(function (g) {
// Extract configuration parameters stored in HTML
// XXX Will work only if top gadget...
var element_list =
document.querySelectorAll("[data-renderjs-configuration]"),
len = element_list.length,
key,
value,
i,
queue = new RSVP.Queue();
function push(a, b) {
queue.push(function () {
return setSetting(g, a, b);
});
}
for (i = 0; i < len; i += 1) {
key = element_list[i].getAttribute('data-renderjs-configuration');
value = element_list[i].textContent;
g.props[key] = value;
push(key, value);
}
return queue;
})
.ready(function (g) {
return setSetting(g, 'hateoas_url',
(new URI(g.props.hateoas_url))
.absoluteTo(location.href)
.toString()
);
})
// Configure jIO storage
/*.ready(function (g) {
var jio_gadget;
return g.getDeclaredGadget("jio_gadget")
.push(function (result) {
jio_gadget = result;
return getSetting(g, 'jio_storage_description');
})
.push(function (result) {
return jio_gadget.createJio(result);
});
})*/
/*
.ready(function (g) {
return g.getDeclaredGadget('panel')
.push(function (panel_gadget) {
return panel_gadget.render();
});
})
*/
.ready(function (g) {
return g.getDeclaredGadget('router')
.push(function (router_gadget) {
return router_gadget.start();
});
})
//////////////////////////////////////////
// Allow Acquisition
//////////////////////////////////////////
.allowPublicAcquisition("getSetting", function (argument_list) {
return getSetting(this, argument_list[0], argument_list[1]);
})
.allowPublicAcquisition("setSetting", function (argument_list) {
return setSetting(this, argument_list[0], argument_list[1]);
})
/*
.allowPublicAcquisition("translateHtml", function (argument_list) {
return this.getDeclaredGadget("translation_gadget")
.push(function (translation_gadget) {
return translation_gadget.translateHtml(argument_list[0]);
});
})
// XXX Those methods may be directly integrated into the header,
// as it handles the submit triggering
.allowPublicAcquisition('notifySubmitting', function () {
return route(this, "header", 'notifySubmitting');
})
.allowPublicAcquisition('notifySubmitted', function () {
return route(this, "header", "notifySubmitted");
})
.allowPublicAcquisition('notifyChange', function () {
return route(this, "header", 'notifyChange');
})
.allowPublicAcquisition("translate", function (argument_list) {
return this.getDeclaredGadget("translation_gadget")
.push(function (translation_gadget) {
return translation_gadget.translate(argument_list[0]);
});
})
/**/
.allowPublicAcquisition("redirect", function (param_list) {
return this.getDeclaredGadget('router')
.push(function (router_gadget) {
return router_gadget.redirect.apply(router_gadget, param_list);
});
})
.allowPublicAcquisition('reload', function () {
return location.reload();
})
.allowPublicAcquisition("getUrlParameter", function (param_list) {
return this.getDeclaredGadget('router')
.push(function (router_gadget) {
return router_gadget.getUrlParameter.apply(router_gadget, param_list);
});
})
.allowPublicAcquisition("getUrlFor", function (param_list) {
return this.getDeclaredGadget('router')
.push(function (router_gadget) {
return router_gadget.getCommandUrlFor.apply(router_gadget,
param_list);
});
})
/*
.allowPublicAcquisition("updateHeader", function (param_list) {
var gadget = this;
initHeaderOptions(gadget);
return this.getDeclaredGadget("translation_gadget")
.push(function (translation_gadget) {
var promise_list = [],
key;
for (key in param_list[0]) {
if (param_list[0].hasOwnProperty(key)) {
gadget.props.header_argument_list[key] = param_list[0][key];
}
}
promise_list.push(translation_gadget.translate(
gadget.props.header_argument_list.title
));
if (gadget.props.header_argument_list.hasOwnProperty('right_title')) {
promise_list.push(translation_gadget.translate(
gadget.props.header_argument_list.right_title
));
}
return RSVP.all(promise_list);
})
.push(function (result_list) {
gadget.props.header_argument_list.title = result_list[0];
if (result_list.length === 2) {
gadget.props.header_argument_list.right_title = result_list[1];
}
// XXX Sven hack: number of _url determine padding for
// subheader on ui-content
var key,
count = 0;
for (key in gadget.props.header_argument_list) {
if (gadget.props.header_argument_list.hasOwnProperty(key)) {
if (key.indexOf('_url') > -1) {
count += 1;
}
}
}
if (count > 2) {
gadget.props.sub_header_class = "ui-has-subheader";
}
});
})
.allowPublicAcquisition('triggerPanel', function () {
return route(this, "panel", "toggle");
})
.allowPublicAcquisition('renderEditorPanel', function (param_list) {
return route(this, "editor_panel", 'render', param_list);
})
/**/
.allowPublicAcquisition("jio_createJio", function (param_list) {
return callJioGadget(this, "createJio", param_list);
})
.allowPublicAcquisition("jio_allDocs", function (param_list) {
return callJioGadget(this, "allDocs", param_list);
})
.allowPublicAcquisition("jio_remove", function (param_list) {
return callJioGadget(this, "remove", param_list);
})
.allowPublicAcquisition("jio_post", function (param_list) {
return callJioGadget(this, "post", param_list);
})
.allowPublicAcquisition("jio_put", function (param_list) {
return callJioGadget(this, "put", param_list);
})
.allowPublicAcquisition("jio_get", function (param_list) {
return callJioGadget(this, "get", param_list);
})
.allowPublicAcquisition("jio_allAttachments", function (param_list) {
return callJioGadget(this, "allAttachments", param_list);
})
.allowPublicAcquisition("jio_getAttachment", function (param_list) {
return callJioGadget(this, "getAttachment", param_list);
})
.allowPublicAcquisition("jio_putAttachment", function (param_list) {
return callJioGadget(this, "putAttachment", param_list);
})
.allowPublicAcquisition("jio_removeAttachment", function (param_list) {
return callJioGadget(this, "removeAttachment", param_list);
})
.allowPublicAcquisition("jio_repair", function (param_list) {
return callJioGadget(this, "repair", param_list);
})
.allowPublicAcquisition("triggerSubmit", function (param_list) {
return this.getDeclaredGadget(MAIN_SCOPE)
.push(function (main_gadget) {
return main_gadget.triggerSubmit(param_list);
});
})
.allowPublicAcquisition("crib_sw_allDocs", function (param_list) {
return callCribSWGadget(this, "allDocs", param_list);
})
.allowPublicAcquisition("crib_sw_remove", function (param_list) {
return callCribSWGadget(this, "remove", param_list);
})
.allowPublicAcquisition("crib_sw_put", function (param_list) {
return callCribSWGadget(this, "put", param_list);
})
.allowPublicAcquisition("crib_sw_get", function (param_list) {
return callCribSWGadget(this, "get", param_list);
})
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.allowPublicAcquisition("renderApplication", function (param_list) {
return this.renderXXX.apply(this, param_list);
})
// Render the page
.declareMethod('renderXXX', function (options) {
var gadget = this;
gadget.props.options = options;
// Reinitialize the loading counter
gadget.props.loading_counter = 0;
// By default, init the header options to be empty
// (ERP5 title by default + sidebar)
//initHeaderOptions(gadget);
return new RSVP.Queue()
/*.push(function () {
return increaseLoadingCounter(gadget);
})
.push(function () {
return gadget.getDeclaredGadget('panel');
})
.push(function (panel_gadget) {
return panel_gadget.close();
})
.push(function () {
return gadget.getDeclaredGadget('editor_panel');
})
.push(function (editor_panel) {
return editor_panel.close();
})/**/
.push(function () {
return gadget.getDeclaredGadget('router');
})
.push(function (router_gadget) {
return router_gadget.route(options);
})
.push(function (route_result) {
return renderMainGadget(
gadget,
route_result.url,
route_result.options
);
})
.push(function (main_gadget) {
// Append loaded gadget in the page
if (main_gadget !== undefined) {
return main_gadget.getElement()
.push(function (fragment) {
var element = gadget.props.content_element,
content_container = document.createElement("div");
//content_container.className = "ui-content " +
// (gadget.props.sub_header_class || "");
// reset subheader indicator
//delete gadget.props.sub_header_class;
// go to the top of the page
window.scrollTo(0, 0);
// Clear first to DOM, append after to reduce flickering/manip
while (element.firstChild) {
element.removeChild(element.firstChild);
}
content_container.appendChild(fragment);
element.appendChild(content_container);
//$(element).trigger("create");
//return updateHeader(gadget);
// XXX Drop notification
// return header_gadget.notifyLoaded();
});
}
})
/*.push(function () {
return decreaseLoadingCounter(gadget);
}, function (error) {
return decreaseLoadingCounter(gadget)
.push(function () {
throw error;
});
})/**/
.push(undefined, function (error) {
return displayError(gadget, error);
});
})
/////////////////////////////////
// Handle sub gadgets services
/////////////////////////////////
.allowPublicAcquisition('reportServiceError', function (param_list,
gadget_scope) {
if (gadget_scope === undefined) {
// don't fail in case of dropped subgadget (like previous page)
return;
}
return displayError(this, param_list[0]);
})
.declareService(function () {
////////////////////////////////////
// Form submit listening. Prevent browser to automatically
// handle the form submit in case of a bug
////////////////////////////////////
var gadget = this;
function catchFormSubmit() {
return displayError(gadget, new Error("Unexpected form submit"));
}
// Listen to form submit
return loopEventListener(
gadget.props.element,
'submit',
false,
catchFormSubmit
);
});
}(window, document, RSVP, rJS, loopEventListener,
XMLHttpRequest, location, console));
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="/lib/bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="/crib-editor3/cribjs.css">
<title>CribJS</title>
<script src="/lib/rsvp.js"></script>
<script src="/lib/jio-latest.js"></script>
<script src="/lib/renderjs.js"></script>
<script src="/gadget/gadget_global.js"></script>
<script src="cribjs_launcher.js"></script>
</head>
<body>
<div data-gadget-url="/gadget/gadget_jio.html"
data-gadget-scope="setting_gadget"
data-gadget-sandbox="public"></div>
<div data-gadget-url="/gadget/gadget_cribjs_router.html"
data-gadget-scope="router"
data-gadget-sandbox="public"></div>
<div data-gadget-url="/gadget/gadget_cribjs_header.html"
data-gadget-scope="header"
data-gadget-sandbox="public"></div>
<div data-gadget-url="/gadget/crib-sw-gadget.html"
data-gadget-scope="crib_sw_gadget"
data-gadget-sandbox="public"></div>
<div data-gadget-url="/gadget/gadget_jio.html"
data-gadget-scope="jio_gadget"
data-gadget-sandbox="public"></div>
<div role="main" class="ui-content gadget-content"></div>
</body>
</html>
\ No newline at end of file
https://www.cribjs.com/cribjs-conqueror.html
https://cedriclendav.node.vifib.com/public/cribjs/cribjs-conqueror.html
https://cedriclendav.node.vifib.com/public/cribjs-storage/
\ No newline at end of file
......@@ -6,8 +6,8 @@
<title>Crib SW interface Gadget</title>
<!-- renderjs -->
<script src="../lib/rsvp.js" type="text/javascript"></script>
<script src="../lib/renderjs.js" type="text/javascript"></script>
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="crib-sw-gadget.js" type="text/javascript"></script>
......
......@@ -135,7 +135,6 @@
.declareMethod('put', function(url, parameter) {
return new RSVP.Queue()
.push(function() {
console.log(url);
if (parameter.blob !== undefined) {
return sendMessage({
command: 'add',
......
......@@ -4,13 +4,13 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="../lib/bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="/lib/bootstrap/bootstrap.min.css">
<title>CribJS</title>
<script src="../lib/sha256.js"></script>
<script src="../lib/sha256.amd.js"></script>
<script src="../lib/rsvp.js"></script>
<script src="../lib/jio-latest.js"></script>
<script src="../lib/renderjs.js"></script>
<script src="/lib/sha256.js"></script>
<script src="/lib/sha256.amd.js"></script>
<script src="/lib/rsvp.js"></script>
<script src="/lib/jio-latest.js"></script>
<script src="/lib/renderjs.js"></script>
<script src="cribjs-ide-gadget.js"></script>
<!--The following CSS shows a lack of developing style -->
<style>
......
......@@ -5,23 +5,23 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Codemirror Gadget</title>
<script src="../lib/rsvp.js" type="text/javascript"></script>
<script src="../lib/renderjs.js" type="text/javascript"></script>
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<link rel="stylesheet" href="../lib/codemirror.css">
<link rel="stylesheet" href="../lib/codemirror/addon/dialog/dialog.css">
<link rel="stylesheet" href="../lib/codemirror/addon/search/matchesonscrollbar.css">
<link rel="stylesheet" href="/lib/codemirror.css">
<link rel="stylesheet" href="/lib/codemirror/addon/dialog/dialog.css">
<link rel="stylesheet" href="/lib/codemirror/addon/search/matchesonscrollbar.css">
<script src="../lib/codemirror.js"></script>
<script src="../lib/codemirror/mode/css/css.js"></script>
<script src="../lib/codemirror/mode/xml/xml.js"></script>
<script src="../lib/codemirror/mode/javascript/javascript.js"></script>
<script src="../lib/codemirror/mode/htmlmixed/htmlmixed.js"></script>
<script src="../lib/codemirror/addon/dialog/dialog.js"></script>
<script src="../lib/codemirror/addon/search/searchcursor.js"></script>
<script src="../lib/codemirror/addon/search/search.js"></script>
<script src="../lib/codemirror/addon/scroll/annotatescrollbar.js"></script>
<script src="../lib/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="/lib/codemirror.js"></script>
<script src="/lib/codemirror/mode/css.js"></script>
<script src="/lib/codemirror/mode/xml.js"></script>
<script src="/lib/codemirror/mode/javascript.js"></script>
<script src="/lib/codemirror/mode/htmlmixed.js"></script>
<script src="/lib/codemirror/addon/dialog/dialog.js"></script>
<script src="/lib/codemirror/addon/search/searchcursor.js"></script>
<script src="/lib/codemirror/addon/search/search.js"></script>
<script src="/lib/codemirror/addon/scroll/annotatescrollbar.js"></script>
<script src="/lib/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="gadget_codemirror.js" type="text/javascript"></script>
</head>
......
<!DOCTYPE html>
<html>
<head>
<base href="https://texteditor.app.officejs.com/gadget_officejs_header.html/" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>OfficeJS Header</title>
<!-- renderjs -->
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<script src="/lib/handlebars.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_cribjs_header.js" type="text/javascript"></script>
<script id="header-title-link-template" type="text/x-handlebars-template"><a data-i18n="{{title}}" class="ui-btn ui-btn-icon-left ui-icon-arrow-down" href="{{url}}">{{title}}</a></script>
<script id="header-title-template" type="text/x-handlebars-template"><span data-i18n="{{title}}">{{title}}</span></script>
<script id="header-link-template" type="text/x-handlebars-template">
<a role="button" data-i18n="{{title}}" href="{{url}}" class="responsive ui-btn ui-icon-{{icon}} ui-btn-icon-left ui-first-child ui-last-child {{class}}">{{title}}</a>
</script>
<script id="header-button-template" type="text/x-handlebars-template">
<form><button name='{{name}}' data-i18n="{{title}}" type='submit' class='responsive ui-btn ui-icon-{{icon}} ui-btn-icon-left ui-first-child ui-last-child {{class}}'>{{title}}</button></form>
</script>
</head>
<body>
<!--div data-role="header" data-theme="a" class="ui-header ui-bar-a" data-position="fixed" data-tap-toggle="false">
<div data-role="header" data-theme="a" class="ui-header ui-bar-a" data-tap-toggle="false">
<div class="ui-controlgroup ui-controlgroup-horizontal ui-btn-left">
<div class="ui-controlgroup-controls">
</div>
</div>
<h1 class="ui-title"></h1>
<div class="ui-controlgroup ui-controlgroup-horizontal ui-btn-right">
<div class="ui-controlgroup-controls">
</div>
</div>
</div-->
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#page=cribjs_home">CribJS</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="#page=url_list">URL List</a></li>
<li><a href="#page=editor">Editor</a></li>
<li><a href="#page=save_load">Export/Import</a></li>
<li><a href="#page=mass_remove">Remove</a></li>
</ul>
</div>
</div>
</nav>
</body>
</html>
\ No newline at end of file
/*jslint nomen: true, indent: 2, maxerr: 3 */
/*global window, rJS, Handlebars, document, loopEventListener, RSVP */
(function (window, rJS, Handlebars, document, loopEventListener, RSVP) {
"use strict";
/////////////////////////////////////////////////////////////////
// Handlebars
/////////////////////////////////////////////////////////////////
// Precompile the templates while loading the first gadget instance
var gadget_klass = rJS(window),
header_title_source = gadget_klass.__template_element
.getElementById("header-title-template")
.innerHTML,
header_title_template = Handlebars.compile(header_title_source),
header_title_link_source = gadget_klass.__template_element
.getElementById("header-title-link-template")
.innerHTML,
header_title_link_template = Handlebars.compile(header_title_link_source),
header_button_source = gadget_klass.__template_element
.getElementById("header-button-template")
.innerHTML,
header_button_template = Handlebars.compile(header_button_source),
header_link_source = gadget_klass.__template_element
.getElementById("header-link-template")
.innerHTML,
header_link_template = Handlebars.compile(header_link_source);
gadget_klass
/////////////////////////////////////////////////////////////////
// ready
/////////////////////////////////////////////////////////////////
// Init local properties
.ready(function (g) {
g.props = {};
g.stats = {
loaded: false,
modified: false,
submitted: true,
error: false,
options: {}
};
})
// Assign the element to a variable
.ready(function (g) {
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.left_link = element.querySelector(".ui-btn-left > div");
g.props.right_link = element.querySelector(".ui-btn-right > div");
g.props.title_element = element.querySelector("h1");
});
})
/*
.ready(function (g) {
return g.render(g.stats.options);
})
*/
//////////////////////////////////////////////
// acquired methods
//////////////////////////////////////////////
.declareAcquiredMethod("translateHtml", "translateHtml")
.declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareAcquiredMethod("triggerSubmit", "triggerSubmit")
.declareAcquiredMethod("triggerPanel", "triggerPanel")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
/*
.declareMethod('notifyError', function () {
this.stats.loaded = true;
this.stats.submitted = true;
this.stats.error = true;
var gadget = this;
return this.render(this.stats.options)
.push(function () {
gadget.stats.error = false;
});
})
.declareMethod('notifyUpdate', function () {
return this.render(this.stats.options);
})
*/
.declareMethod('notifyLoading', function () {
if (this.stats.loaded) {
this.stats.loaded = false;
return this.render(this.stats.options);
}
})
.declareMethod('notifyLoaded', function () {
if (!this.stats.loaded) {
this.stats.loaded = true;
return this.render(this.stats.options);
}
})
/*
.declareMethod('notifyChange', function () {
if (!this.stats.modified) {
this.stats.modified = true;
return this.render(this.stats.options);
}
})
.declareMethod('notifySubmitting', function () {
if (this.stats.submitted) {
this.stats.submitted = false;
return this.render(this.stats.options);
}
})
.declareMethod('notifySubmitted', function () {
if (!this.stats.submitted) {
this.stats.submitted = true;
// Change modify here, to allow user to redo some modification and being correctly notified
this.stats.modified = false;
return this.render(this.stats.options);
}
})
*/
.declareMethod('render', function (options) {
var gadget = this,
possible_left_link_list = [
// ['menu_url', 'Menu', 'bars'],
['selection_url', 'Back', 'arrow-left'],
['view_url', 'View', 'check'],
['cancel_url', 'Cancel', 'times'],
['back_url', 'Back', 'arrow-left']
],
possible_left_button_list = [
['panel_action', 'Menu', 'bars', 'panel']
],
possible_right_link_list = [
['edit_url', 'Edit', 'pencil'],
['add_url', 'Add', 'plus'],
['new_url', 'New', 'plus']
],
possible_right_button_list = [
['save_action', 'Save', 'check', 'submit'],
['submit_action', 'Proceed', 'check', 'submit']
],
i,
klass,
//left_link = {
// title: "Menu",
// icon: "bars",
// url: "#leftpanel",
// class: "ui-disabled"
// },
left_link,
left_button,
right_link,
right_button,
default_right_text,
default_right_icon = "",
title_link = {},
promise_list = [];
gadget.stats.options = options;
// Handle main title
if (options.hasOwnProperty("title")) {
title_link.title = options.title;
// Updating globally the page title. Does not follow RenderJS philosophy, but, it is enough for now
document.title = title_link.title;
}
if (options.hasOwnProperty("breadcrumb_url")) {
title_link.url = options.breadcrumb_url;
promise_list.push(gadget.translateHtml(header_title_link_template(title_link)));
} else {
promise_list.push(gadget.translateHtml(header_title_template(title_link)));
}
// Handle left link
for (i = 0; i < possible_left_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_left_link_list[i][0])) {
klass = "";
if (!options[possible_left_link_list[i][0]]) {
klass = "ui-disabled";
}
left_link = {
title: possible_left_link_list[i][1],
icon: possible_left_link_list[i][2],
url: options[possible_left_link_list[i][0]],
class: klass
};
}
}
for (i = 0; i < possible_left_button_list.length; i += 1) {
if (options.hasOwnProperty(possible_left_button_list[i][0])
&& options[possible_left_button_list[i][0]]) {
left_button = {
title: possible_left_button_list[i][1],
icon: possible_left_button_list[i][2],
name: possible_left_button_list[i][3]
};
}
}
if (left_button !== undefined) {
promise_list.push(gadget.translateHtml(header_button_template(left_button)));
} else if (left_link === undefined) {
promise_list.push(gadget.translateHtml(""));
} else {
promise_list.push(gadget.translateHtml(header_link_template(left_link)));
}
// Handle right link
if (gadget.stats.error) {
default_right_icon = "exclamation";
} else if (!gadget.stats.loaded) {
default_right_icon = "spinner";
// Show default loading information
right_link = {
title: "Loading",
icon: default_right_icon,
url: "",
class: "ui-disabled ui-icon-spin"
};
} else if (!gadget.stats.submitted) {
default_right_icon = "spinner";
} else if (gadget.stats.modified) {
default_right_text = "Save";
default_right_icon = "warning";
}
for (i = 0; i < possible_right_link_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_link_list[i][0])) {
klass = "";
if (!options[possible_right_link_list[i][0]]) {
klass = "ui-disabled";
}
right_link = {
title: possible_right_link_list[i][1],
icon: default_right_icon || possible_right_link_list[i][2],
url: options[possible_right_link_list[i][0]],
class: klass
};
}
}
for (i = 0; i < possible_right_button_list.length; i += 1) {
if (options.hasOwnProperty(possible_right_button_list[i][0])
&& options[possible_right_button_list[i][0]]) {
right_button = {
title: default_right_text || possible_right_button_list[i][1],
icon: default_right_icon || possible_right_button_list[i][2],
name: possible_right_button_list[i][3]
};
if (gadget.stats.error) {
right_button.class = "ui-disabled";
}
}
}
if (right_button !== undefined) {
promise_list.push(gadget.translateHtml(header_button_template(right_button)));
} else if (right_link !== undefined) {
promise_list.push(gadget.translateHtml(header_link_template(right_link)));
} else {
promise_list.push(gadget.translateHtml(""));
}
return new RSVP.Queue()
.push(function () {
return RSVP.all(promise_list);
})
.push(function (my_translated_html_list) {
gadget.props.title_element.innerHTML = my_translated_html_list[0];
gadget.props.left_link.innerHTML = my_translated_html_list[1];
gadget.props.right_link.innerHTML = my_translated_html_list[2];
});
})
//////////////////////////////////////////////
// handle button click
//////////////////////////////////////////////
.declareService(function () {
var form_gadget = this;
function formSubmit(evt) {
var button = evt.target[0],
name = button.getAttribute("name");
if (name === "panel") {
return form_gadget.triggerPanel();
}
if (name === "submit") {
return form_gadget.triggerSubmit();
}
throw new Error("Unsupported button " + name);
}
// Listen to form submit
return loopEventListener(
form_gadget.props.element,
'submit',
false,
formSubmit
);
});
}(window, rJS, Handlebars, document, loopEventListener, RSVP));
\ No newline at end of file
......@@ -6,16 +6,16 @@
<meta name="viewport" content="width=device-width">
<title>CribJS Loader</title>
<script src="../lib/rsvp.js"></script>
<script src="../lib/renderjs.js"></script>
<script src="/lib/rsvp.js"></script>
<script src="/lib/renderjs.js"></script>
<script src="gadget_cribjs_loader.js"></script>
</head>
<body>
<h1>CribJS Loader</h1>
<div data-gadget-url="gadget_jio_cribjs.html"
<div data-gadget-url="/gadget/gadget_jio_cribjs.html"
data-gadget-scope="jio_cribjs"
data-gadget-sandbox="public"></div>
<div data-gadget-url="gadget_jio_configurator.html"
<div data-gadget-url="/gadget/gadget_jio_configurator.html"
data-gadget-scope="jio_configurator"
data-gadget-sandbox="public"></div>
<form>
......
......@@ -8,7 +8,7 @@
jio_configurator_gadget;
return RSVP.Queue()
.push(function() {
return RSPV.all([
return RSVP.all([
gadget.getDeclaredGadget("jio_cribjs"),
gadget.getDeclaredGadget("jio_configurator")]);
})
......@@ -19,14 +19,14 @@
})
.push(function (jio_string) {
return jio_cribjs_gadget.load({
path: document.location.href,
path: document.location.origin,
jio_config: JSON.parse(jio_string),
application_id: "cribjs"
})
})
.push(function (url_list) {
console.log(url_list);
document.location = document.location.href + "/crib-editor/";
document.location = document.location.origin + "/crib-editor/";
})
}
......@@ -35,7 +35,6 @@
.declareMethod('render', function (options) {
var gadget = this,
jio_configuration_string = "";
console.log("rendering");
if (localStorage.hasOwnProperty("crib_js_loader_jio")) {
jio_configuration_string = localStorage.getItem("crib_js_loader_jio");
} else {
......@@ -46,12 +45,11 @@
return gadget.getDeclaredGadget('jio_configurator');
})
.push(function (jio_configurator_gadget) {
console.log(jio_configuration_string);
return jio_configurator_gadget.render({value: jio_configuration_string});
})
.push(function () {
return loopEventListener(
gadget.props.element.querySelector("form"),
gadget.props.element.querySelector("form.loading"),
'submit',
false,
function (event) {loadCribJS(gadget, event)}
......
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>CribJS Header</title>
</head>
<body>
<div class="nav_content cribjs container">
<h1>CribJS: have a taste of your web</h1>
<p>Developed to bring the free software idea to the web,
CribJS offer to you the possibility to create your version of the web application you are using.
Make your copy of the web from here: learn, modify, improve, share.</p>
<p>As this application is a place to develop web applications, it can edit itself.
See how it is made, modify it, improve it.
Start developping your own way. Feel free to make this place your own crib.</p>
<ul>
<li>1. Browse the <a href="#view=url_list">list of URLs</a> you wish to edit</li>
<li>2. Edit and add files in your <a href="#view=editor">Editor</a></li>
<li>3. <a href="#view=save_load">Export and Import</a> your copy of the web locally and remotly</li>
<li>4. <a href="#view=mass_remove">Remove</a> uncessary URLs</li>
</ul>
<p>Have fun building the web :), here is your <a href="/crib-editor/todo.txt">TODO list</a>.</p>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>CribJS Header</title>
<!-- renderjs -->
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<!-- Custom -->
<script src="gadget_cribjs_page_editor.js" type="text/javascript"></script>
</head>
<body>
<div class="nav_content editor">
<div class="container">
<div class="row">
<form class="crib-editor-get form-inline">
<h3>Edit</h3>
<div class="form-group">
<label>URL:
<input name="url" class="url form-control" type="text" size="50" value=""></label>
</div>
<button type="submit" name="get" class="btn btn-default">Load</button>
</form>
</div>
<div class="row">
<form class="crib-editor-save form-inline">
<div class="form-group">
<label>Mimetype:
<input class="mimetype form-control" name="mimetype" type="text" size="50" value="text/html">
</label>
</div>
<div class="form-group">
<button name="add" type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
<div class="row">
<table class="table">
<tr>
<td class="success"><span class="crib-editor-save-status"></span></td>
</tr>
</table>
</div>
</div>
<div class="container-fluid">
<div data-gadget-url="/gadget/gadget_codemirror.html"
data-gadget-scope="codeeditor"
data-gadget-sandbox="public"></div>
</div>
</div>
</body>
</html>
\ No newline at end of file
/*global window, rJS, loopEventListener */
/*jslint nomen: true, indent: 2, maxerr: 3*/
(function (window, rJS, loopEventListener) {
"use strict";
var CODE_CONTENT_KEY = "text_content";
function saveTextContent(gadget, event) {
var content,
url = gadget.props.element.querySelector("form.crib-editor-get .url").value,
mimetype = gadget.props.element.querySelector("form.crib-editor-save .mimetype").value;
return new RSVP.Queue()
.push(function () {
return gadget.getDeclaredGadget('codeeditor');
})
.push(function (code_editor_gadget) {
return code_editor_gadget.getContent();
})
.push(function (data) {
content = data[CODE_CONTENT_KEY] || "";
return gadget.crib_sw_put(url, {content:content, type:mimetype});
})
.push(function() {
gadget.props.element.querySelector(".crib-editor-save-status").textContent = "Saved " + url + " files at "+ Date ()
})
}
function getUrlTextContent(gadget, event, url) {
return new RSVP.Queue()
.push(function () {
return RSVP.all([gadget.crib_sw_get(url),
gadget.getDeclaredGadget('codeeditor')])
})
.push(function(data_list) {
//gadget.props.element.querySelector("form.crib-editor-save .content").value = data_list[0].responseText;
gadget.props.element.querySelector("form.crib-editor-save .mimetype").value = data_list[0].responseType;
return data_list[1].render({
key: CODE_CONTENT_KEY,
value: data_list[0].responseText,
mode: data_list[0].responseType
});
})
}
rJS(window)
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.start_deferred = RSVP.defer();
});
})
.allowPublicAcquisition("editor_saveContent", function () {
return saveTextContent(this, undefined);
})
.declareAcquiredMethod("crib_sw_get", "crib_sw_get")
.declareAcquiredMethod("crib_sw_put", "crib_sw_put")
.declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareMethod('render', function (options) {
var gadget = this;
if (options === undefined)
options = {}
gadget.props.options = options;
return new RSVP.Queue()
.push(function () {
if (options.url !== undefined) {
gadget.props.element.querySelector("form.crib-editor-get .url").value = options.url;
return getUrlTextContent(gadget, undefined, options.url)
}
})
.push(function () {
return gadget.props.start_deferred.resolve();
})
})
.declareService(function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.props.start_deferred.promise;
})
.push(function () {
var promise_list = [];
// promise to get content from URL
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-editor-get"),
'submit',
false,
function (event) {
var url = gadget.props.element.querySelector("form.crib-editor-get .url").value;
return getUrlTextContent(gadget, event, url);
}
));
// promise to save content
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-editor-save"),
'submit',
false,
function (event) {saveTextContent(gadget, event)}
));
return RSVP.all(promise_list);
});
})
}(window, rJS, loopEventListener));
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>CribJS Header</title>
<!-- renderjs -->
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<!-- Custom -->
<script src="gadget_cribjs_page_mass_remove.js" type="text/javascript"></script>
</head>
<body>
<div class="nav_content mass_remove container">
<form class="crib-mass-remove">
<h3>Mass removal</h3>
<div class="form-group">
<textarea name="mass-remove-list" cols="35" wrap="soft" class="form-control"></textarea>
</div>
<button type="submit" class="mass-remove btn btn-danger" name="mass-remove">Mass remove from Cache</button>
<div><span class="crib-mass-remove-status"></span></div>
</form>
</div>
</body>
</html>
\ No newline at end of file
/*global window, rJS, loopEventListener */
/*jslint nomen: true, indent: 2, maxerr: 3*/
(function (window, rJS, loopEventListener) {
"use strict";
function massRemoveFromCache(gadget, event) {
var url_list = gadget.props.element.querySelector("form.crib-mass-remove textarea").value.match(/[^\r\n]+/g),
url_list_length = url_list.length;
return new RSVP.Queue()
.push(function () {
var i,
promise_list = [];
for (i = 0; i < url_list_length; i += 1) {
promise_list.push(gadget.crib_sw_remove(url_list[i]));
};
return RSVP.all(promise_list);
})
.push(function() {
gadget.props.element.querySelector(".crib-mass-remove-status").textContent = "Removed " + url_list.length + " files at "+ Date ()
})
.fail(function(error) {
gadget.props.element.querySelector(".crib-mass-remove-status").textContent = error;
console.log(error);
});
}
rJS(window)
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.start_deferred = RSVP.defer();
});
})
.declareAcquiredMethod("crib_sw_remove", "crib_sw_remove")
.declareMethod('render', function (options) {
var gadget = this;
if (options === undefined)
options = {};
gadget.props.options = options;
return new RSVP.Queue()
.push(function () {
return gadget.props.start_deferred.resolve();
})
})
.declareService(function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.props.start_deferred.promise;
})
.push(function () {
var promise_list = [];
// promise to remove content from cache
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-mass-remove"),
'submit',
false,
function (event) {massRemoveFromCache(gadget, event)}
));
return RSVP.all(promise_list);
});
})
}(window, rJS, loopEventListener));
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>CribJS Header</title>
<!-- renderjs -->
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<script src="/lib/jszip.js" type="text/javascript"></script>
<script src="/lib/FileSaver.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<!-- Custom -->
<script src="gadget_cribjs_page_save_load.js" type="text/javascript"></script>
</head>
<body>
<div class="nav_content save_load container">
<h3>Storage</h3>
<h4>Dav Storage</h4>
<form class="form-horizontal form-use-jio-dav">
<div class="form-group">
<label for="url" class="col-sm-2 control-label">URL</label>
<div class="col-sm-10">
<input type="text" class="form-control url" id="url" value="https://yourdav.node.vifib.com/public/cribjs-storage/">
</div>
</div>
<div class="form-group">
<label for="credential" class="col-sm-2 control-label">Credential</label>
<div class="col-sm-10">
<input type="password" class="form-control credential" id="credential" placeholder="couscous:admin">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Use Dav Storage</button>
</div>
</div>
</form>
<h4>Local Storage</h4>
<form class="form-horizontal form-use-jio-local">
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<button class="btn btn-default" type="submit">Local is Enough</button>
</div>
</div>
</form>
<form class="crib-save-to-jio form-inline">
<h3>Export</h3>
<div class="form-group">
<label>Export:
<input class="save-path form-control" name="save-path" type="text" size="30" value=""></label>
</div>
<div class="form-group">
<label> to:
<input name="save-id" class="save-id form-control" type="text" size="30" value="cribjs"></label>
</div>
<button name="save-contents" type="submit" class="btn btn-default">Export</button>
</form>
<div><span class="info crib-save-to-jio-status"></span></div>
<form class="crib-load-from-jio form-inline">
<h3>Import</h3>
<div class="form-group">
<label>Import :
<input name="load-id" class="load-id form-control" type="text" size="30" value="cribjs"></label>
</div>
<div class="form-group">
<label> to path:
<input name="load-path" class="load-path form-control" type="text" size="30" value="cribeditor/v1.1">
</label>
</div>
<button name="load-contents" class="load-contents btn btn-default" type="submit">Import</button>
</form>
<form class="crib-save-to-zip form-inline">
<h3>Export to Zip</h3>
<div class="form-group">
<label>Export to zip:
<input class="save-zip-path form-control" name="save-zip-path" type="text" size="30" value=""></label>
</div>
<div class="form-group">
<label> to:
<input name="save-zip-id" class="save-zip-id form-control" type="text" size="30" value="cribjs.zip"></label>
</div>
<button name="save-zip-contents" type="submit" class="btn btn-default">Export to Zip</button>
</form>
<div><span class="info crib-save-to-zip-status"></span></div>
<form class="crib-load-from-zip form-inline">
<h3>Import from zip</h3>
<div class="form-group">
<label>Import from zip:
<input name="load-zip-file" class="load-zip-file form-control" type="file" size="30"></label>
</div>
<div class="form-group">
<label> to path:
<input name="load-zip-path" class="load-zip-path form-control" type="text" size="30" value="cribeditor/v1.1">
</label>
</div>
<button name="load-zip-contents" class="load-zip-contents btn btn-default" type="submit">Import from zip</button>
</form>
<div><span class="crib-load-from-zip-status"></span></div>
</div>
<div data-gadget-url="/gadget/gadget_jio.html"
data-gadget-scope="jio_gadget"
data-gadget-sandbox="public"></div>
</body>
</html>
\ No newline at end of file
/*global window, rJS, loopEventListener */
/*jslint nomen: true, indent: 2, maxerr: 3*/
(function (window, rJS, loopEventListener, JSZip, FileSaver) {
"use strict";
function getExtension(url) {
var extension = url.split('.').pop();
if (extension.endsWith('/')) {
return ".html";
}
return "." + extension;
}
function createJio(gadget, jio_config) {
var jio_gadget;
return gadget.getDeclaredGadget("jio_gadget")
.push(function (jio_g) {
jio_gadget = jio_g;
if (jio_config === undefined)
jio_config = {type: "indexeddb", database: "cribjs"};
return jio_gadget.createJio(jio_config);
});
}
function createDAVJio(gadget, event) {
return createJio(gadget, {
type:"dav",
url: gadget.props.element.querySelector('.form-use-jio-dav .url').value,
basic_login: btoa(gadget.props.element.querySelector(".form-use-jio-dav .credential").value)
});
}
function saveContentToJIO(gadget, event) {
var path_to_save, path_to_save_length, application_id, crib_sw_gadget,
jio_gadget, url_list = [], saved_number = 0;
path_to_save = gadget.props.element.querySelector('form.crib-save-to-jio .save-path').value
application_id = gadget.props.element.querySelector('form.crib-save-to-jio .save-id').value
path_to_save_length = path_to_save.length;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
gadget.getDeclaredGadget('jio_gadget')]);
})
.push(function (gadget_list) {
jio_gadget = gadget_list[0];
return gadget.crib_sw_allDocs({cached_only: true});
})
.push(function(data) {
url_list = data.urls;
// This is buggy, it fails if the document already exists with dav storage
return RSVP.all(
[jio_gadget.put("/" + application_id + ".attachment/", {
// url: path_to_save
}),
jio_gadget.putAttachment("/", application_id, new Blob([JSON.stringify({url: path_to_save})],{type: "application/json"}))
]);
})
.push(function() {
var promise_list = [],
i, i_len, url;
for (i = 0, i_len = url_list.length; i < i_len; i += 1) {
url = new String(url_list[i]);
if (url.indexOf(path_to_save) === 0) {
saved_number += 1;
promise_list.push(gadget.crib_sw_get(url));
};
};
return RSVP.all(promise_list);
})
.push(function(response_list) {
var promise_list = [],
i, i_len, url, response, extension;
for (i = 0, i_len = response_list.length; i < i_len; i += 1) {
response = response_list[i];
url = response.responseURL.substr(path_to_save_length)
extension = getExtension(url)
promise_list.push(
jio_gadget.putAttachment("/" + application_id + ".attachment/", btoa(url) + extension,
// XXX Not sure it would work with images
new Blob([response.responseText], {type : response.responseType})
)
);
};
return RSVP.all(promise_list)
})
.push(function() {
gadget.props.element.querySelector(".crib-save-to-jio-status").textContent = "Saved " + saved_number + " files at "+ Date ()
})
}
function loadContentFromJIO(gadget, event) {
var path_to_load, path_to_load_length, application_id, crib_sw_gadget,
jio_gadget, url_list = [];
path_to_load = gadget.props.element.querySelector('form.crib-load-from-jio .load-path').value
application_id = gadget.props.element.querySelector('form.crib-load-from-jio .load-id').value
path_to_load_length = path_to_load.length;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
gadget.getDeclaredGadget('jio_gadget')]);
})
.push(function (gadget_list) {
jio_gadget = gadget_list[0];
return jio_gadget.allAttachments("/" + application_id + ".attachment/");
})
.push(function(response) {
var promise_list = [],
key, extension;
for (key in response) {
if (response.hasOwnProperty(key)) {
extension = getExtension(key);
url_list.push(atob(key.substr(0, key.length - extension.length)))
promise_list.push(jio_gadget.getAttachment("/" + application_id + ".attachment/", key));
}
};
return RSVP.all(promise_list)
})
.push(function(response_list) {
var promise_list = [],
i, i_len, url, index, response, location, location_len;
location = document.location.origin;
location_len = location.length
for (i = 0, i_len = response_list.length; i < i_len; i += 1) {
url = url_list[i]
index = url.indexOf(location);
if (index != -1)
url = url.substr(index + location_len);
promise_list.push(
gadget.crib_sw_put(path_to_load + url, {blob: response_list[i]})
)
}
})
.push(function() {
gadget.props.element.querySelector(".crib-load-from-jio-status").textContent = "Loaded " + url_list.length + " files at "+ Date ()
});
}
// Zip Methods
function saveContentToZIP(gadget, event) {
var path_to_save, path_to_save_length, application_id, crib_sw_gadget,
jio_gadget, url_list = [], saved_number = 0, zip;
path_to_save = gadget.props.element.querySelector('form.crib-save-to-zip .save-zip-path').value
application_id = gadget.props.element.querySelector('form.crib-save-to-zip .save-zip-id').value
path_to_save_length = path_to_save.length;
return new RSVP.Queue()
.push(function () {
return RSVP.all([
gadget.getDeclaredGadget('jio_gadget')]);
})
.push(function (gadget_list) {
jio_gadget = gadget_list[0];
return gadget.crib_sw_allDocs({cached_only: true});
})
.push(function(data) {
var promise_list = [],
i, i_len, url;
if (Array.isArray(data.urls)) {
url_list = data.urls;
} else {
url_list = Object.keys(data.urls);
}
for (i = 0, i_len = url_list.length; i < i_len; i += 1) {
url = new String(url_list[i]);
if (url.indexOf(path_to_save) === 0) {
saved_number += 1;
promise_list.push(gadget.crib_sw_get(url));
};
};
return RSVP.all(promise_list);
})
.push(function(response_list) {
var promise_list = [],
i, i_len, url, response, extension, zip;
zip = new JSZip();
for (i = 0, i_len = response_list.length; i < i_len; i += 1) {
response = response_list[i];
url = response.responseURL.substr(path_to_save_length)
if ( url.endsWith("/") ) {
url = url + "index.html";
}
zip.file(url, response.responseText)
};
return zip.generateAsync({type:"blob"});
})
.push(function(content) {
return saveAs(content, application_id)
})
.push(function() {
gadget.props.element.querySelector(".crib-save-to-zip-status").textContent = "Saved " + saved_number + " files at "+ Date ()
})
.push(console.log, console.log)
}
function loadContentFromZIP(gadget, event) {
var path_to_load, path_to_load_length, file_list, crib_sw_gadget,
jio_gadget, url_list = [], file, url_number = 0;
path_to_load = gadget.props.element.querySelector('form.crib-load-from-zip .load-zip-path').value
file_list = gadget.props.element.querySelector('form.crib-load-from-zip .load-zip-file').files
if (file_list.length === 0) {
gadget.props.element.querySelector(".crib-load-from-zip-status").textContent = "Please put a Zip at "+ Date ()
return
}
path_to_load_length = path_to_load.length;
file = file_list[0]
return new RSVP.Queue()
.push(function () {
return JSZip.loadAsync(file);
})
.push(function (zip) {
var promise_list = [];
zip.forEach(function (relativePath, zipEntry) {
var end_url;
url_number += 1;
if ( zipEntry.dir ) {
return
}
if (!relativePath.startsWith("/") && !path_to_load.endsWith("/")) {
end_url = path_to_load + "/" + relativePath
} else if (relativePath.startsWith("/") && path_to_load.endsWith("/")) {
end_url = path_to_load + relativePath.substring(1);
} else {
end_url = path_to_load + relativePath
}
promise_list.push(
new RSVP.Queue().
push(function () {
return zipEntry.async('blob');
})
.push(function (result) {
if ( end_url.endsWith(".js") ) {
// This is a ugly hack as mimetype needs to be correct for JS
result = result.slice(0, result.size, "application/javascript")
} else if ( end_url.endsWith(".html") ) {
// This is a ugly hack as mimetype needs to be correct for JS
result = result.slice(0, result.size, "text/html")
} else if ( end_url.endsWith(".css") ) {
// This is a ugly hack as mimetype needs to be correct for JS
result = result.slice(0, result.size, "text/css")
}
return gadget.crib_sw_put(end_url, {blob: result})
})
)
})
return RSVP.all(promise_list)
})
.push(function() {
gadget.props.element.querySelector(".crib-load-from-zip-status").textContent = "Loaded " + url_number + " files at "+ Date ()
})
.push(console.log, console.log)
}
rJS(window)
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.start_deferred = RSVP.defer();
});
})
.declareAcquiredMethod("crib_sw_allDocs", "crib_sw_allDocs")
.declareAcquiredMethod("crib_sw_get", "crib_sw_get")
.declareAcquiredMethod("crib_sw_put", "crib_sw_put")
.declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareMethod('render', function (options) {
var gadget = this;
if (options === undefined)
options = {};
gadget.props.options = options;
gadget.props.element.querySelector('form.crib-save-to-jio .save-path').value = document.location.origin;
gadget.props.element.querySelector('form.crib-load-from-jio .load-path').value = document.location.origin;
gadget.props.element.querySelector('form.crib-save-to-zip .save-zip-path').value = document.location.origin;
return new RSVP.Queue()
.push(function () {
return gadget.props.start_deferred.resolve();
})
})
.declareService(function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.props.start_deferred.promise;
})
.push(function () {
var promise_list = [];
// promise to save content to jIO
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-save-to-jio"),
'submit',
false,
function (event) {saveContentToJIO(gadget, event)}
));
// promise to load content from jIO
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-load-from-jio"),
'submit',
false,
function (event) {loadContentFromJIO(gadget, event)}
));
// promise to use dav storage for jIO
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".form-use-jio-dav"),
'submit',
false,
function (event) {createDAVJio(gadget, event)}
));
// promise to use local storage for jIO
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".form-use-jio-local"),
'submit',
false,
function (event) {createJio(gadget, {type: "indexeddb", database: "cribjs"})}
));
// promise to save content to ZIP
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-save-to-zip"),
'submit',
false,
function (event) {saveContentToZIP(gadget, event)}
));
// promise to load content from ZIP
promise_list.push(loopEventListener(
gadget.props.element.querySelector(".crib-load-from-zip"),
'submit',
false,
function (event) {loadContentFromZIP(gadget, event)}
));
return RSVP.all(promise_list);
});
})
}(window, rJS, loopEventListener, JSZip, FileSaver));
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>CribJS Header</title>
<!-- renderjs -->
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<!-- Custom -->
<script src="gadget_cribjs_page_url_list.js" type="text/javascript"></script>
</head>
<body>
<div class="nav_content url_list container">
<form class="crib-url-list-content">
<h3>URL List</h3>
<button type="submit" name="list-contents" class="btn btn-default">Refresh</button>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Cached</th>
<th>Url</th>
<th>Go</th>
</tr>
</thead>
<tfoot>
</tfoot>
<tbody>
</tbody>
</table>
<div>
<button type="submit" name="list-contents" class="btn btn-default">Refresh</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
/*global window, rJS, loopEventListener */
/*jslint nomen: true, indent: 2, maxerr: 3*/
(function (window, rJS, loopEventListener) {
"use strict";
function displayURLList(gadget, event) {
var url_list;
return new RSVP.Queue()
.push(function () {
return gadget.crib_sw_allDocs()
})
.push(function (data) {
var promise_list = [],
url;
url_list = data.urls;
for (url in url_list) {
if (url_list.hasOwnProperty(url)) {
promise_list.push(gadget.getUrlFor({page: 'editor', url: url}));
}
}
return RSVP.all(promise_list);
})
.push(function(url_link_list) {
var contentsElement = gadget.props.element.querySelector('.crib-url-list-content tbody'),
footer_element = gadget.props.element.querySelector('.crib-url-list-content tfoot'),
url_number = 0, cached_number = 0,
url, trElement, tdElement;
// Clear out the existing items from the list.
while (contentsElement.firstChild) {
contentsElement.removeChild(contentsElement.firstChild);
}
console.log(url_list);
// Add each cached URL to the list, one by one.
for (url in url_list) {
if (url_list.hasOwnProperty(url)) {
var element;
trElement = document.createElement('tr');
tdElement = document.createElement('td');
tdElement.innerHTML = (url_list[url].cached ? "<span>&#x2713;</span>" : "")
trElement.appendChild(tdElement);
tdElement = document.createElement('td');
element = document.createElement('a');
element.setAttribute('href', url_link_list[url_number]);
element.textContent = url;
tdElement.appendChild(element);
trElement.appendChild(tdElement);
tdElement = document.createElement('td');
element = document.createElement('a');
element.textContent = "Go";
element.setAttribute('href', url);
element.setAttribute('target', "_blank");
element.setAttribute("class", "btn btn-primary btn-xs");
tdElement.appendChild(element);
trElement.appendChild(tdElement);
contentsElement.appendChild(trElement);
cached_number = url_list[url].cached ? cached_number + 1 : cached_number;
url_number += 1;
}
};
while (footer_element.firstChild) {
footer_element.removeChild(footer_element.firstChild);
}
trElement = document.createElement('tr');
tdElement = document.createElement('td');
tdElement.innerHTML = "<span>" + cached_number + " &#x2713;</span>";
trElement.appendChild(tdElement);
tdElement = document.createElement('td');
tdElement.innerHTML = url_number + " URLs";
trElement.appendChild(tdElement);
tdElement = document.createElement('td');
trElement.appendChild(tdElement);
footer_element.appendChild(trElement);
})
}
rJS(window)
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
g.props.start_deferred = RSVP.defer();
});
})
.declareAcquiredMethod("crib_sw_allDocs", "crib_sw_allDocs")
.declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareMethod('render', function (options) {
var gadget = this;
if (options === undefined)
options = {}
gadget.props.options = options;
return new RSVP.Queue()
.push(function () {
return displayURLList(gadget, undefined);
})
.push(function () {
return gadget.props.start_deferred.resolve();
})
})
.declareService(function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.props.start_deferred.promise;
})
.push(function () {
return loopEventListener(
gadget.props.element.querySelector(".crib-url-list-content"),
'submit',
false,
function (event) {displayURLList(gadget, event)}
)
});
})
}(window, rJS, loopEventListener));
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>CribSJ Router Gadget</title>
<!-- renderjs -->
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_cribjs_router.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
\ No newline at end of file
/*global window, rJS */
/*jslint nomen: true, indent: 2, maxerr: 3*/
(function (window, rJS) {
"use strict";
var gadget_klass = rJS(window),
MAIN_PAGE_PREFIX = "/gadget/gadget_cribjs_",
DEFAULT_PAGE = "cribjs_home",
REDIRECT_TIMEOUT = 5000;
function listenHashChange(gadget) {
function extractHashAndDispatch(evt) {
var hash = (evt.newURL || window.location.toString()).split('#')[1],
subhashes,
subhash,
keyvalue,
index,
args = {};
if (hash !== undefined) {
subhashes = hash.split('&');
for (index in subhashes) {
if (subhashes.hasOwnProperty(index)) {
subhash = subhashes[index];
if (subhash !== '') {
keyvalue = subhash.split('=');
if (keyvalue.length === 2) {
args[decodeURIComponent(keyvalue[0])] = decodeURIComponent(keyvalue[1]);
}
}
}
}
}
return gadget.renderApplication({
args: args
});
}
var result = loopEventListener(window, 'hashchange', false,
extractHashAndDispatch),
event = document.createEvent("Event");
event.initEvent('hashchange', true, true);
event.newURL = window.location.toString();
window.dispatchEvent(event);
return result;
}
gadget_klass
.ready(function (gadget) {
gadget.props = {
start_deferred: RSVP.defer()
};
})
.declareMethod("getCommandUrlFor", function(options) {
var prefix = '',
result,
key;
result = "#";
for (key in options) {
if (options.hasOwnProperty(key) && options[key] !== undefined) {
// Don't keep empty values
result += prefix + encodeURIComponent(key) + "=" + encodeURIComponent(options[key]);
prefix = '&';
}
}
return result;
})
.declareMethod('redirect', function (options) {
if (options !== undefined && options.toExternal) {
window.location.replace(options.url);
return RSVP.timeout(REDIRECT_TIMEOUT); // timeout if not redirected
}
else {
return this.getCommandUrlFor(options)
.push(function (hash) {
window.location.replace(hash);
// prevent returning unexpected response
// wait for the hash change to occur
// fail if nothing happens
return RSVP.timeout(REDIRECT_TIMEOUT);
});
}
})
.declareMethod('route', function (options) {
var gadget = this,
args = options.args;
gadget.options = options;
if (args.jio_key === undefined || args.jio_key === '') {
if (args.page === undefined || args.page === '' || args.page === "document_list") {
args.page = DEFAULT_PAGE;
}
return {
url: MAIN_PAGE_PREFIX + "page_" + args.page + ".html",
options: args
};
}
return gadget.jio_get(args.jio_key)
.push(function (doc) {
var sub_options = {},
base_portal_type = doc.portal_type.toLowerCase().replace(/\s/g, "_");
sub_options = {
doc: doc,
jio_key: args.jio_key,
search: args.search
};
if (base_portal_type.search(/_temp$/) >= 0) {
//Remove "_temp"
base_portal_type = base_portal_type.substr(
0,
base_portal_type.length - 5
);
}
return {
url: MAIN_PAGE_PREFIX + "jio_"
+ base_portal_type
+ "_" + args.page + ".html",
options: sub_options
};
});
})
.declareAcquiredMethod('jio_get', 'jio_get')
.declareAcquiredMethod('renderApplication', 'renderApplication')
.declareMethod('start', function () {
this.props.start_deferred.resolve();
})
.declareService(function () {
var gadget = this;
return new RSVP.Queue()
.push(function () {
return gadget.props.start_deferred.promise;
})
.push(function () {
return listenHashChange(gadget);
});
});
}(window, rJS));
\ No newline at end of file
/*global window, RSVP, FileReader */
/*jslint indent: 2, maxerr: 3, unparam: true */
(function (window, RSVP, FileReader) {
"use strict";
window.loopEventListener = function (target, type, useCapture, callback,
prevent_default) {
//////////////////////////
// Infinite event listener (promise is never resolved)
// eventListener is removed when promise is cancelled/rejected
//////////////////////////
var handle_event_callback,
callback_promise;
if (prevent_default === undefined) {
prevent_default = true;
}
function cancelResolver() {
if ((callback_promise !== undefined) &&
(typeof callback_promise.cancel === "function")) {
callback_promise.cancel();
}
}
function canceller() {
if (handle_event_callback !== undefined) {
target.removeEventListener(type, handle_event_callback, useCapture);
}
cancelResolver();
}
function itsANonResolvableTrap(resolve, reject) {
var result;
handle_event_callback = function (evt) {
if (prevent_default) {
evt.stopPropagation();
evt.preventDefault();
}
cancelResolver();
try {
result = callback(evt);
} catch (e) {
result = RSVP.reject(e);
}
callback_promise = result;
new RSVP.Queue()
.push(function () {
return result;
})
.push(undefined, function (error) {
if (!(error instanceof RSVP.CancellationError)) {
canceller();
reject(error);
}
});
};
target.addEventListener(type, handle_event_callback, useCapture);
}
return new RSVP.Promise(itsANonResolvableTrap, canceller);
};
window.promiseEventListener = function (target, type, useCapture) {
//////////////////////////
// Resolve the promise as soon as the event is triggered
// eventListener is removed when promise is cancelled/resolved/rejected
//////////////////////////
var handle_event_callback;
function canceller() {
target.removeEventListener(type, handle_event_callback, useCapture);
}
function resolver(resolve) {
handle_event_callback = function (evt) {
canceller();
evt.stopPropagation();
evt.preventDefault();
resolve(evt);
return false;
};
target.addEventListener(type, handle_event_callback, useCapture);
}
return new RSVP.Promise(resolver, canceller);
};
window.promiseReadAsText = function (file) {
return new RSVP.Promise(function (resolve, reject) {
var reader = new FileReader();
reader.onload = function (evt) {
resolve(evt.target.result);
};
reader.onerror = function (evt) {
reject(evt);
};
reader.readAsText(file);
});
};
}(window, RSVP, FileReader));
\ No newline at end of file
......@@ -8,10 +8,10 @@
<title>Jio Gadget</title>
<!-- renderjs -->
<script src="../lib/rsvp.js" type="text/javascript"></script>
<script src="../lib/renderjs.js" type="text/javascript"></script>
<script src="/lib/rsvp.js" type="text/javascript"></script>
<script src="/lib/renderjs.js" type="text/javascript"></script>
<script src="../lib/jio-latest.js" type="text/javascript"></script>
<script src="/lib/jio-latest.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_jio.js" type="text/javascript"></script>
......
......@@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width">
<title>CribJS Loader</title>
<script src="../lib/rsvp.js"></script>
<script src="../lib/renderjs.js"></script>
<script src="/lib/rsvp.js"></script>
<script src="/lib/renderjs.js"></script>
<script src="gadget_jio_configurator.js"></script>
</head>
<body>
......
......@@ -6,15 +6,15 @@
<meta name="viewport" content="width=device-width">
<title>CribJS Loader</title>
<script src="../lib/rsvp.js"></script>
<script src="../lib/renderjs.js"></script>
<script src="/lib/rsvp.js"></script>
<script src="/lib/renderjs.js"></script>
<script src="gadget_jio_cribjs.js"></script>
</head>
<body>
<div data-gadget-url="crib-sw-gadget.html"
<div data-gadget-url="/gadget/crib-sw-gadget.html"
data-gadget-scope="crib_sw_gadget"
data-gadget-sandbox="public"></div>
<div data-gadget-url="gadget_jio.html"
<div data-gadget-url="/gadget/gadget_jio.html"
data-gadget-scope="jio_gadget"
data-gadget-sandbox="public"></div>
</body>
......
......@@ -52,9 +52,8 @@
})
.push(function(response_list) {
var promise_list = [],
i, i_len, url, index, response, location, location_len,
new_url;
location = document.location.href;
i, i_len, url, index, response, location, location_len;
location = document.location.origin;
location_len = location.length
for (i = 0, i_len = response_list.length; i < i_len; i += 1) {
url = url_list[i]
......@@ -62,13 +61,8 @@
if (index != -1)
url = url.substr(index + location_len);
console.log(path_to_load + url);
if (path_to_load.endsWith("/") && url.startsWith("/")) {
new_url = path_to_load + url.substr(1)
} else {
new_url = path_to_load + url
}
promise_list.push(
crib_sw_gadget.put(new_url, {blob: response_list[i]})
crib_sw_gadget.put(path_to_load + url, {blob: response_list[i]})
)
}
return RSVP.all(promise_list);
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>CribJS Loader</title>
<script src="/lib/rsvp.js"></script>
<script src="/lib/renderjs.js"></script>
<!--script src="gadget_jio_simple_configurator.js"></script-->
</head>
<body>
<h3>Storage</h3>
<div class="row">
<div class="col-md-6">
<form class="select-dav-form">
<button class="btn btn-default btn-lg btn-block" type="submit" data-i18n="DAV Storage">DAV Storage</button>
</form>
</div>
<div class="col-md-6">
<form class="select-local-form">
<button class="btn btn-default btn-lg btn-block" type="submit" data-i18n="Local is Enough">Local is Enough</button>
</form>
</div>
</div>
</body>
</html>
\ No newline at end of file
/*jslint nomen: true, indent: 2, maxerr: 3 */
/*global window, rJS */
(function (window, rJS) {
"use strict";
rJS(window)
.declareAcquiredMethod("saveContent", "editor_saveContent")
.declareMethod('render', function (options) {
if (options && options.hasOwnProperty("value"))
this.props.element.querySelector("textarea").value = options.value || "";
})
.declareMethod('getContent', function () {
return this.props.element.querySelector("textarea").value;
})
.ready(function (g) {
g.props = {};
return g.getElement()
.push(function (element) {
g.props.element = element;
});
});
}(window, rJS));
\ No newline at end of file
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define([], factory);
} else if (typeof exports !== "undefined") {
factory();
} else {
var mod = {
exports: {}
};
factory();
global.FileSaver = mod.exports;
}
})(this, function () {
"use strict";
/*
* FileSaver.js
* A saveAs() FileSaver implementation.
*
* By Eli Grey, http://eligrey.com
*
* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
* source : http://purl.eligrey.com/github/FileSaver.js
*/
// The one and only way of getting global scope in all environments
// https://stackoverflow.com/q/3277182/1008999
var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0;
function bom(blob, opts) {
if (typeof opts === 'undefined') opts = {
autoBom: false
};else if (typeof opts !== 'object') {
console.warn('Deprecated: Expected third argument to be a object');
opts = {
autoBom: !opts
};
} // prepend BOM for UTF-8 XML and text/* types (including HTML)
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob([String.fromCharCode(0xFEFF), blob], {
type: blob.type
});
}
return blob;
}
function download(url, name, opts) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.onload = function () {
saveAs(xhr.response, name, opts);
};
xhr.onerror = function () {
console.error('could not download file');
};
xhr.send();
}
function corsEnabled(url) {
var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker
xhr.open('HEAD', url, false);
try {
xhr.send();
} catch (e) {}
return xhr.status >= 200 && xhr.status <= 299;
} // `a.click()` doesn't work for all browsers (#465)
function click(node) {
try {
node.dispatchEvent(new MouseEvent('click'));
} catch (e) {
var evt = document.createEvent('MouseEvents');
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
node.dispatchEvent(evt);
}
} // Detect WebView inside a native macOS app by ruling out all browsers
// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
var isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent);
var saveAs = _global.saveAs || ( // probably in some web worker
typeof window !== 'object' || window !== _global ? function saveAs() {}
/* noop */
// Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
: 'download' in HTMLAnchorElement.prototype && !isMacOSWebView ? function saveAs(blob, name, opts) {
var URL = _global.URL || _global.webkitURL;
var a = document.createElement('a');
name = name || blob.name || 'download';
a.download = name;
a.rel = 'noopener'; // tabnabbing
// TODO: detect chrome extensions & packaged apps
// a.target = '_blank'
if (typeof blob === 'string') {
// Support regular links
a.href = blob;
if (a.origin !== location.origin) {
corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
} else {
click(a);
}
} else {
// Support blobs
a.href = URL.createObjectURL(blob);
setTimeout(function () {
URL.revokeObjectURL(a.href);
}, 4E4); // 40s
setTimeout(function () {
click(a);
}, 0);
}
} // Use msSaveOrOpenBlob as a second approach
: 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
name = name || blob.name || 'download';
if (typeof blob === 'string') {
if (corsEnabled(blob)) {
download(blob, name, opts);
} else {
var a = document.createElement('a');
a.href = blob;
a.target = '_blank';
setTimeout(function () {
click(a);
});
}
} else {
navigator.msSaveOrOpenBlob(bom(blob, opts), name);
}
} // Fallback to using FileReader and a popup
: function saveAs(blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker
// Mostly only available on user interaction and the fileReader is async so...
popup = popup || open('', '_blank');
if (popup) {
popup.document.title = popup.document.body.innerText = 'downloading...';
}
if (typeof blob === 'string') return download(blob, name, opts);
var force = blob.type === 'application/octet-stream';
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== 'undefined') {
// Safari doesn't allow downloading of blob URLs
var reader = new FileReader();
reader.onloadend = function () {
var url = reader.result;
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
if (popup) popup.location.href = url;else location = url;
popup = null; // reverse-tabnabbing #460
};
reader.readAsDataURL(blob);
} else {
var URL = _global.URL || _global.webkitURL;
var url = URL.createObjectURL(blob);
if (popup) popup.location = url;else location.href = url;
popup = null; // reverse-tabnabbing #460
setTimeout(function () {
URL.revokeObjectURL(url);
}, 4E4); // 40s
}
});
_global.saveAs = saveAs.saveAs = saveAs;
if (typeof module !== 'undefined') {
module.exports = saveAs;
}
});
\ No newline at end of file
......@@ -41,21 +41,19 @@
/* CURSOR */
.CodeMirror-cursor {
.CodeMirror div.CodeMirror-cursor {
border-left: 1px solid black;
border-right: none;
width: 0;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.cm-fat-cursor .CodeMirror-cursor {
.CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
}
.cm-fat-cursor div.CodeMirror-cursors {
.CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
......@@ -84,7 +82,7 @@
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror-overwrite .CodeMirror-cursor {}
div.CodeMirror-overwrite div.CodeMirror-cursor {}
.cm-tab { display: inline-block; text-decoration: inherit; }
......@@ -165,7 +163,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actual scrolling happens, thus preventing shaking and
before actuall scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
......@@ -286,19 +284,19 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
overflow: hidden;
visibility: hidden;
}
.CodeMirror-cursor { position: absolute; }
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor {
position: absolute;
border-right: none;
width: 0;
}
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 3;
}
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
......
......@@ -13,7 +13,7 @@
else if (typeof define == "function" && define.amd) // AMD
return define([], mod);
else // Plain browser env
(this || window).CodeMirror = mod();
this.CodeMirror = mod();
})(function() {
"use strict";
......@@ -21,29 +21,27 @@
// Kludges for bugs and behavior differences that can't be feature
// detected are enabled based on userAgent etc sniffing.
var userAgent = navigator.userAgent;
var platform = navigator.platform;
var gecko = /gecko\/\d/i.test(userAgent);
var ie_upto10 = /MSIE \d/.test(userAgent);
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
var gecko = /gecko\/\d/i.test(navigator.userAgent);
var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
var ie = ie_upto10 || ie_11up;
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
var webkit = /WebKit\//.test(userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
var chrome = /Chrome\//.test(userAgent);
var presto = /Opera\//.test(userAgent);
var webkit = /WebKit\//.test(navigator.userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
var chrome = /Chrome\//.test(navigator.userAgent);
var presto = /Opera\//.test(navigator.userAgent);
var safari = /Apple Computer/.test(navigator.vendor);
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
var phantom = /PhantomJS/.test(userAgent);
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
var phantom = /PhantomJS/.test(navigator.userAgent);
var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
// This is woefully incomplete. Suggestions for alternative methods welcome.
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
var mac = ios || /Mac/.test(platform);
var windows = /win/i.test(platform);
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
var mac = ios || /Mac/.test(navigator.platform);
var windows = /win/i.test(navigator.platform);
var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
if (presto_version) presto_version = Number(presto_version[1]);
if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
......@@ -89,7 +87,6 @@
focused: false,
suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
selectingText: false,
draggingText: false,
highlight: new Delayed(), // stores highlight worker timeout
keySeq: null, // Unfinished key sequence
......@@ -410,7 +407,7 @@
if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
});
this.checkedZeroWidth = false;
this.checkedOverlay = false;
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
}
......@@ -445,43 +442,29 @@
this.horiz.firstChild.style.width = "0";
}
if (!this.checkedZeroWidth && measure.clientHeight > 0) {
if (sWidth == 0) this.zeroWidthHack();
this.checkedZeroWidth = true;
if (!this.checkedOverlay && measure.clientHeight > 0) {
if (sWidth == 0) this.overlayHack();
this.checkedOverlay = true;
}
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
},
setScrollLeft: function(pos) {
if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
},
setScrollTop: function(pos) {
if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);
},
zeroWidthHack: function() {
overlayHack: function() {
var w = mac && !mac_geMountainLion ? "12px" : "18px";
this.horiz.style.height = this.vert.style.width = w;
this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
this.disableHoriz = new Delayed;
this.disableVert = new Delayed;
},
enableZeroWidthBar: function(bar, delay) {
bar.style.pointerEvents = "auto";
function maybeDisable() {
// To find out whether the scrollbar is still visible, we
// check whether the element under the pixel in the bottom
// left corner of the scrollbar box is the scrollbar box
// itself (when the bar is still visible) or its filler child
// (when the bar is hidden). If it is still visible, we keep
// it enabled, if it's hidden, we disable pointer events.
var box = bar.getBoundingClientRect();
var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);
if (elt != bar) bar.style.pointerEvents = "none";
else delay.set(1000, maybeDisable);
}
delay.set(1000, maybeDisable);
this.horiz.style.minHeight = this.vert.style.minWidth = w;
var self = this;
var barMouseDown = function(e) {
if (e_target(e) != self.vert && e_target(e) != self.horiz)
operation(self.cm, onMouseDown)(e);
};
on(this.vert, "mousedown", barMouseDown);
on(this.horiz, "mousedown", barMouseDown);
},
clear: function() {
var parent = this.horiz.parentNode;
......@@ -823,7 +806,7 @@
// given line.
function updateWidgetHeight(line) {
if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;
line.widgets[i].height = line.widgets[i].node.offsetHeight;
}
// Do a bulk-read of the DOM positions and sizes needed to draw the
......@@ -1094,6 +1077,10 @@
if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
}
function isReadOnly(cm) {
return cm.options.readOnly || cm.doc.cantEdit;
}
// This will be set to an array of strings when copying, so that,
// when pasting, we know what kind of selections the copied text
// was made out of.
......@@ -1148,7 +1135,6 @@
var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
if (pasted) {
e.preventDefault();
if (!cm.isReadOnly() && !cm.options.disableInput)
runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
return true;
}
......@@ -1251,14 +1237,13 @@
});
on(te, "paste", function(e) {
if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return
if (handlePaste(e, cm)) return true;
cm.state.pasteIncoming = true;
input.fastPoll();
});
function prepareCopyCut(e) {
if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) {
lastCopied = cm.getSelections();
if (input.inaccurateSelection) {
......@@ -1286,7 +1271,7 @@
on(te, "copy", prepareCopyCut);
on(display.scroller, "paste", function(e) {
if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return;
if (eventInWidget(display, e)) return;
cm.state.pasteIncoming = true;
input.focus();
});
......@@ -1298,7 +1283,6 @@
on(te, "compositionstart", function() {
var start = cm.getCursor("from");
if (input.composing) input.composing.range.clear()
input.composing = {
start: start,
range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
......@@ -1420,7 +1404,7 @@
// in which case reading its value would be expensive.
if (this.contextMenuPending || !cm.state.focused ||
(hasSelection(input) && !prevInput && !this.composing) ||
cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
return false;
var text = input.value;
......@@ -1547,10 +1531,6 @@
}
},
readOnlyChanged: function(val) {
if (!val) this.reset();
},
setUneditable: nothing,
needsContentAttribute: false
......@@ -1569,11 +1549,10 @@
init: function(display) {
var input = this, cm = input.cm;
var div = input.div = display.lineDiv;
div.contentEditable = "true";
disableBrowserMagic(div);
on(div, "paste", function(e) {
if (!signalDOMEvent(cm, e)) handlePaste(e, cm);
})
on(div, "paste", function(e) { handlePaste(e, cm); })
on(div, "compositionstart", function(e) {
var data = e.data;
......@@ -1611,12 +1590,11 @@
on(div, "input", function() {
if (input.composing) return;
if (cm.isReadOnly() || !input.pollContent())
if (!input.pollContent())
runInOp(input.cm, function() {regChange(cm);});
});
function onCopyCut(e) {
if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) {
lastCopied = cm.getSelections();
if (e.type == "cut") cm.replaceSelection("", null, "cut");
......@@ -1692,13 +1670,8 @@
try { var rng = range(start.node, start.offset, end.offset, end.node); }
catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
if (rng) {
if (!gecko && this.cm.state.focused) {
sel.collapse(start.node, start.offset);
if (!rng.collapsed) sel.addRange(rng);
} else {
sel.removeAllRanges();
sel.addRange(rng);
}
if (old && sel.anchorNode == null) sel.addRange(old);
else if (gecko) this.startGracePeriod();
}
......@@ -1842,26 +1815,19 @@
this.div.focus();
},
applyComposition: function(composing) {
if (this.cm.isReadOnly())
operation(this.cm, regChange)(this.cm)
else if (composing.data && composing.data != composing.startData)
if (composing.data && composing.data != composing.startData)
operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
},
setUneditable: function(node) {
node.contentEditable = "false"
node.setAttribute("contenteditable", "false");
},
onKeyPress: function(e) {
e.preventDefault();
if (!this.cm.isReadOnly())
operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
},
readOnlyChanged: function(val) {
this.div.contentEditable = String(val != "nocursor")
},
onContextMenu: nothing,
resetPosition: nothing,
......@@ -2159,7 +2125,7 @@
// Give beforeSelectionChange handlers a change to influence a
// selection update.
function filterSelectionChange(doc, sel, options) {
function filterSelectionChange(doc, sel) {
var obj = {
ranges: sel.ranges,
update: function(ranges) {
......@@ -2167,8 +2133,7 @@
for (var i = 0; i < ranges.length; i++)
this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
clipPos(doc, ranges[i].head));
},
origin: options && options.origin
}
};
signal(doc, "beforeSelectionChange", doc, obj);
if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
......@@ -2194,7 +2159,7 @@
function setSelectionNoUndo(doc, sel, options) {
if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
sel = filterSelectionChange(doc, sel, options);
sel = filterSelectionChange(doc, sel);
var bias = options && options.bias ||
(cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
......@@ -2228,9 +2193,8 @@
var out;
for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[i];
var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
var newHead = skipAtomic(doc, range.head, bias, mayClear);
if (out || newAnchor != range.anchor || newHead != range.head) {
if (!out) out = sel.ranges.slice(0, i);
out[i] = new Range(newAnchor, newHead);
......@@ -2239,12 +2203,18 @@
return out ? normalizeSelection(out, sel.primIndex) : sel;
}
function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
var line = getLine(doc, pos.line);
if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
// Ensure a given position is not inside an atomic range.
function skipAtomic(doc, pos, bias, mayClear) {
var flipped = false, curPos = pos;
var dir = bias || 1;
doc.cantEdit = false;
search: for (;;) {
var line = getLine(doc, curPos.line);
if (line.markedSpans) {
for (var i = 0; i < line.markedSpans.length; ++i) {
var sp = line.markedSpans[i], m = sp.marker;
if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
(sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
(sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
if (mayClear) {
signal(m, "beforeCursorEnter");
if (m.explicitlyCleared) {
......@@ -2253,45 +2223,34 @@
}
}
if (!m.atomic) continue;
if (oldPos) {
var near = m.find(dir < 0 ? 1 : -1), diff;
if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, line);
if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
return skipAtomicInner(doc, near, pos, dir, mayClear);
var newPos = m.find(dir < 0 ? -1 : 1);
if (cmp(newPos, curPos) == 0) {
newPos.ch += dir;
if (newPos.ch < 0) {
if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
else newPos = null;
} else if (newPos.ch > line.text.length) {
if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
else newPos = null;
}
if (!newPos) {
if (flipped) {
// Driven in a corner -- no valid cursor position found at all
// -- try again *with* clearing, if we didn't already
if (!mayClear) return skipAtomic(doc, pos, bias, true);
// Otherwise, turn off editing until further notice, and return the start of the doc
doc.cantEdit = true;
return Pos(doc.first, 0);
}
var far = m.find(dir < 0 ? -1 : 1);
if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) far = movePos(doc, far, dir, line);
return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;
flipped = true; newPos = pos; dir = -dir;
}
}
return pos;
curPos = newPos;
continue search;
}
// Ensure a given position is not inside an atomic range.
function skipAtomic(doc, pos, oldPos, bias, mayClear) {
var dir = bias || 1;
var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
(!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
(!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
if (!found) {
doc.cantEdit = true;
return Pos(doc.first, 0);
}
return found;
}
function movePos(doc, pos, dir, line) {
if (dir < 0 && pos.ch == 0) {
if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1));
else return null;
} else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0);
else return null;
} else {
return new Pos(pos.line, pos.ch + dir);
return curPos;
}
}
......@@ -2311,7 +2270,7 @@
var range = doc.sel.ranges[i];
var collapsed = range.empty();
if (collapsed || cm.options.showCursorWhenSelecting)
drawSelectionCursor(cm, range.head, curFragment);
drawSelectionCursor(cm, range, curFragment);
if (!collapsed)
drawSelectionRange(cm, range, selFragment);
}
......@@ -2319,8 +2278,8 @@
}
// Draws a cursor for the given range
function drawSelectionCursor(cm, head, output) {
var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
function drawSelectionCursor(cm, range, output) {
var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
cursor.style.left = pos.left + "px";
......@@ -2444,8 +2403,8 @@
doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
if (doc.frontier >= cm.display.viewFrom) { // Visible
var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength;
var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true);
var oldStyles = line.styles;
var highlighted = highlightLine(cm, line, state, true);
line.styles = highlighted.styles;
var oldCls = line.styleClasses, newCls = highlighted.classes;
if (newCls) line.styleClasses = newCls;
......@@ -2454,9 +2413,8 @@
oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
if (ischange) changedLines.push(doc.frontier);
line.stateAfter = tooLong ? state : copyState(doc.mode, state);
line.stateAfter = copyState(doc.mode, state);
} else {
if (line.text.length <= cm.options.maxHighlightLength)
processLine(cm, line.text, state);
line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
}
......@@ -3020,12 +2978,12 @@
var callbacks = group.delayedCallbacks, i = 0;
do {
for (; i < callbacks.length; i++)
callbacks[i].call(null);
callbacks[i]();
for (var j = 0; j < group.ops.length; j++) {
var op = group.ops[j];
if (op.cursorActivityHandlers)
while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm);
op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);
}
} while (i < callbacks.length);
}
......@@ -3119,8 +3077,7 @@
if (cm.state.focused && op.updateInput)
cm.display.input.reset(op.typing);
if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()))
ensureFocus(op.cm);
if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
}
function endOperation_finish(op) {
......@@ -3435,7 +3392,7 @@
return dx * dx + dy * dy > 20 * 20;
}
on(d.scroller, "touchstart", function(e) {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
if (!isMouseLikeTouchEvent(e)) {
clearTimeout(touchFinished);
var now = +new Date;
d.activeTouch = {start: now, moved: false,
......@@ -3486,11 +3443,9 @@
on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
d.dragFunctions = {
enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
start: function(e){onDragStart(cm, e);},
drop: operation(cm, onDrop),
leave: function() {clearDragCursor(cm);}
drop: operation(cm, onDrop)
};
var inp = d.input.getField();
......@@ -3507,9 +3462,8 @@
var funcs = cm.display.dragFunctions;
var toggle = value ? on : off;
toggle(cm.display.scroller, "dragstart", funcs.start);
toggle(cm.display.scroller, "dragenter", funcs.enter);
toggle(cm.display.scroller, "dragover", funcs.over);
toggle(cm.display.scroller, "dragleave", funcs.leave);
toggle(cm.display.scroller, "dragenter", funcs.simple);
toggle(cm.display.scroller, "dragover", funcs.simple);
toggle(cm.display.scroller, "drop", funcs.drop);
}
}
......@@ -3564,7 +3518,7 @@
// not interfere with, such as a scrollbar or widget.
function onMouseDown(e) {
var cm = this, display = cm.display;
if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return;
if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
display.shift = e.shiftKey;
if (eventInWidget(display, e)) {
......@@ -3582,10 +3536,7 @@
switch (e_button(e)) {
case 1:
// #3261: make sure, that we're not starting a second selection
if (cm.state.selectingText)
cm.state.selectingText(e);
else if (start)
if (start)
leftButtonDown(cm, e, start);
else if (e_target(e) == display.scroller)
e_preventDefault(e);
......@@ -3620,7 +3571,7 @@
}
var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
type == "single" && (contained = sel.contains(start)) > -1 &&
(cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
(cmp(contained.to(), start) > 0 || start.xRel < 0))
......@@ -3705,8 +3656,7 @@
setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
{scroll: false, origin: "*mouse"});
} else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
{scroll: false, origin: "*mouse"});
setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
startSel = doc.sel;
} else {
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
......@@ -3784,7 +3734,6 @@
}
function done(e) {
cm.state.selectingText = false;
counter = Infinity;
e_preventDefault(e);
display.input.focus();
......@@ -3798,14 +3747,13 @@
else extend(e);
});
var up = operation(cm, done);
cm.state.selectingText = up;
on(document, "mousemove", move);
on(document, "mouseup", up);
}
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
function gutterEvent(cm, e, type, prevent) {
function gutterEvent(cm, e, type, prevent, signalfn) {
try { var mX = e.clientX, mY = e.clientY; }
catch(e) { return false; }
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
......@@ -3822,14 +3770,14 @@
if (g && g.getBoundingClientRect().right >= mX) {
var line = lineAtHeight(cm.doc, mY);
var gutter = cm.options.gutters[i];
signal(cm, type, cm, line, gutter, e);
signalfn(cm, type, cm, line, gutter, e);
return e_defaultPrevented(e);
}
}
}
function clickInGutter(cm, e) {
return gutterEvent(cm, e, "gutterClick", true);
return gutterEvent(cm, e, "gutterClick", true, signalLater);
}
// Kludge to work around strange IE behavior where it'll sometimes
......@@ -3838,27 +3786,20 @@
function onDrop(e) {
var cm = this;
clearDragCursor(cm);
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
return;
e_preventDefault(e);
if (ie) lastDrop = +new Date;
var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
if (!pos || cm.isReadOnly()) return;
if (!pos || isReadOnly(cm)) return;
// Might be a file drop, in which case we simply extract the text
// and insert it.
if (files && files.length && window.FileReader && window.File) {
var n = files.length, text = Array(n), read = 0;
var loadFile = function(file, i) {
if (cm.options.allowDropFileTypes &&
indexOf(cm.options.allowDropFileTypes, file.type) == -1)
return;
var reader = new FileReader;
reader.onload = operation(cm, function() {
var content = reader.result;
if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
text[i] = content;
text[i] = reader.result;
if (++read == n) {
pos = clipPos(cm.doc, pos);
var change = {from: pos, to: pos,
......@@ -3917,25 +3858,6 @@
}
}
function onDragOver(cm, e) {
var pos = posFromMouse(cm, e);
if (!pos) return;
var frag = document.createDocumentFragment();
drawSelectionCursor(cm, pos, frag);
if (!cm.display.dragCursor) {
cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
}
removeChildrenAndAdd(cm.display.dragCursor, frag);
}
function clearDragCursor(cm) {
if (cm.display.dragCursor) {
cm.display.lineSpace.removeChild(cm.display.dragCursor);
cm.display.dragCursor = null;
}
}
// SCROLL EVENTS
// Sync the scrollable area and scrollbars, ensure the viewport
......@@ -4000,9 +3922,8 @@
var display = cm.display, scroll = display.scroller;
// Quit if there's nothing to scroll here
var canScrollX = scroll.scrollWidth > scroll.clientWidth;
var canScrollY = scroll.scrollHeight > scroll.clientHeight;
if (!(dx && canScrollX || dy && canScrollY)) return;
if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
dy && scroll.scrollHeight > scroll.clientHeight)) return;
// Webkit browsers on OS X abort momentum scrolls when the target
// of the scroll event is removed from the scrollable element.
......@@ -4026,14 +3947,9 @@
// scrolling entirely here. It'll be slightly off from native, but
// better than glitching out.
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
if (dy && canScrollY)
if (dy)
setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
// Only prevent default scrolling if vertical scrolling is
// actually possible. Otherwise, it causes vertical scroll
// jitter on OSX trackpads when deltaX is small and deltaY
// is large (issue #3579)
if (!dy || (dy && canScrollY))
e_preventDefault(e);
display.wheelStartX = null; // Abort measurement, if in progress
return;
......@@ -4083,7 +3999,7 @@
cm.display.input.ensurePolled();
var prevShift = cm.display.shift, done = false;
try {
if (cm.isReadOnly()) cm.state.suppressEdits = true;
if (isReadOnly(cm)) cm.state.suppressEdits = true;
if (dropShift) cm.display.shift = false;
done = bound(cm) != Pass;
} finally {
......@@ -4262,13 +4178,12 @@
// right-click take effect on it.
function onContextMenu(cm, e) {
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
if (signalDOMEvent(cm, e, "contextmenu")) return;
cm.display.input.onContextMenu(e);
}
function contextMenuInGutter(cm, e) {
if (!hasHandler(cm, "gutterContextMenu")) return false;
return gutterEvent(cm, e, "gutterContextMenu", false);
return gutterEvent(cm, e, "gutterContextMenu", false, signal);
}
// UPDATING
......@@ -4816,9 +4731,10 @@
function findPosH(doc, pos, dir, unit, visually) {
var line = pos.line, ch = pos.ch, origDir = dir;
var lineObj = getLine(doc, line);
var possible = true;
function findNextLine() {
var l = line + dir;
if (l < doc.first || l >= doc.first + doc.size) return false
if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
line = l;
return lineObj = getLine(doc, l);
}
......@@ -4828,16 +4744,14 @@
if (!boundToLine && findNextLine()) {
if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
else ch = dir < 0 ? lineObj.text.length : 0;
} else return false
} else return (possible = false);
} else ch = next;
return true;
}
if (unit == "char") {
moveOnce()
} else if (unit == "column") {
moveOnce(true)
} else if (unit == "word" || unit == "group") {
if (unit == "char") moveOnce();
else if (unit == "column") moveOnce(true);
else if (unit == "word" || unit == "group") {
var sawType = null, group = unit == "group";
var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
for (var first = true;; first = false) {
......@@ -4857,8 +4771,8 @@
if (dir > 0 && !moveOnce(!first)) break;
}
}
var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true);
if (!cmp(pos, result)) result.hitSide = true;
var result = skipAtomic(doc, Pos(line, ch), origDir, true);
if (!possible) result.hitSide = true;
return result;
}
......@@ -5150,7 +5064,7 @@
execCommand: function(cmd) {
if (commands.hasOwnProperty(cmd))
return commands[cmd].call(null, this);
return commands[cmd](this);
},
triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
......@@ -5245,7 +5159,6 @@
signal(this, "overwriteToggle", this, this.state.overwrite);
},
hasFocus: function() { return this.display.input.getField() == activeElt(); },
isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); },
scrollTo: methodOp(function(x, y) {
if (x != null || y != null) resolveScrollToPos(this);
......@@ -5443,12 +5356,11 @@
cm.display.disabled = true;
} else {
cm.display.disabled = false;
if (!val) cm.display.input.reset();
}
cm.display.input.readOnlyChanged(val)
});
option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
option("dragDrop", true, dragDropChanged);
option("allowDropFileTypes", null);
option("cursorBlinkRate", 530);
option("cursorScrollMargin", 0);
......@@ -5753,8 +5665,8 @@
var range = cm.listSelections()[i];
cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
cm.indentLine(range.from().line + 1, null, true);
}
ensureCursorVisible(cm);
}
});
},
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
......@@ -6682,7 +6594,7 @@
parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
}
return widget.height = widget.node.parentNode.offsetHeight;
return widget.height = widget.node.offsetHeight;
}
function addLineWidget(doc, handle, node, options) {
......@@ -6871,9 +6783,7 @@
function getLineStyles(cm, line, updateFrontier) {
if (!line.styles || line.styles[0] != cm.state.modeGen) {
var state = getStateBefore(cm, lineNo(line));
var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state);
line.stateAfter = state;
var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
line.styles = result.styles;
if (result.classes) line.styleClasses = result.classes;
else if (line.styleClasses) line.styleClasses = null;
......@@ -6890,7 +6800,7 @@
var stream = new StringStream(text, cm.options.tabSize);
stream.start = stream.pos = startAt || 0;
if (text == "") callBlankLine(mode, state);
while (!stream.eol()) {
while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
readToken(mode, stream, state);
stream.start = stream.pos;
}
......@@ -7008,7 +6918,7 @@
txt.setAttribute("cm-text", "\t");
builder.col += tabWidth;
} else if (m[0] == "\r" || m[0] == "\n") {
var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
var txt = content.appendChild(elt("span", m[0] == "\r" ? "" : "", "cm-invalidchar"));
txt.setAttribute("cm-text", m[0]);
builder.col += 1;
} else {
......@@ -7092,7 +7002,7 @@
if (nextChange == pos) { // Update current marker set
spanStyle = spanEndStyle = spanStartStyle = title = css = "";
collapsed = null; nextChange = Infinity;
var foundBookmarks = [], endStyles
var foundBookmarks = [];
for (var j = 0; j < spans.length; ++j) {
var sp = spans[j], m = sp.marker;
if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
......@@ -7103,9 +7013,9 @@
spanEndStyle = "";
}
if (m.className) spanStyle += " " + m.className;
if (m.css) css = (css ? css + ";" : "") + m.css;
if (m.css) css = m.css;
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to)
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
if (m.title && !title) title = m.title;
if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
collapsed = sp;
......@@ -7113,17 +7023,14 @@
nextChange = sp.from;
}
}
if (endStyles) for (var j = 0; j < endStyles.length; j += 2)
if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j]
if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j)
buildCollapsedSpan(builder, 0, foundBookmarks[j]);
if (collapsed && (collapsed.from || 0) == pos) {
buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
collapsed.marker, collapsed.from == null);
if (collapsed.to == null) return;
if (collapsed.to == pos) collapsed = false;
}
if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
buildCollapsedSpan(builder, 0, foundBookmarks[j]);
}
if (pos >= len) break;
......@@ -7375,7 +7282,6 @@
this.id = ++nextDocId;
this.modeOption = mode;
this.lineSep = lineSep;
this.extend = false;
if (typeof text == "string") text = this.splitLines(text);
updateDoc(this, {from: start, to: start, text: text});
......@@ -7463,11 +7369,10 @@
extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
}),
extendSelections: docMethodOp(function(heads, options) {
extendSelections(this, clipPosArray(this, heads), options);
extendSelections(this, clipPosArray(this, heads, options));
}),
extendSelectionsBy: docMethodOp(function(f, options) {
var heads = map(this.sel.ranges, f);
extendSelections(this, clipPosArray(this, heads), options);
extendSelections(this, map(this.sel.ranges, f), options);
}),
setSelections: docMethodOp(function(ranges, primary, options) {
if (!ranges.length) return;
......@@ -7592,7 +7497,7 @@
removeLineWidget: function(widget) { widget.clear(); },
markText: function(from, to, options) {
return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range");
return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
},
setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
......@@ -8153,30 +8058,24 @@
}
};
var noHandlers = []
function getHandlers(emitter, type, copy) {
var arr = emitter._handlers && emitter._handlers[type]
if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
else return arr || noHandlers
}
var off = CodeMirror.off = function(emitter, type, f) {
if (emitter.removeEventListener)
emitter.removeEventListener(type, f, false);
else if (emitter.detachEvent)
emitter.detachEvent("on" + type, f);
else {
var handlers = getHandlers(emitter, type, false)
for (var i = 0; i < handlers.length; ++i)
if (handlers[i] == f) { handlers.splice(i, 1); break; }
var arr = emitter._handlers && emitter._handlers[type];
if (!arr) return;
for (var i = 0; i < arr.length; ++i)
if (arr[i] == f) { arr.splice(i, 1); break; }
}
};
var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
var handlers = getHandlers(emitter, type, true)
if (!handlers.length) return;
var arr = emitter._handlers && emitter._handlers[type];
if (!arr) return;
var args = Array.prototype.slice.call(arguments, 2);
for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
};
var orphanDelayedCallbacks = null;
......@@ -8189,8 +8088,8 @@
// them to be executed when the last operation ends, or, if no
// operation is active, when a timeout fires.
function signalLater(emitter, type /*, values...*/) {
var arr = getHandlers(emitter, type, false)
if (!arr.length) return;
var arr = emitter._handlers && emitter._handlers[type];
if (!arr) return;
var args = Array.prototype.slice.call(arguments, 2), list;
if (operationGroup) {
list = operationGroup.delayedCallbacks;
......@@ -8230,7 +8129,8 @@
}
function hasHandler(emitter, type) {
return getHandlers(emitter, type).length > 0
var arr = emitter._handlers && emitter._handlers[type];
return arr && arr.length > 0;
}
// Add on and off methods to a constructor's prototype, to make
......@@ -8277,7 +8177,7 @@
// The inverse of countColumn -- find the offset that corresponds to
// a particular column.
var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) {
function findColumn(string, goal, tabSize) {
for (var pos = 0, col = 0;;) {
var nextTab = string.indexOf("\t", pos);
if (nextTab == -1) nextTab = string.length;
......@@ -8570,16 +8470,14 @@
// KEY NAMES
var keyNames = CodeMirror.keyNames = {
3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
};
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
CodeMirror.keyNames = keyNames;
(function() {
// Number keys
for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
......@@ -8884,7 +8782,7 @@
// THE END
CodeMirror.version = "5.11.0";
CodeMirror.version = "5.5.0";
return CodeMirror;
});
......@@ -51,7 +51,7 @@
Annotation.prototype.computeScale = function() {
var cm = this.cm;
var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
cm.getScrollerElement().scrollHeight
cm.heightAtLine(cm.lastLine() + 1, "local");
if (hScale != this.hScale) {
this.hScale = hScale;
return true;
......@@ -100,9 +100,6 @@
elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
+ (top + this.buttonHeight) + "px; height: " + height + "px";
elt.className = this.options.className;
if (ann.id) {
elt.setAttribute("annotation-id", ann.id);
}
}
this.div.textContent = "";
this.div.appendChild(frag);
......
......@@ -29,7 +29,7 @@
query.lastIndex = stream.pos;
var match = query.exec(stream.string);
if (match && match.index == stream.pos) {
stream.pos += match[0].length || 1;
stream.pos += match[0].length;
return "searching";
} else if (match) {
stream.pos = match.index;
......@@ -76,21 +76,11 @@
else if (confirm(shortText)) fs[0]();
}
function parseString(string) {
return string.replace(/\\(.)/g, function(_, ch) {
if (ch == "n") return "\n"
if (ch == "r") return "\r"
return ch
})
}
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
if (isRE) {
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
catch(e) {} // Not a regular expression after all, do a string search
} else {
query = parseString(query)
}
if (typeof query == "string" ? query == "" : query.test(""))
query = /x^/;
......@@ -117,19 +107,11 @@
if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery;
if (persistent && cm.openDialog) {
var hiding = null
persistentDialog(cm, queryDialog, q, function(query, event) {
CodeMirror.e_stop(event);
if (!query) return;
if (query != state.queryText) startSearch(cm, state, query);
if (hiding) hiding.style.opacity = 1
findNext(cm, event.shiftKey, function(_, to) {
var dialog
if (to.line < 3 && document.querySelector &&
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
(hiding = dialog).style.opacity = .4
})
findNext(cm, event.shiftKey);
});
} else {
dialog(cm, queryDialog, "Search for:", q, function(query) {
......@@ -142,7 +124,7 @@
}
}
function findNext(cm, rev, callback) {cm.operation(function() {
function findNext(cm, rev) {cm.operation(function() {
var state = getSearchState(cm);
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
if (!cursor.find(rev)) {
......@@ -152,7 +134,6 @@
cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
state.posFrom = cursor.from(); state.posTo = cursor.to();
if (callback) callback(cursor.from(), cursor.to())
});}
function clearSearch(cm) {cm.operation(function() {
......@@ -165,11 +146,18 @@
});}
var replaceQueryDialog =
' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
'Replace: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
function replaceAll(cm, query, text) {
function replace(cm, all) {
if (cm.getOption("readOnly")) return;
var query = cm.getSelection() || getSearchState(cm).lastQuery;
dialog(cm, replaceQueryDialog, "Replace:", query, function(query) {
if (!query) return;
query = parseQuery(query);
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
if (all) {
cm.operation(function() {
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
if (typeof query != "string") {
......@@ -178,19 +166,6 @@
} else cursor.replace(text);
}
});
}
function replace(cm, all) {
if (cm.getOption("readOnly")) return;
var query = cm.getSelection() || getSearchState(cm).lastQuery;
var dialogText = all ? "Replace all:" : "Replace:"
dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
if (!query) return;
query = parseQuery(query);
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
text = parseString(text)
if (all) {
replaceAll(cm, query, text)
} else {
clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor());
......@@ -204,8 +179,7 @@
cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
confirmDialog(cm, doReplaceConfirm, "Replace?",
[function() {doReplace(match);}, advance,
function() {replaceAll(cm, query, text)}]);
[function() {doReplace(match);}, advance]);
};
var doReplace = function(match) {
cursor.replace(typeof query == "string" ? text :
......
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("css", function(config, parserConfig) {
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
var indentUnit = config.indentUnit,
tokenHooks = parserConfig.tokenHooks,
documentTypes = parserConfig.documentTypes || {},
mediaTypes = parserConfig.mediaTypes || {},
mediaFeatures = parserConfig.mediaFeatures || {},
propertyKeywords = parserConfig.propertyKeywords || {},
nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
fontProperties = parserConfig.fontProperties || {},
counterDescriptors = parserConfig.counterDescriptors || {},
colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {},
allowNested = parserConfig.allowNested;
var type, override;
function ret(style, tp) { type = tp; return style; }
// Tokenizers
function tokenBase(stream, state) {
var ch = stream.next();
if (tokenHooks[ch]) {
var result = tokenHooks[ch](stream, state);
if (result !== false) return result;
}
if (ch == "@") {
stream.eatWhile(/[\w\\\-]/);
return ret("def", stream.current());
} else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
return ret(null, "compare");
} else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
} else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
} else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
} else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (ch === "-") {
if (/[\d.]/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^-[\w\\\-]+/)) {
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ret("variable-2", "variable-definition");
return ret("variable-2", "variable");
} else if (stream.match(/^\w+-/)) {
return ret("meta", "meta");
}
} else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
} else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", "qualifier");
} else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
} else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
(ch == "d" && stream.match("omain(")) ||
(ch == "r" && stream.match("egexp("))) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
return ret("property", "word");
} else if (/[\w\\\-]/.test(ch)) {
stream.eatWhile(/[\w\\\-]/);
return ret("property", "word");
} else {
return ret(null, null);
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped) {
if (quote == ")") stream.backUp(1);
break;
}
escaped = !escaped && ch == "\\";
}
if (ch == quote || !escaped && quote != ")") state.tokenize = null;
return ret("string", "string");
};
}
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
if (!stream.match(/\s*[\"\')]/, false))
state.tokenize = tokenString(")");
else
state.tokenize = null;
return ret(null, "(");
}
// Context management
function Context(type, indent, prev) {
this.type = type;
this.indent = indent;
this.prev = prev;
}
function pushContext(state, stream, type) {
state.context = new Context(type, stream.indentation() + indentUnit, state.context);
return type;
}
function popContext(state) {
state.context = state.context.prev;
return state.context.type;
}
function pass(type, stream, state) {
return states[state.context.type](type, stream, state);
}
function popAndPass(type, stream, state, n) {
for (var i = n || 1; i > 0; i--)
state.context = state.context.prev;
return pass(type, stream, state);
}
// Parser
function wordAsValue(stream) {
var word = stream.current().toLowerCase();
if (valueKeywords.hasOwnProperty(word))
override = "atom";
else if (colorKeywords.hasOwnProperty(word))
override = "keyword";
else
override = "variable";
}
var states = {};
states.top = function(type, stream, state) {
if (type == "{") {
return pushContext(state, stream, "block");
} else if (type == "}" && state.context.prev) {
return popContext(state);
} else if (/@(media|supports|(-moz-)?document)/.test(type)) {
return pushContext(state, stream, "atBlock");
} else if (/@(font-face|counter-style)/.test(type)) {
state.stateArg = type;
return "restricted_atBlock_before";
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
return "keyframes";
} else if (type && type.charAt(0) == "@") {
return pushContext(state, stream, "at");
} else if (type == "hash") {
override = "builtin";
} else if (type == "word") {
override = "tag";
} else if (type == "variable-definition") {
return "maybeprop";
} else if (type == "interpolation") {
return pushContext(state, stream, "interpolation");
} else if (type == ":") {
return "pseudo";
} else if (allowNested && type == "(") {
return pushContext(state, stream, "parens");
}
return state.context.type;
};
states.block = function(type, stream, state) {
if (type == "word") {
var word = stream.current().toLowerCase();
if (propertyKeywords.hasOwnProperty(word)) {
override = "property";
return "maybeprop";
} else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
override = "string-2";
return "maybeprop";
} else if (allowNested) {
override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
return "block";
} else {
override += " error";
return "maybeprop";
}
} else if (type == "meta") {
return "block";
} else if (!allowNested && (type == "hash" || type == "qualifier")) {
override = "error";
return "block";
} else {
return states.top(type, stream, state);
}
};
states.maybeprop = function(type, stream, state) {
if (type == ":") return pushContext(state, stream, "prop");
return pass(type, stream, state);
};
states.prop = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
if (type == "}" || type == "{") return popAndPass(type, stream, state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
override += " error";
} else if (type == "word") {
wordAsValue(stream);
} else if (type == "interpolation") {
return pushContext(state, stream, "interpolation");
}
return "prop";
};
states.propBlock = function(type, _stream, state) {
if (type == "}") return popContext(state);
if (type == "word") { override = "property"; return "maybeprop"; }
return state.context.type;
};
states.parens = function(type, stream, state) {
if (type == "{" || type == "}") return popAndPass(type, stream, state);
if (type == ")") return popContext(state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "interpolation") return pushContext(state, stream, "interpolation");
if (type == "word") wordAsValue(stream);
return "parens";
};
states.pseudo = function(type, stream, state) {
if (type == "word") {
override = "variable-3";
return state.context.type;
}
return pass(type, stream, state);
};
states.atBlock = function(type, stream, state) {
if (type == "(") return pushContext(state, stream, "atBlock_parens");
if (type == "}") return popAndPass(type, stream, state);
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
if (type == "word") {
var word = stream.current().toLowerCase();
if (word == "only" || word == "not" || word == "and" || word == "or")
override = "keyword";
else if (documentTypes.hasOwnProperty(word))
override = "tag";
else if (mediaTypes.hasOwnProperty(word))
override = "attribute";
else if (mediaFeatures.hasOwnProperty(word))
override = "property";
else if (propertyKeywords.hasOwnProperty(word))
override = "property";
else if (nonStandardPropertyKeywords.hasOwnProperty(word))
override = "string-2";
else if (valueKeywords.hasOwnProperty(word))
override = "atom";
else if (colorKeywords.hasOwnProperty(word))
override = "keyword";
else
override = "error";
}
return state.context.type;
};
states.atBlock_parens = function(type, stream, state) {
if (type == ")") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
return states.atBlock(type, stream, state);
};
states.restricted_atBlock_before = function(type, stream, state) {
if (type == "{")
return pushContext(state, stream, "restricted_atBlock");
if (type == "word" && state.stateArg == "@counter-style") {
override = "variable";
return "restricted_atBlock_before";
}
return pass(type, stream, state);
};
states.restricted_atBlock = function(type, stream, state) {
if (type == "}") {
state.stateArg = null;
return popContext(state);
}
if (type == "word") {
if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
(state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
override = "error";
else
override = "property";
return "maybeprop";
}
return "restricted_atBlock";
};
states.keyframes = function(type, stream, state) {
if (type == "word") { override = "variable"; return "keyframes"; }
if (type == "{") return pushContext(state, stream, "top");
return pass(type, stream, state);
};
states.at = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state);
if (type == "word") override = "tag";
else if (type == "hash") override = "builtin";
return "at";
};
states.interpolation = function(type, stream, state) {
if (type == "}") return popContext(state);
if (type == "{" || type == ";") return popAndPass(type, stream, state);
if (type == "word") override = "variable";
else if (type != "variable" && type != "(" && type != ")") override = "error";
return "interpolation";
};
return {
startState: function(base) {
return {tokenize: null,
state: "top",
stateArg: null,
context: new Context("top", base || 0, null)};
},
token: function(stream, state) {
if (!state.tokenize && stream.eatSpace()) return null;
var style = (state.tokenize || tokenBase)(stream, state);
if (style && typeof style == "object") {
type = style[1];
style = style[0];
}
override = style;
state.state = states[state.state](type, stream, state);
return override;
},
indent: function(state, textAfter) {
var cx = state.context, ch = textAfter && textAfter.charAt(0);
var indent = cx.indent;
if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
if (cx.prev &&
(ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "restricted_atBlock") ||
ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
ch == "{" && (cx.type == "at" || cx.type == "atBlock"))) {
indent = cx.indent - indentUnit;
cx = cx.prev;
}
return indent;
},
electricChars: "}",
blockCommentStart: "/*",
blockCommentEnd: "*/",
fold: "brace"
};
});
function keySet(array) {
var keys = {};
for (var i = 0; i < array.length; ++i) {
keys[array[i]] = true;
}
return keys;
}
var documentTypes_ = [
"domain", "regexp", "url", "url-prefix"
], documentTypes = keySet(documentTypes_);
var mediaTypes_ = [
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
], mediaTypes = keySet(mediaTypes_);
var mediaFeatures_ = [
"width", "min-width", "max-width", "height", "min-height", "max-height",
"device-width", "min-device-width", "max-device-width", "device-height",
"min-device-height", "max-device-height", "aspect-ratio",
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid"
], mediaFeatures = keySet(mediaFeatures_);
var propertyKeywords_ = [
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-fill-mode",
"animation-iteration-count", "animation-name", "animation-play-state",
"animation-timing-function", "appearance", "azimuth", "backface-visibility",
"background", "background-attachment", "background-clip", "background-color",
"background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
"bookmark-target", "border", "border-bottom", "border-bottom-color",
"border-bottom-left-radius", "border-bottom-right-radius",
"border-bottom-style", "border-bottom-width", "border-collapse",
"border-color", "border-image", "border-image-outset",
"border-image-repeat", "border-image-slice", "border-image-source",
"border-image-width", "border-left", "border-left-color",
"border-left-style", "border-left-width", "border-radius", "border-right",
"border-right-color", "border-right-style", "border-right-width",
"border-spacing", "border-style", "border-top", "border-top-color",
"border-top-left-radius", "border-top-right-radius", "border-top-style",
"border-top-width", "border-width", "bottom", "box-decoration-break",
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
"caption-side", "clear", "clip", "color", "color-profile", "column-count",
"column-fill", "column-gap", "column-rule", "column-rule-color",
"column-rule-style", "column-rule-width", "column-span", "column-width",
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
"cue-after", "cue-before", "cursor", "direction", "display",
"dominant-baseline", "drop-initial-after-adjust",
"drop-initial-after-align", "drop-initial-before-adjust",
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
"float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
"font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
"font-stretch", "font-style", "font-synthesis", "font-variant",
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
"font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
"grid-auto-position", "grid-auto-rows", "grid-column", "grid-column-end",
"grid-column-start", "grid-row", "grid-row-end", "grid-row-start",
"grid-template", "grid-template-areas", "grid-template-columns",
"grid-template-rows", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "left", "letter-spacing",
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
"line-stacking-shift", "line-stacking-strategy", "list-style",
"list-style-image", "list-style-position", "list-style-type", "margin",
"margin-bottom", "margin-left", "margin-right", "margin-top",
"marker-offset", "marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "object-fit", "object-position",
"opacity", "order", "orphans", "outline",
"outline-color", "outline-offset", "outline-style", "outline-width",
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
"page", "page-break-after", "page-break-before", "page-break-inside",
"page-policy", "pause", "pause-after", "pause-before", "perspective",
"perspective-origin", "pitch", "pitch-range", "play-during", "position",
"presentation-level", "punctuation-trim", "quotes", "region-break-after",
"region-break-before", "region-break-inside", "region-fragment",
"rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
"right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
"ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
"shape-outside", "size", "speak", "speak-as", "speak-header",
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
"tab-size", "table-layout", "target", "target-name", "target-new",
"target-position", "text-align", "text-align-last", "text-decoration",
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
"text-decoration-style", "text-emphasis", "text-emphasis-color",
"text-emphasis-position", "text-emphasis-style", "text-height",
"text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
"text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
"text-wrap", "top", "transform", "transform-origin", "transform-style",
"transition", "transition-delay", "transition-duration",
"transition-property", "transition-timing-function", "unicode-bidi",
"vertical-align", "visibility", "voice-balance", "voice-duration",
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
"voice-volume", "volume", "white-space", "widows", "width", "word-break",
"word-spacing", "word-wrap", "z-index",
// SVG-specific
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
"color-interpolation", "color-interpolation-filters",
"color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
"marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
"stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
"glyph-orientation-vertical", "text-anchor", "writing-mode"
], propertyKeywords = keySet(propertyKeywords_);
var nonStandardPropertyKeywords_ = [
"scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
"scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
"scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
"searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
"searchfield-results-decoration", "zoom"
], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
var fontProperties_ = [
"font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
"font-stretch", "font-weight", "font-style"
], fontProperties = keySet(fontProperties_);
var counterDescriptors_ = [
"additive-symbols", "fallback", "negative", "pad", "prefix", "range",
"speak-as", "suffix", "symbols", "system"
], counterDescriptors = keySet(counterDescriptors_);
var colorKeywords_ = [
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
"cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
"darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
"darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
"deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
"floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
"gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
"hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
"lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
"lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
"maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
"mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
"papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
"purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
"salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
"whitesmoke", "yellow", "yellowgreen"
], colorKeywords = keySet(colorKeywords_);
var valueKeywords_ = [
"above", "absolute", "activeborder", "additive", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
"arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page",
"avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
"bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
"both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
"cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
"col-resize", "collapse", "column", "compact", "condensed", "contain", "content",
"content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
"cross", "crosshair", "currentcolor", "cursive", "cyclic", "dashed", "decimal",
"decimal-leading-zero", "default", "default-button", "destination-atop",
"destination-in", "destination-out", "destination-over", "devanagari",
"disc", "discard", "disclosure-closed", "disclosure-open", "document",
"dot-dash", "dot-dot-dash",
"dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
"element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
"ethiopic-numeric", "ew-resize", "expanded", "extends", "extra-condensed",
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "footnotes",
"forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
"inline-block", "inline-flex", "inline-table", "inset", "inside", "intrinsic", "invert",
"italic", "japanese-formal", "japanese-informal", "justify", "kannada",
"katakana", "katakana-iroha", "keep-all", "khmer",
"korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
"landscape", "lao", "large", "larger", "left", "level", "lighter",
"line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
"lower-roman", "lowercase", "ltr", "malayalam", "match", "matrix", "matrix3d",
"media-controls-background", "media-current-time-display",
"media-fullscreen-button", "media-mute-button", "media-play-button",
"media-return-to-realtime-button", "media-rewind-button",
"media-seek-back-button", "media-seek-forward-button", "media-slider",
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
"menu", "menulist", "menulist-button", "menulist-text",
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
"mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
"ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
"outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
"painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
"pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
"progress", "push-button", "radial-gradient", "radio", "read-only",
"read-write", "read-write-plaintext-only", "rectangle", "region",
"relative", "repeat", "repeating-linear-gradient",
"repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
"rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
"rotateZ", "round", "row-resize", "rtl", "run-in", "running",
"s-resize", "sans-serif", "scale", "scale3d", "scaleX", "scaleY", "scaleZ",
"scroll", "scrollbar", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration",
"searchfield-results-button", "searchfield-results-decoration",
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
"simp-chinese-formal", "simp-chinese-informal", "single",
"skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
"small", "small-caps", "small-caption", "smaller", "solid", "somali",
"source-atop", "source-in", "source-out", "source-over", "space", "spell-out", "square",
"square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
"subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table",
"table-caption", "table-cell", "table-column", "table-column-group",
"table-footer-group", "table-header-group", "table-row", "table-row-group",
"tamil",
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
"trad-chinese-formal", "trad-chinese-informal",
"translate", "translate3d", "translateX", "translateY", "translateZ",
"transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
"var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
"window", "windowframe", "windowtext", "words", "x-large", "x-small", "xor",
"xx-large", "xx-small"
], valueKeywords = keySet(valueKeywords_);
var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(propertyKeywords_)
.concat(nonStandardPropertyKeywords_).concat(colorKeywords_).concat(valueKeywords_);
CodeMirror.registerHelper("hintWords", "css", allWords);
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
state.tokenize = null;
break;
}
maybeEnd = (ch == "*");
}
return ["comment", "comment"];
}
CodeMirror.defineMIME("text/css", {
documentTypes: documentTypes,
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
fontProperties: fontProperties,
counterDescriptors: counterDescriptors,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
tokenHooks: {
"/": function(stream, state) {
if (!stream.eat("*")) return false;
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
},
name: "css"
});
CodeMirror.defineMIME("text/x-scss", {
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
fontProperties: fontProperties,
allowNested: true,
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
":": function(stream) {
if (stream.match(/\s*\{/))
return [null, "{"];
return false;
},
"$": function(stream) {
stream.match(/^[\w-]+/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
return ["variable-2", "variable"];
},
"#": function(stream) {
if (!stream.eat("{")) return false;
return [null, "interpolation"];
}
},
name: "css",
helperType: "scss"
});
CodeMirror.defineMIME("text/x-less", {
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
fontProperties: fontProperties,
allowNested: true,
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
"@": function(stream) {
if (stream.eat("{")) return [null, "interpolation"];
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
return ["variable-2", "variable"];
},
"&": function() {
return ["atom", "atom"];
}
},
name: "css",
helperType: "less"
});
});
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
var htmlMode = CodeMirror.getMode(config, {name: "xml",
htmlMode: true,
multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag});
var cssMode = CodeMirror.getMode(config, "css");
var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
mode: CodeMirror.getMode(config, "javascript")});
if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
var conf = scriptTypesConf[i];
scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
}
scriptTypes.push({matches: /./,
mode: CodeMirror.getMode(config, "text/plain")});
function html(stream, state) {
var tagName = state.htmlState.tagName;
if (tagName) tagName = tagName.toLowerCase();
var style = htmlMode.token(stream, state.htmlState);
if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
// Script block: mode to change to depends on type attribute
var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
scriptType = scriptType ? scriptType[1] : "";
if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
for (var i = 0; i < scriptTypes.length; ++i) {
var tp = scriptTypes[i];
if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
if (tp.mode) {
state.token = script;
state.localMode = tp.mode;
state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
}
break;
}
}
} else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
state.token = css;
state.localMode = cssMode;
state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
}
return style;
}
function maybeBackup(stream, pat, style) {
var cur = stream.current();
var close = cur.search(pat);
if (close > -1) stream.backUp(cur.length - close);
else if (cur.match(/<\/?$/)) {
stream.backUp(cur.length);
if (!stream.match(pat, false)) stream.match(cur);
}
return style;
}
function script(stream, state) {
if (stream.match(/^<\/\s*script\s*>/i, false)) {
state.token = html;
state.localState = state.localMode = null;
return null;
}
return maybeBackup(stream, /<\/\s*script\s*>/,
state.localMode.token(stream, state.localState));
}
function css(stream, state) {
if (stream.match(/^<\/\s*style\s*>/i, false)) {
state.token = html;
state.localState = state.localMode = null;
return null;
}
return maybeBackup(stream, /<\/\s*style\s*>/,
cssMode.token(stream, state.localState));
}
return {
startState: function() {
var state = htmlMode.startState();
return {token: html, localMode: null, localState: null, htmlState: state};
},
copyState: function(state) {
if (state.localState)
var local = CodeMirror.copyState(state.localMode, state.localState);
return {token: state.token, localMode: state.localMode, localState: local,
htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
},
token: function(stream, state) {
return state.token(stream, state);
},
indent: function(state, textAfter) {
if (!state.localMode || /^\s*<\//.test(textAfter))
return htmlMode.indent(state.htmlState, textAfter);
else if (state.localMode.indent)
return state.localMode.indent(state.localState, textAfter);
else
return CodeMirror.Pass;
},
innerMode: function(state) {
return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
}
};
}, "xml", "javascript", "css");
CodeMirror.defineMIME("text/html", "htmlmixed");
});
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// TODO actually recognize syntax of TypeScript constructs
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("javascript", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var statementIndent = parserConfig.statementIndent;
var jsonldMode = parserConfig.jsonld;
var jsonMode = parserConfig.json || jsonldMode;
var isTS = parserConfig.typescript;
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
// Tokenizer
var keywords = function(){
function kw(type) {return {type: type, style: "keyword"};}
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
var jsKeywords = {
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
"var": kw("var"), "const": kw("var"), "let": kw("var"),
"function": kw("function"), "catch": kw("catch"),
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
"in": operator, "typeof": operator, "instanceof": operator,
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
"this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C
};
// Extend the 'normal' keywords with the TypeScript language extensions
if (isTS) {
var type = {type: "variable", style: "variable-3"};
var tsKeywords = {
// object-like things
"interface": kw("interface"),
"extends": kw("extends"),
"constructor": kw("constructor"),
// scope modifiers
"public": kw("public"),
"private": kw("private"),
"protected": kw("protected"),
"static": kw("static"),
// types
"string": type, "number": type, "bool": type, "any": type
};
for (var attr in tsKeywords) {
jsKeywords[attr] = tsKeywords[attr];
}
}
return jsKeywords;
}();
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
function readRegexp(stream) {
var escaped = false, next, inSet = false;
while ((next = stream.next()) != null) {
if (!escaped) {
if (next == "/" && !inSet) return;
if (next == "[") inSet = true;
else if (inSet && next == "]") inSet = false;
}
escaped = !escaped && next == "\\";
}
}
// Used as scratch variables to communicate multiple values without
// consing up tons of objects.
var type, content;
function ret(tp, style, cont) {
type = tp; content = cont;
return style;
}
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
return ret("number", "number");
} else if (ch == "." && stream.match("..")) {
return ret("spread", "meta");
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
return ret(ch);
} else if (ch == "=" && stream.eat(">")) {
return ret("=>", "operator");
} else if (ch == "0" && stream.eat(/x/i)) {
stream.eatWhile(/[\da-f]/i);
return ret("number", "number");
} else if (/\d/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
return ret("number", "number");
} else if (ch == "/") {
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
} else if (stream.eat("/")) {
stream.skipToEnd();
return ret("comment", "comment");
} else if (state.lastType == "operator" || state.lastType == "keyword c" ||
state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
readRegexp(stream);
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
return ret("regexp", "string-2");
} else {
stream.eatWhile(isOperatorChar);
return ret("operator", "operator", stream.current());
}
} else if (ch == "`") {
state.tokenize = tokenQuasi;
return tokenQuasi(stream, state);
} else if (ch == "#") {
stream.skipToEnd();
return ret("error", "error");
} else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return ret("operator", "operator", stream.current());
} else if (wordRE.test(ch)) {
stream.eatWhile(wordRE);
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
ret("variable", "variable", word);
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next;
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
state.tokenize = tokenBase;
return ret("jsonld-keyword", "meta");
}
while ((next = stream.next()) != null) {
if (next == quote && !escaped) break;
escaped = !escaped && next == "\\";
}
if (!escaped) state.tokenize = tokenBase;
return ret("string", "string");
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return ret("comment", "comment");
}
function tokenQuasi(stream, state) {
var escaped = false, next;
while ((next = stream.next()) != null) {
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
state.tokenize = tokenBase;
break;
}
escaped = !escaped && next == "\\";
}
return ret("quasi", "string-2", stream.current());
}
var brackets = "([{}])";
// This is a crude lookahead trick to try and notice that we're
// parsing the argument patterns for a fat-arrow function before we
// actually hit the arrow token. It only works if the arrow is on
// the same line as the arguments and there's no strange noise
// (comments) in between. Fallback is to only notice when we hit the
// arrow, and not declare the arguments as locals for the arrow
// body.
function findFatArrow(stream, state) {
if (state.fatArrowAt) state.fatArrowAt = null;
var arrow = stream.string.indexOf("=>", stream.start);
if (arrow < 0) return;
var depth = 0, sawSomething = false;
for (var pos = arrow - 1; pos >= 0; --pos) {
var ch = stream.string.charAt(pos);
var bracket = brackets.indexOf(ch);
if (bracket >= 0 && bracket < 3) {
if (!depth) { ++pos; break; }
if (--depth == 0) break;
} else if (bracket >= 3 && bracket < 6) {
++depth;
} else if (wordRE.test(ch)) {
sawSomething = true;
} else if (/["'\/]/.test(ch)) {
return;
} else if (sawSomething && !depth) {
++pos;
break;
}
}
if (sawSomething && !depth) state.fatArrowAt = pos;
}
// Parser
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
function JSLexical(indented, column, type, align, prev, info) {
this.indented = indented;
this.column = column;
this.type = type;
this.prev = prev;
this.info = info;
if (align != null) this.align = align;
}
function inScope(state, varname) {
for (var v = state.localVars; v; v = v.next)
if (v.name == varname) return true;
for (var cx = state.context; cx; cx = cx.prev) {
for (var v = cx.vars; v; v = v.next)
if (v.name == varname) return true;
}
}
function parseJS(state, style, type, content, stream) {
var cc = state.cc;
// Communicate our context to the combinators.
// (Less wasteful than consing up a hundred closures on every call.)
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = true;
while(true) {
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
if (combinator(type, content)) {
while(cc.length && cc[cc.length - 1].lex)
cc.pop()();
if (cx.marked) return cx.marked;
if (type == "variable" && inScope(state, content)) return "variable-2";
return style;
}
}
}
// Combinator utils
var cx = {state: null, column: null, marked: null, cc: null};
function pass() {
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
}
function cont() {
pass.apply(null, arguments);
return true;
}
function register(varname) {
function inList(list) {
for (var v = list; v; v = v.next)
if (v.name == varname) return true;
return false;
}
var state = cx.state;
if (state.context) {
cx.marked = "def";
if (inList(state.localVars)) return;
state.localVars = {name: varname, next: state.localVars};
} else {
if (inList(state.globalVars)) return;
if (parserConfig.globalVars)
state.globalVars = {name: varname, next: state.globalVars};
}
}
// Combinators
var defaultVars = {name: "this", next: {name: "arguments"}};
function pushcontext() {
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
cx.state.localVars = defaultVars;
}
function popcontext() {
cx.state.localVars = cx.state.context.vars;
cx.state.context = cx.state.context.prev;
}
function pushlex(type, info) {
var result = function() {
var state = cx.state, indent = state.indented;
if (state.lexical.type == "stat") indent = state.lexical.indented;
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
indent = outer.indented;
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
};
result.lex = true;
return result;
}
function poplex() {
var state = cx.state;
if (state.lexical.prev) {
if (state.lexical.type == ")")
state.indented = state.lexical.indented;
state.lexical = state.lexical.prev;
}
}
poplex.lex = true;
function expect(wanted) {
function exp(type) {
if (type == wanted) return cont();
else if (wanted == ";") return pass();
else return cont(exp);
};
return exp;
}
function statement(type, value) {
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
if (type == "{") return cont(pushlex("}"), block, poplex);
if (type == ";") return cont();
if (type == "if") {
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
cx.state.cc.pop()();
return cont(pushlex("form"), expression, statement, poplex, maybeelse);
}
if (type == "function") return cont(functiondef);
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
if (type == "variable") return cont(pushlex("stat"), maybelabel);
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
block, poplex, poplex);
if (type == "case") return cont(expression, expect(":"));
if (type == "default") return cont(expect(":"));
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
statement, poplex, popcontext);
if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
if (type == "class") return cont(pushlex("form"), className, poplex);
if (type == "export") return cont(pushlex("form"), afterExport, poplex);
if (type == "import") return cont(pushlex("form"), afterImport, poplex);
return pass(pushlex("stat"), expression, expect(";"), poplex);
}
function expression(type) {
return expressionInner(type, false);
}
function expressionNoComma(type) {
return expressionInner(type, true);
}
function expressionInner(type, noComma) {
if (cx.state.fatArrowAt == cx.stream.start) {
var body = noComma ? arrowBodyNoComma : arrowBody;
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
}
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
if (type == "function") return cont(functiondef, maybeop);
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
if (type == "quasi") { return pass(quasi, maybeop); }
return cont();
}
function maybeexpression(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expression);
}
function maybeexpressionNoComma(type) {
if (type.match(/[;\}\)\],]/)) return pass();
return pass(expressionNoComma);
}
function maybeoperatorComma(type, value) {
if (type == ",") return cont(expression);
return maybeoperatorNoComma(type, value, false);
}
function maybeoperatorNoComma(type, value, noComma) {
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
var expr = noComma == false ? expression : expressionNoComma;
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
if (type == "operator") {
if (/\+\+|--/.test(value)) return cont(me);
if (value == "?") return cont(expression, expect(":"), expr);
return cont(expr);
}
if (type == "quasi") { return pass(quasi, me); }
if (type == ";") return;
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
if (type == ".") return cont(property, me);
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
}
function quasi(type, value) {
if (type != "quasi") return pass();
if (value.slice(value.length - 2) != "${") return cont(quasi);
return cont(expression, continueQuasi);
}
function continueQuasi(type) {
if (type == "}") {
cx.marked = "string-2";
cx.state.tokenize = tokenQuasi;
return cont(quasi);
}
}
function arrowBody(type) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement : expression);
}
function arrowBodyNoComma(type) {
findFatArrow(cx.stream, cx.state);
return pass(type == "{" ? statement : expressionNoComma);
}
function maybelabel(type) {
if (type == ":") return cont(poplex, statement);
return pass(maybeoperatorComma, expect(";"), poplex);
}
function property(type) {
if (type == "variable") {cx.marked = "property"; return cont();}
}
function objprop(type, value) {
if (type == "variable" || cx.style == "keyword") {
cx.marked = "property";
if (value == "get" || value == "set") return cont(getterSetter);
return cont(afterprop);
} else if (type == "number" || type == "string") {
cx.marked = jsonldMode ? "property" : (cx.style + " property");
return cont(afterprop);
} else if (type == "jsonld-keyword") {
return cont(afterprop);
} else if (type == "[") {
return cont(expression, expect("]"), afterprop);
}
}
function getterSetter(type) {
if (type != "variable") return pass(afterprop);
cx.marked = "property";
return cont(functiondef);
}
function afterprop(type) {
if (type == ":") return cont(expressionNoComma);
if (type == "(") return pass(functiondef);
}
function commasep(what, end) {
function proceed(type) {
if (type == ",") {
var lex = cx.state.lexical;
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
return cont(what, proceed);
}
if (type == end) return cont();
return cont(expect(end));
}
return function(type) {
if (type == end) return cont();
return pass(what, proceed);
};
}
function contCommasep(what, end, info) {
for (var i = 3; i < arguments.length; i++)
cx.cc.push(arguments[i]);
return cont(pushlex(end, info), commasep(what, end), poplex);
}
function block(type) {
if (type == "}") return cont();
return pass(statement, block);
}
function maybetype(type) {
if (isTS && type == ":") return cont(typedef);
}
function maybedefault(_, value) {
if (value == "=") return cont(expressionNoComma);
}
function typedef(type) {
if (type == "variable") {cx.marked = "variable-3"; return cont();}
}
function vardef() {
return pass(pattern, maybetype, maybeAssign, vardefCont);
}
function pattern(type, value) {
if (type == "variable") { register(value); return cont(); }
if (type == "[") return contCommasep(pattern, "]");
if (type == "{") return contCommasep(proppattern, "}");
}
function proppattern(type, value) {
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
register(value);
return cont(maybeAssign);
}
if (type == "variable") cx.marked = "property";
return cont(expect(":"), pattern, maybeAssign);
}
function maybeAssign(_type, value) {
if (value == "=") return cont(expressionNoComma);
}
function vardefCont(type) {
if (type == ",") return cont(vardef);
}
function maybeelse(type, value) {
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
}
function forspec(type) {
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
}
function forspec1(type) {
if (type == "var") return cont(vardef, expect(";"), forspec2);
if (type == ";") return cont(forspec2);
if (type == "variable") return cont(formaybeinof);
return pass(expression, expect(";"), forspec2);
}
function formaybeinof(_type, value) {
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
return cont(maybeoperatorComma, forspec2);
}
function forspec2(type, value) {
if (type == ";") return cont(forspec3);
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
return pass(expression, expect(";"), forspec3);
}
function forspec3(type) {
if (type != ")") cont(expression);
}
function functiondef(type, value) {
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
if (type == "variable") {register(value); return cont(functiondef);}
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
}
function funarg(type) {
if (type == "spread") return cont(funarg);
return pass(pattern, maybetype, maybedefault);
}
function className(type, value) {
if (type == "variable") {register(value); return cont(classNameAfter);}
}
function classNameAfter(type, value) {
if (value == "extends") return cont(expression, classNameAfter);
if (type == "{") return cont(pushlex("}"), classBody, poplex);
}
function classBody(type, value) {
if (type == "variable" || cx.style == "keyword") {
if (value == "static") {
cx.marked = "keyword";
return cont(classBody);
}
cx.marked = "property";
if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
return cont(functiondef, classBody);
}
if (value == "*") {
cx.marked = "keyword";
return cont(classBody);
}
if (type == ";") return cont(classBody);
if (type == "}") return cont();
}
function classGetterSetter(type) {
if (type != "variable") return pass();
cx.marked = "property";
return cont();
}
function afterModule(type, value) {
if (type == "string") return cont(statement);
if (type == "variable") { register(value); return cont(maybeFrom); }
}
function afterExport(_type, value) {
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
return pass(statement);
}
function afterImport(type) {
if (type == "string") return cont();
return pass(importSpec, maybeFrom);
}
function importSpec(type, value) {
if (type == "{") return contCommasep(importSpec, "}");
if (type == "variable") register(value);
if (value == "*") cx.marked = "keyword";
return cont(maybeAs);
}
function maybeAs(_type, value) {
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
}
function maybeFrom(_type, value) {
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
}
function arrayLiteral(type) {
if (type == "]") return cont();
return pass(expressionNoComma, maybeArrayComprehension);
}
function maybeArrayComprehension(type) {
if (type == "for") return pass(comprehension, expect("]"));
if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
return pass(commasep(expressionNoComma, "]"));
}
function comprehension(type) {
if (type == "for") return cont(forspec, comprehension);
if (type == "if") return cont(expression, comprehension);
}
function isContinuedStatement(state, textAfter) {
return state.lastType == "operator" || state.lastType == "," ||
isOperatorChar.test(textAfter.charAt(0)) ||
/[,.]/.test(textAfter.charAt(0));
}
// Interface
return {
startState: function(basecolumn) {
var state = {
tokenize: tokenBase,
lastType: "sof",
cc: [],
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
localVars: parserConfig.localVars,
context: parserConfig.localVars && {vars: parserConfig.localVars},
indented: 0
};
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
state.globalVars = parserConfig.globalVars;
return state;
},
token: function(stream, state) {
if (stream.sol()) {
if (!state.lexical.hasOwnProperty("align"))
state.lexical.align = false;
state.indented = stream.indentation();
findFatArrow(stream, state);
}
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (type == "comment") return style;
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
return parseJS(state, style, type, content, stream);
},
indent: function(state, textAfter) {
if (state.tokenize == tokenComment) return CodeMirror.Pass;
if (state.tokenize != tokenBase) return 0;
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
// Kludge to prevent 'maybelse' from blocking lexical scope pops
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
var c = state.cc[i];
if (c == poplex) lexical = lexical.prev;
else if (c != maybeelse) break;
}
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
lexical = lexical.prev;
var type = lexical.type, closing = firstChar == type;
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
else if (type == "form" && firstChar == "{") return lexical.indented;
else if (type == "form") return lexical.indented + indentUnit;
else if (type == "stat")
return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
else return lexical.indented + (closing ? 0 : indentUnit);
},
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
blockCommentStart: jsonMode ? null : "/*",
blockCommentEnd: jsonMode ? null : "*/",
lineComment: jsonMode ? null : "//",
fold: "brace",
closeBrackets: "()[]{}''\"\"``",
helperType: jsonMode ? "json" : "javascript",
jsonldMode: jsonldMode,
jsonMode: jsonMode
};
});
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
CodeMirror.defineMIME("text/javascript", "javascript");
CodeMirror.defineMIME("text/ecmascript", "javascript");
CodeMirror.defineMIME("application/javascript", "javascript");
CodeMirror.defineMIME("application/x-javascript", "javascript");
CodeMirror.defineMIME("application/ecmascript", "javascript");
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
});
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
/*
For extra ASP classic objects, initialize CodeMirror instance with this option:
isASP: true
E.G.:
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
isASP: true
});
*/
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("vbscript", function(conf, parserConf) {
var ERRORCLASS = 'error';
function wordRegexp(words) {
return new RegExp("^((" + words.join(")|(") + "))\\b", "i");
}
var singleOperators = new RegExp("^[\\+\\-\\*/&\\\\\\^<>=]");
var doubleOperators = new RegExp("^((<>)|(<=)|(>=))");
var singleDelimiters = new RegExp('^[\\.,]');
var brakets = new RegExp('^[\\(\\)]');
var identifiers = new RegExp("^[A-Za-z][_A-Za-z0-9]*");
var openingKeywords = ['class','sub','select','while','if','function', 'property', 'with', 'for'];
var middleKeywords = ['else','elseif','case'];
var endKeywords = ['next','loop','wend'];
var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'is', 'mod', 'eqv', 'imp']);
var commonkeywords = ['dim', 'redim', 'then', 'until', 'randomize',
'byval','byref','new','property', 'exit', 'in',
'const','private', 'public',
'get','set','let', 'stop', 'on error resume next', 'on error goto 0', 'option explicit', 'call', 'me'];
//This list was from: http://msdn.microsoft.com/en-us/library/f8tbc79x(v=vs.84).aspx
var atomWords = ['true', 'false', 'nothing', 'empty', 'null'];
//This list was from: http://msdn.microsoft.com/en-us/library/3ca8tfek(v=vs.84).aspx
var builtinFuncsWords = ['abs', 'array', 'asc', 'atn', 'cbool', 'cbyte', 'ccur', 'cdate', 'cdbl', 'chr', 'cint', 'clng', 'cos', 'csng', 'cstr', 'date', 'dateadd', 'datediff', 'datepart',
'dateserial', 'datevalue', 'day', 'escape', 'eval', 'execute', 'exp', 'filter', 'formatcurrency', 'formatdatetime', 'formatnumber', 'formatpercent', 'getlocale', 'getobject',
'getref', 'hex', 'hour', 'inputbox', 'instr', 'instrrev', 'int', 'fix', 'isarray', 'isdate', 'isempty', 'isnull', 'isnumeric', 'isobject', 'join', 'lbound', 'lcase', 'left',
'len', 'loadpicture', 'log', 'ltrim', 'rtrim', 'trim', 'maths', 'mid', 'minute', 'month', 'monthname', 'msgbox', 'now', 'oct', 'replace', 'rgb', 'right', 'rnd', 'round',
'scriptengine', 'scriptenginebuildversion', 'scriptenginemajorversion', 'scriptengineminorversion', 'second', 'setlocale', 'sgn', 'sin', 'space', 'split', 'sqr', 'strcomp',
'string', 'strreverse', 'tan', 'time', 'timer', 'timeserial', 'timevalue', 'typename', 'ubound', 'ucase', 'unescape', 'vartype', 'weekday', 'weekdayname', 'year'];
//This list was from: http://msdn.microsoft.com/en-us/library/ydz4cfk3(v=vs.84).aspx
var builtinConsts = ['vbBlack', 'vbRed', 'vbGreen', 'vbYellow', 'vbBlue', 'vbMagenta', 'vbCyan', 'vbWhite', 'vbBinaryCompare', 'vbTextCompare',
'vbSunday', 'vbMonday', 'vbTuesday', 'vbWednesday', 'vbThursday', 'vbFriday', 'vbSaturday', 'vbUseSystemDayOfWeek', 'vbFirstJan1', 'vbFirstFourDays', 'vbFirstFullWeek',
'vbGeneralDate', 'vbLongDate', 'vbShortDate', 'vbLongTime', 'vbShortTime', 'vbObjectError',
'vbOKOnly', 'vbOKCancel', 'vbAbortRetryIgnore', 'vbYesNoCancel', 'vbYesNo', 'vbRetryCancel', 'vbCritical', 'vbQuestion', 'vbExclamation', 'vbInformation', 'vbDefaultButton1', 'vbDefaultButton2',
'vbDefaultButton3', 'vbDefaultButton4', 'vbApplicationModal', 'vbSystemModal', 'vbOK', 'vbCancel', 'vbAbort', 'vbRetry', 'vbIgnore', 'vbYes', 'vbNo',
'vbCr', 'VbCrLf', 'vbFormFeed', 'vbLf', 'vbNewLine', 'vbNullChar', 'vbNullString', 'vbTab', 'vbVerticalTab', 'vbUseDefault', 'vbTrue', 'vbFalse',
'vbEmpty', 'vbNull', 'vbInteger', 'vbLong', 'vbSingle', 'vbDouble', 'vbCurrency', 'vbDate', 'vbString', 'vbObject', 'vbError', 'vbBoolean', 'vbVariant', 'vbDataObject', 'vbDecimal', 'vbByte', 'vbArray'];
//This list was from: http://msdn.microsoft.com/en-us/library/hkc375ea(v=vs.84).aspx
var builtinObjsWords = ['WScript', 'err', 'debug', 'RegExp'];
var knownProperties = ['description', 'firstindex', 'global', 'helpcontext', 'helpfile', 'ignorecase', 'length', 'number', 'pattern', 'source', 'value', 'count'];
var knownMethods = ['clear', 'execute', 'raise', 'replace', 'test', 'write', 'writeline', 'close', 'open', 'state', 'eof', 'update', 'addnew', 'end', 'createobject', 'quit'];
var aspBuiltinObjsWords = ['server', 'response', 'request', 'session', 'application'];
var aspKnownProperties = ['buffer', 'cachecontrol', 'charset', 'contenttype', 'expires', 'expiresabsolute', 'isclientconnected', 'pics', 'status', //response
'clientcertificate', 'cookies', 'form', 'querystring', 'servervariables', 'totalbytes', //request
'contents', 'staticobjects', //application
'codepage', 'lcid', 'sessionid', 'timeout', //session
'scripttimeout']; //server
var aspKnownMethods = ['addheader', 'appendtolog', 'binarywrite', 'end', 'flush', 'redirect', //response
'binaryread', //request
'remove', 'removeall', 'lock', 'unlock', //application
'abandon', //session
'getlasterror', 'htmlencode', 'mappath', 'transfer', 'urlencode']; //server
var knownWords = knownMethods.concat(knownProperties);
builtinObjsWords = builtinObjsWords.concat(builtinConsts);
if (conf.isASP){
builtinObjsWords = builtinObjsWords.concat(aspBuiltinObjsWords);
knownWords = knownWords.concat(aspKnownMethods, aspKnownProperties);
};
var keywords = wordRegexp(commonkeywords);
var atoms = wordRegexp(atomWords);
var builtinFuncs = wordRegexp(builtinFuncsWords);
var builtinObjs = wordRegexp(builtinObjsWords);
var known = wordRegexp(knownWords);
var stringPrefixes = '"';
var opening = wordRegexp(openingKeywords);
var middle = wordRegexp(middleKeywords);
var closing = wordRegexp(endKeywords);
var doubleClosing = wordRegexp(['end']);
var doOpening = wordRegexp(['do']);
var noIndentWords = wordRegexp(['on error resume next', 'exit']);
var comment = wordRegexp(['rem']);
function indent(_stream, state) {
state.currentIndent++;
}
function dedent(_stream, state) {
state.currentIndent--;
}
// tokenizers
function tokenBase(stream, state) {
if (stream.eatSpace()) {
return 'space';
//return null;
}
var ch = stream.peek();
// Handle Comments
if (ch === "'") {
stream.skipToEnd();
return 'comment';
}
if (stream.match(comment)){
stream.skipToEnd();
return 'comment';
}
// Handle Number Literals
if (stream.match(/^((&H)|(&O))?[0-9\.]/i, false) && !stream.match(/^((&H)|(&O))?[0-9\.]+[a-z_]/i, false)) {
var floatLiteral = false;
// Floats
if (stream.match(/^\d*\.\d+/i)) { floatLiteral = true; }
else if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
else if (stream.match(/^\.\d+/)) { floatLiteral = true; }
if (floatLiteral) {
// Float literals may be "imaginary"
stream.eat(/J/i);
return 'number';
}
// Integers
var intLiteral = false;
// Hex
if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; }
// Octal
else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; }
// Decimal
else if (stream.match(/^[1-9]\d*F?/)) {
// Decimal literals may be "imaginary"
stream.eat(/J/i);
// TODO - Can you have imaginary longs?
intLiteral = true;
}
// Zero by itself with no other piece of number.
else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
if (intLiteral) {
// Integer literals may be "long"
stream.eat(/L/i);
return 'number';
}
}
// Handle Strings
if (stream.match(stringPrefixes)) {
state.tokenize = tokenStringFactory(stream.current());
return state.tokenize(stream, state);
}
// Handle operators and Delimiters
if (stream.match(doubleOperators)
|| stream.match(singleOperators)
|| stream.match(wordOperators)) {
return 'operator';
}
if (stream.match(singleDelimiters)) {
return null;
}
if (stream.match(brakets)) {
return "bracket";
}
if (stream.match(noIndentWords)) {
state.doInCurrentLine = true;
return 'keyword';
}
if (stream.match(doOpening)) {
indent(stream,state);
state.doInCurrentLine = true;
return 'keyword';
}
if (stream.match(opening)) {
if (! state.doInCurrentLine)
indent(stream,state);
else
state.doInCurrentLine = false;
return 'keyword';
}
if (stream.match(middle)) {
return 'keyword';
}
if (stream.match(doubleClosing)) {
dedent(stream,state);
dedent(stream,state);
return 'keyword';
}
if (stream.match(closing)) {
if (! state.doInCurrentLine)
dedent(stream,state);
else
state.doInCurrentLine = false;
return 'keyword';
}
if (stream.match(keywords)) {
return 'keyword';
}
if (stream.match(atoms)) {
return 'atom';
}
if (stream.match(known)) {
return 'variable-2';
}
if (stream.match(builtinFuncs)) {
return 'builtin';
}
if (stream.match(builtinObjs)){
return 'variable-2';
}
if (stream.match(identifiers)) {
return 'variable';
}
// Handle non-detected items
stream.next();
return ERRORCLASS;
}
function tokenStringFactory(delimiter) {
var singleline = delimiter.length == 1;
var OUTCLASS = 'string';
return function(stream, state) {
while (!stream.eol()) {
stream.eatWhile(/[^'"]/);
if (stream.match(delimiter)) {
state.tokenize = tokenBase;
return OUTCLASS;
} else {
stream.eat(/['"]/);
}
}
if (singleline) {
if (parserConf.singleLineStringErrors) {
return ERRORCLASS;
} else {
state.tokenize = tokenBase;
}
}
return OUTCLASS;
};
}
function tokenLexer(stream, state) {
var style = state.tokenize(stream, state);
var current = stream.current();
// Handle '.' connected identifiers
if (current === '.') {
style = state.tokenize(stream, state);
current = stream.current();
if (style && (style.substr(0, 8) === 'variable' || style==='builtin' || style==='keyword')){//|| knownWords.indexOf(current.substring(1)) > -1) {
if (style === 'builtin' || style === 'keyword') style='variable';
if (knownWords.indexOf(current.substr(1)) > -1) style='variable-2';
return style;
} else {
return ERRORCLASS;
}
}
return style;
}
var external = {
electricChars:"dDpPtTfFeE ",
startState: function() {
return {
tokenize: tokenBase,
lastToken: null,
currentIndent: 0,
nextLineIndent: 0,
doInCurrentLine: false,
ignoreKeyword: false
};
},
token: function(stream, state) {
if (stream.sol()) {
state.currentIndent += state.nextLineIndent;
state.nextLineIndent = 0;
state.doInCurrentLine = 0;
}
var style = tokenLexer(stream, state);
state.lastToken = {style:style, content: stream.current()};
if (style==='space') style=null;
return style;
},
indent: function(state, textAfter) {
var trueText = textAfter.replace(/^\s+|\s+$/g, '') ;
if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);
if(state.currentIndent < 0) return 0;
return state.currentIndent * conf.indentUnit;
}
};
return external;
});
CodeMirror.defineMIME("text/vbscript", "vbscript");
});
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("xml", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
var Kludges = parserConfig.htmlMode ? {
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
'track': true, 'wbr': true, 'menuitem': true},
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
'th': true, 'tr': true},
contextGrabbers: {
'dd': {'dd': true, 'dt': true},
'dt': {'dd': true, 'dt': true},
'li': {'li': true},
'option': {'option': true, 'optgroup': true},
'optgroup': {'optgroup': true},
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
'rp': {'rp': true, 'rt': true},
'rt': {'rp': true, 'rt': true},
'tbody': {'tbody': true, 'tfoot': true},
'td': {'td': true, 'th': true},
'tfoot': {'tbody': true},
'th': {'td': true, 'th': true},
'thead': {'tbody': true, 'tfoot': true},
'tr': {'tr': true}
},
doNotIndent: {"pre": true},
allowUnquoted: true,
allowMissing: true,
caseFold: true
} : {
autoSelfClosers: {},
implicitlyClosed: {},
contextGrabbers: {},
doNotIndent: {},
allowUnquoted: false,
allowMissing: false,
caseFold: false
};
var alignCDATA = parserConfig.alignCDATA;
// Return variables for tokenizers
var type, setStyle;
function inText(stream, state) {
function chain(parser) {
state.tokenize = parser;
return parser(stream, state);
}
var ch = stream.next();
if (ch == "<") {
if (stream.eat("!")) {
if (stream.eat("[")) {
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
else return null;
} else if (stream.match("--")) {
return chain(inBlock("comment", "-->"));
} else if (stream.match("DOCTYPE", true, true)) {
stream.eatWhile(/[\w\._\-]/);
return chain(doctype(1));
} else {
return null;
}
} else if (stream.eat("?")) {
stream.eatWhile(/[\w\._\-]/);
state.tokenize = inBlock("meta", "?>");
return "meta";
} else {
type = stream.eat("/") ? "closeTag" : "openTag";
state.tokenize = inTag;
return "tag bracket";
}
} else if (ch == "&") {
var ok;
if (stream.eat("#")) {
if (stream.eat("x")) {
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
} else {
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
}
} else {
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
}
return ok ? "atom" : "error";
} else {
stream.eatWhile(/[^&<]/);
return null;
}
}
inText.isInText = true;
function inTag(stream, state) {
var ch = stream.next();
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
state.tokenize = inText;
type = ch == ">" ? "endTag" : "selfcloseTag";
return "tag bracket";
} else if (ch == "=") {
type = "equals";
return null;
} else if (ch == "<") {
state.tokenize = inText;
state.state = baseState;
state.tagName = state.tagStart = null;
var next = state.tokenize(stream, state);
return next ? next + " tag error" : "tag error";
} else if (/[\'\"]/.test(ch)) {
state.tokenize = inAttribute(ch);
state.stringStartCol = stream.column();
return state.tokenize(stream, state);
} else {
stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
return "word";
}
}
function inAttribute(quote) {
var closure = function(stream, state) {
while (!stream.eol()) {
if (stream.next() == quote) {
state.tokenize = inTag;
break;
}
}
return "string";
};
closure.isInAttribute = true;
return closure;
}
function inBlock(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator)) {
state.tokenize = inText;
break;
}
stream.next();
}
return style;
};
}
function doctype(depth) {
return function(stream, state) {
var ch;
while ((ch = stream.next()) != null) {
if (ch == "<") {
state.tokenize = doctype(depth + 1);
return state.tokenize(stream, state);
} else if (ch == ">") {
if (depth == 1) {
state.tokenize = inText;
break;
} else {
state.tokenize = doctype(depth - 1);
return state.tokenize(stream, state);
}
}
}
return "meta";
};
}
function Context(state, tagName, startOfLine) {
this.prev = state.context;
this.tagName = tagName;
this.indent = state.indented;
this.startOfLine = startOfLine;
if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
this.noIndent = true;
}
function popContext(state) {
if (state.context) state.context = state.context.prev;
}
function maybePopContext(state, nextTagName) {
var parentTagName;
while (true) {
if (!state.context) {
return;
}
parentTagName = state.context.tagName;
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
return;
}
popContext(state);
}
}
function baseState(type, stream, state) {
if (type == "openTag") {
state.tagStart = stream.column();
return tagNameState;
} else if (type == "closeTag") {
return closeTagNameState;
} else {
return baseState;
}
}
function tagNameState(type, stream, state) {
if (type == "word") {
state.tagName = stream.current();
setStyle = "tag";
return attrState;
} else {
setStyle = "error";
return tagNameState;
}
}
function closeTagNameState(type, stream, state) {
if (type == "word") {
var tagName = stream.current();
if (state.context && state.context.tagName != tagName &&
Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
popContext(state);
if (state.context && state.context.tagName == tagName) {
setStyle = "tag";
return closeState;
} else {
setStyle = "tag error";
return closeStateErr;
}
} else {
setStyle = "error";
return closeStateErr;
}
}
function closeState(type, _stream, state) {
if (type != "endTag") {
setStyle = "error";
return closeState;
}
popContext(state);
return baseState;
}
function closeStateErr(type, stream, state) {
setStyle = "error";
return closeState(type, stream, state);
}
function attrState(type, _stream, state) {
if (type == "word") {
setStyle = "attribute";
return attrEqState;
} else if (type == "endTag" || type == "selfcloseTag") {
var tagName = state.tagName, tagStart = state.tagStart;
state.tagName = state.tagStart = null;
if (type == "selfcloseTag" ||
Kludges.autoSelfClosers.hasOwnProperty(tagName)) {
maybePopContext(state, tagName);
} else {
maybePopContext(state, tagName);
state.context = new Context(state, tagName, tagStart == state.indented);
}
return baseState;
}
setStyle = "error";
return attrState;
}
function attrEqState(type, stream, state) {
if (type == "equals") return attrValueState;
if (!Kludges.allowMissing) setStyle = "error";
return attrState(type, stream, state);
}
function attrValueState(type, stream, state) {
if (type == "string") return attrContinuedState;
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
setStyle = "error";
return attrState(type, stream, state);
}
function attrContinuedState(type, stream, state) {
if (type == "string") return attrContinuedState;
return attrState(type, stream, state);
}
return {
startState: function() {
return {tokenize: inText,
state: baseState,
indented: 0,
tagName: null, tagStart: null,
context: null};
},
token: function(stream, state) {
if (!state.tagName && stream.sol())
state.indented = stream.indentation();
if (stream.eatSpace()) return null;
type = null;
var style = state.tokenize(stream, state);
if ((style || type) && style != "comment") {
setStyle = null;
state.state = state.state(type || style, stream, state);
if (setStyle)
style = setStyle == "error" ? style + " error" : setStyle;
}
return style;
},
indent: function(state, textAfter, fullLine) {
var context = state.context;
// Indent multi-line strings (e.g. css).
if (state.tokenize.isInAttribute) {
if (state.tagStart == state.indented)
return state.stringStartCol + 1;
else
return state.indented + indentUnit;
}
if (context && context.noIndent) return CodeMirror.Pass;
if (state.tokenize != inTag && state.tokenize != inText)
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
// Indent the starts of attribute names.
if (state.tagName) {
if (multilineTagIndentPastTag)
return state.tagStart + state.tagName.length + 2;
else
return state.tagStart + indentUnit * multilineTagIndentFactor;
}
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
if (tagAfter && tagAfter[1]) { // Closing tag spotted
while (context) {
if (context.tagName == tagAfter[2]) {
context = context.prev;
break;
} else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {
context = context.prev;
} else {
break;
}
}
} else if (tagAfter) { // Opening tag spotted
while (context) {
var grabbers = Kludges.contextGrabbers[context.tagName];
if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
context = context.prev;
else
break;
}
}
while (context && !context.startOfLine)
context = context.prev;
if (context) return context.indent + indentUnit;
else return 0;
},
electricInput: /<\/[\s\w:]+>$/,
blockCommentStart: "<!--",
blockCommentEnd: "-->",
configuration: parserConfig.htmlMode ? "html" : "xml",
helperType: parserConfig.htmlMode ? "html" : "xml"
};
});
CodeMirror.defineMIME("text/xml", "xml");
CodeMirror.defineMIME("application/xml", "xml");
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
});
/*global window, RSVP, FileReader */
/*jslint indent: 2, maxerr: 3, unparam: true */
(function (window, RSVP, FileReader) {
"use strict";
window.loopEventListener = function (target, type, useCapture, callback,
prevent_default) {
//////////////////////////
// Infinite event listener (promise is never resolved)
// eventListener is removed when promise is cancelled/rejected
//////////////////////////
var handle_event_callback,
callback_promise;
if (prevent_default === undefined) {
prevent_default = true;
}
function cancelResolver() {
if ((callback_promise !== undefined) &&
(typeof callback_promise.cancel === "function")) {
callback_promise.cancel();
}
}
function canceller() {
if (handle_event_callback !== undefined) {
target.removeEventListener(type, handle_event_callback, useCapture);
}
cancelResolver();
}
function itsANonResolvableTrap(resolve, reject) {
var result;
handle_event_callback = function (evt) {
if (prevent_default) {
evt.stopPropagation();
evt.preventDefault();
}
cancelResolver();
try {
result = callback(evt);
} catch (e) {
result = RSVP.reject(e);
}
callback_promise = result;
new RSVP.Queue()
.push(function () {
return result;
})
.push(undefined, function (error) {
if (!(error instanceof RSVP.CancellationError)) {
canceller();
reject(error);
}
});
};
target.addEventListener(type, handle_event_callback, useCapture);
}
return new RSVP.Promise(itsANonResolvableTrap, canceller);
};
window.promiseEventListener = function (target, type, useCapture) {
//////////////////////////
// Resolve the promise as soon as the event is triggered
// eventListener is removed when promise is cancelled/resolved/rejected
//////////////////////////
var handle_event_callback;
function canceller() {
target.removeEventListener(type, handle_event_callback, useCapture);
}
function resolver(resolve) {
handle_event_callback = function (evt) {
canceller();
evt.stopPropagation();
evt.preventDefault();
resolve(evt);
return false;
};
target.addEventListener(type, handle_event_callback, useCapture);
}
return new RSVP.Promise(resolver, canceller);
};
window.promiseReadAsText = function (file) {
return new RSVP.Promise(function (resolve, reject) {
var reader = new FileReader();
reader.onload = function (evt) {
resolve(evt.target.result);
};
reader.onerror = function (evt) {
reject(evt);
};
reader.readAsText(file);
});
};
}(window, RSVP, FileReader));
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -666,137 +666,81 @@ if (typeof document.contains !== 'function') {
}
}
;/*! RenderJs */
/*global console*/
/*jslint nomen: true*/
function loopEventListener(target, type, useCapture, callback) {
"use strict";
//////////////////////////
// Infinite event listener (promise is never resolved)
// eventListener is removed when promise is cancelled/rejected
//////////////////////////
var handle_event_callback,
callback_promise;
function cancelResolver() {
if ((callback_promise !== undefined) &&
(typeof callback_promise.cancel === "function")) {
callback_promise.cancel();
}
}
function canceller() {
if (handle_event_callback !== undefined) {
target.removeEventListener(type, handle_event_callback, useCapture);
}
cancelResolver();
}
function itsANonResolvableTrap(resolve, reject) {
handle_event_callback = function (evt) {
evt.stopPropagation();
evt.preventDefault();
cancelResolver();
callback_promise = new RSVP.Queue()
.push(function () {
return callback(evt);
})
.push(undefined, function (error) {
if (!(error instanceof RSVP.CancellationError)) {
canceller();
reject(error);
}
});
};
target.addEventListener(type, handle_event_callback, useCapture);
}
return new RSVP.Promise(itsANonResolvableTrap, canceller);
}
/*
* renderJs - Generic Gadget library renderer.
* http://www.renderjs.org/documentation
*/
(function (document, window, RSVP, DOMParser, Channel, MutationObserver,
Node) {
Node, FileReader, Blob) {
"use strict";
var gadget_model_dict = {},
javascript_registration_dict = {},
stylesheet_registration_dict = {},
gadget_loading_klass,
loading_klass_promise,
renderJS,
Monitor;
/////////////////////////////////////////////////////////////////
// Helper functions
/////////////////////////////////////////////////////////////////
function listenHashChange(gadget) {
function extractHashAndDispatch(evt) {
var hash = (evt.newURL || window.location.toString()).split('#')[1],
subhashes,
subhash,
keyvalue,
index,
options = {};
if (hash === undefined) {
hash = "";
} else {
hash = hash.split('?')[0];
function readBlobAsDataURL(blob) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject) {
fr.addEventListener("load", function (evt) {
resolve(evt.target.result);
});
fr.addEventListener("error", reject);
fr.readAsDataURL(blob);
}, function () {
fr.abort();
});
}
function optionalize(key, value, dict) {
var key_list = key.split("."),
kk,
i;
for (i = 0; i < key_list.length; i += 1) {
kk = key_list[i];
if (i === key_list.length - 1) {
dict[kk] = value;
function ajax(url) {
var xhr;
function resolver(resolve, reject) {
function handler() {
try {
if (xhr.readyState === 0) {
// UNSENT
reject(xhr);
} else if (xhr.readyState === 4) {
// DONE
if ((xhr.status < 200) || (xhr.status >= 300) ||
(!/^text\/html[;]?/.test(
xhr.getResponseHeader("Content-Type") || ""
))) {
reject(xhr);
} else {
if (!dict.hasOwnProperty(kk)) {
dict[kk] = {};
resolve(xhr);
}
dict = dict[kk];
}
} catch (e) {
reject(e);
}
}
subhashes = hash.split('&');
for (index in subhashes) {
if (subhashes.hasOwnProperty(index)) {
subhash = subhashes[index];
if (subhash !== '') {
keyvalue = subhash.split('=');
if (keyvalue.length === 2) {
optionalize(decodeURIComponent(keyvalue[0]),
decodeURIComponent(keyvalue[1]),
options);
}
}
}
xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = handler;
xhr.setRequestHeader('Accept', 'text/html');
xhr.withCredentials = true;
xhr.send();
}
if (gadget.render !== undefined) {
return gadget.render(options);
function canceller() {
if ((xhr !== undefined) && (xhr.readyState !== xhr.DONE)) {
xhr.abort();
}
}
var result = loopEventListener(window, 'hashchange', false,
extractHashAndDispatch),
event = document.createEvent("Event");
event.initEvent('hashchange', true, true);
event.newURL = window.location.toString();
window.dispatchEvent(event);
return result;
return new RSVP.Promise(resolver, canceller);
}
var gadget_model_dict = {},
javascript_registration_dict = {},
stylesheet_registration_dict = {},
gadget_loading_klass,
loading_klass_promise,
renderJS,
Monitor,
isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i');
/////////////////////////////////////////////////////////////////
// Helper functions
/////////////////////////////////////////////////////////////////
function removeHash(url) {
var index = url.indexOf('#');
if (index > 0) {
......@@ -1126,8 +1070,6 @@ function loopEventListener(target, type, useCapture, callback) {
};
RenderJSGadget.declareAcquiredMethod("aq_reportServiceError",
"reportServiceError");
RenderJSGadget.declareAcquiredMethod("aq_pleasePublishMyState",
"pleasePublishMyState");
/////////////////////////////////////////////////////////////////
// RenderJSGadget.allowPublicAcquisition
......@@ -1148,22 +1090,6 @@ function loopEventListener(target, type, useCapture, callback) {
};
}
function pleasePublishMyState(param_list, child_gadget_scope) {
var new_param = {},
key;
for (key in this.state_parameter_dict) {
if (this.state_parameter_dict.hasOwnProperty(key)) {
new_param[key] = this.state_parameter_dict[key];
}
}
if (child_gadget_scope === undefined) {
throw new Error("gadget scope is mandatory");
}
new_param[child_gadget_scope] = param_list[0];
param_list = [new_param];
return this.aq_pleasePublishMyState.apply(this, param_list);
}
/////////////////////////////////////////////////////////////////
// RenderJSEmbeddedGadget
/////////////////////////////////////////////////////////////////
......@@ -1350,6 +1276,33 @@ function loopEventListener(target, type, useCapture, callback) {
]);
}
/////////////////////////////////////////////////////////////////
// privateDeclareDataUrlGadget
/////////////////////////////////////////////////////////////////
function privateDeclareDataUrlGadget(url, options, parent_gadget) {
return new RSVP.Queue()
.push(function () {
return ajax(url);
})
.push(function (xhr) {
// Insert a "base" element, in order to resolve all relative links
// which could get broken with a data url
var doc = (new DOMParser()).parseFromString(xhr.responseText,
'text/html'),
base = doc.createElement('base'),
blob;
base.href = url;
doc.head.insertBefore(base, doc.head.firstChild);
blob = new Blob([doc.documentElement.outerHTML],
{type: "text/html;charset=UTF-8"});
return readBlobAsDataURL(blob);
})
.push(function (data_url) {
return privateDeclareIframeGadget(data_url, options, parent_gadget);
});
}
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareGadget
/////////////////////////////////////////////////////////////////
......@@ -1385,6 +1338,8 @@ function loopEventListener(target, type, useCapture, callback) {
method = privateDeclarePublicGadget;
} else if (options.sandbox === "iframe") {
method = privateDeclareIframeGadget;
} else if (options.sandbox === "dataurl") {
method = privateDeclareDataUrlGadget;
} else {
throw new Error("Unsupported sandbox options '" +
options.sandbox + "'");
......@@ -1497,8 +1452,7 @@ function loopEventListener(target, type, useCapture, callback) {
/////////////////////////////////////////////////////////////////
renderJS.getAbsoluteURL = function (url, base_url) {
var doc, base, link,
html = "<!doctype><html><head></head></html>",
isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i');
html = "<!doctype><html><head></head></html>";
if (url && base_url && !isAbsoluteOrDataURL.test(url)) {
doc = (new DOMParser()).parseFromString(html, 'text/html');
......@@ -1576,10 +1530,9 @@ function loopEventListener(target, type, useCapture, callback) {
// renderJS.declareGadgetKlass
/////////////////////////////////////////////////////////////////
renderJS.declareGadgetKlass = function (url) {
var result,
xhr;
var result;
function parse() {
function parse(xhr) {
var tmp_constructor,
key,
parsed_html;
......@@ -1604,8 +1557,6 @@ function loopEventListener(target, type, useCapture, callback) {
tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url;
tmp_constructor.prototype.__acquired_method_dict = {};
tmp_constructor.allowPublicAcquisition("pleasePublishMyState",
pleasePublishMyState);
// https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
......@@ -1627,50 +1578,18 @@ function loopEventListener(target, type, useCapture, callback) {
return gadget_model_dict[url];
}
function resolver(resolve, reject) {
function handler() {
var tmp_result;
try {
if (xhr.readyState === 0) {
// UNSENT
reject(xhr);
} else if (xhr.readyState === 4) {
// DONE
if ((xhr.status < 200) || (xhr.status >= 300) ||
(!/^text\/html[;]?/.test(
xhr.getResponseHeader("Content-Type") || ""
))) {
reject(xhr);
} else {
tmp_result = parse();
resolve(tmp_result);
}
}
} catch (e) {
reject(e);
}
}
xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = handler;
xhr.setRequestHeader('Accept', 'text/html');
xhr.withCredentials = true;
xhr.send();
}
function canceller() {
if ((xhr !== undefined) && (xhr.readyState !== xhr.DONE)) {
xhr.abort();
}
}
if (gadget_model_dict.hasOwnProperty(url)) {
// Return klass object if it already exists
result = RSVP.resolve(gadget_model_dict[url]);
} else {
// Fetch the HTML page and parse it
result = new RSVP.Promise(resolver, canceller);
result = new RSVP.Queue()
.push(function () {
return ajax(url);
})
.push(function (xhr) {
return parse(xhr);
});
}
return result;
};
......@@ -1696,10 +1615,9 @@ function loopEventListener(target, type, useCapture, callback) {
required_js_list: []
},
i,
element,
isAbsoluteURL = new RegExp('^(?:[a-z]+:)?//', 'i');
element;
if (!url || !isAbsoluteURL.test(url)) {
if (!url || !isAbsoluteOrDataURL.test(url)) {
throw new Error("The url should be absolute: " + url);
}
......@@ -1749,39 +1667,6 @@ function loopEventListener(target, type, useCapture, callback) {
// Bootstrap process. Register the self gadget.
///////////////////////////////////////////////////
function mergeSubDict(dict) {
var subkey,
subkey2,
subresult2,
value,
result = {};
for (subkey in dict) {
if (dict.hasOwnProperty(subkey)) {
value = dict[subkey];
if (value instanceof Object) {
subresult2 = mergeSubDict(value);
for (subkey2 in subresult2) {
if (subresult2.hasOwnProperty(subkey2)) {
// XXX key should not have an . inside
if (result.hasOwnProperty(subkey + "." + subkey2)) {
throw new Error("Key " + subkey + "." +
subkey2 + " already present");
}
result[subkey + "." + subkey2] = subresult2[subkey2];
}
}
} else {
if (result.hasOwnProperty(subkey)) {
throw new Error("Key " + subkey + " already present");
}
result[subkey] = value;
}
}
}
return result;
}
function bootstrap() {
var url = removeHash(window.location.href),
tmp_constructor,
......@@ -1808,26 +1693,6 @@ function loopEventListener(target, type, useCapture, callback) {
},
reportServiceError: function (param_list) {
letsCrash(param_list[0]);
},
pleaseRedirectMyHash: function (param_list) {
window.location.replace(param_list[0]);
},
pleasePublishMyState: function (param_list) {
var key,
first = true,
hash = "#";
param_list[0] = mergeSubDict(param_list[0]);
for (key in param_list[0]) {
if (param_list[0].hasOwnProperty(key)) {
if (!first) {
hash += "&";
}
hash += encodeURIComponent(key) + "=" +
encodeURIComponent(param_list[0][key]);
first = false;
}
}
return hash;
}
};
// Stop acquisition on the last acquisition gadget
......@@ -1869,10 +1734,6 @@ function loopEventListener(target, type, useCapture, callback) {
// Create the root gadget instance and put it in the loading stack
root_gadget = new gadget_model_dict[url]();
tmp_constructor.declareService(function () {
return listenHashChange(this);
});
setAqParent(root_gadget, last_acquisition_gadget);
} else {
......@@ -1959,8 +1820,6 @@ function loopEventListener(target, type, useCapture, callback) {
}
tmp_constructor.prototype.__acquired_method_dict = {};
tmp_constructor.allowPublicAcquisition("pleasePublishMyState",
pleasePublishMyState);
gadget_loading_klass = tmp_constructor;
function init() {
......@@ -2113,9 +1972,6 @@ function loopEventListener(target, type, useCapture, callback) {
//we consider current gadget is parent gadget
//redifine last acquisition gadget
iframe_top_gadget = true;
tmp_constructor.declareService(function () {
return listenHashChange(this);
});
setAqParent(root_gadget, last_acquisition_gadget);
} else {
throw error;
......@@ -2164,4 +2020,5 @@ function loopEventListener(target, type, useCapture, callback) {
}
bootstrap();
}(document, window, RSVP, DOMParser, Channel, MutationObserver, Node));
\ No newline at end of file
}(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
FileReader, Blob));
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment