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 @@ ...@@ -6,8 +6,8 @@
<title>Crib SW interface Gadget</title> <title>Crib SW interface Gadget</title>
<!-- renderjs --> <!-- renderjs -->
<script src="../lib/rsvp.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/renderjs.js" type="text/javascript"></script>
<!-- custom script --> <!-- custom script -->
<script src="crib-sw-gadget.js" type="text/javascript"></script> <script src="crib-sw-gadget.js" type="text/javascript"></script>
......
...@@ -135,7 +135,6 @@ ...@@ -135,7 +135,6 @@
.declareMethod('put', function(url, parameter) { .declareMethod('put', function(url, parameter) {
return new RSVP.Queue() return new RSVP.Queue()
.push(function() { .push(function() {
console.log(url);
if (parameter.blob !== undefined) { if (parameter.blob !== undefined) {
return sendMessage({ return sendMessage({
command: 'add', command: 'add',
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width"> <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> <title>CribJS</title>
<script src="../lib/sha256.js"></script> <script src="/lib/sha256.js"></script>
<script src="../lib/sha256.amd.js"></script> <script src="/lib/sha256.amd.js"></script>
<script src="../lib/rsvp.js"></script> <script src="/lib/rsvp.js"></script>
<script src="../lib/jio-latest.js"></script> <script src="/lib/jio-latest.js"></script>
<script src="../lib/renderjs.js"></script> <script src="/lib/renderjs.js"></script>
<script src="cribjs-ide-gadget.js"></script> <script src="cribjs-ide-gadget.js"></script>
<!--The following CSS shows a lack of developing style --> <!--The following CSS shows a lack of developing style -->
<style> <style>
......
...@@ -5,23 +5,23 @@ ...@@ -5,23 +5,23 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Codemirror Gadget</title> <title>Codemirror Gadget</title>
<script src="../lib/rsvp.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/renderjs.js" type="text/javascript"></script>
<link rel="stylesheet" href="../lib/codemirror.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/dialog/dialog.css">
<link rel="stylesheet" href="../lib/codemirror/addon/search/matchesonscrollbar.css"> <link rel="stylesheet" href="/lib/codemirror/addon/search/matchesonscrollbar.css">
<script src="../lib/codemirror.js"></script> <script src="/lib/codemirror.js"></script>
<script src="../lib/codemirror/mode/css/css.js"></script> <script src="/lib/codemirror/mode/css.js"></script>
<script src="../lib/codemirror/mode/xml/xml.js"></script> <script src="/lib/codemirror/mode/xml.js"></script>
<script src="../lib/codemirror/mode/javascript/javascript.js"></script> <script src="/lib/codemirror/mode/javascript.js"></script>
<script src="../lib/codemirror/mode/htmlmixed/htmlmixed.js"></script> <script src="/lib/codemirror/mode/htmlmixed.js"></script>
<script src="../lib/codemirror/addon/dialog/dialog.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/searchcursor.js"></script>
<script src="../lib/codemirror/addon/search/search.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/scroll/annotatescrollbar.js"></script>
<script src="../lib/codemirror/addon/search/matchesonscrollbar.js"></script> <script src="/lib/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="gadget_codemirror.js" type="text/javascript"></script> <script src="gadget_codemirror.js" type="text/javascript"></script>
</head> </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 @@ ...@@ -6,16 +6,16 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<title>CribJS Loader</title> <title>CribJS Loader</title>
<script src="../lib/rsvp.js"></script> <script src="/lib/rsvp.js"></script>
<script src="../lib/renderjs.js"></script> <script src="/lib/renderjs.js"></script>
<script src="gadget_cribjs_loader.js"></script> <script src="gadget_cribjs_loader.js"></script>
</head> </head>
<body> <body>
<h1>CribJS Loader</h1> <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-scope="jio_cribjs"
data-gadget-sandbox="public"></div> 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-scope="jio_configurator"
data-gadget-sandbox="public"></div> data-gadget-sandbox="public"></div>
<form> <form>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
jio_configurator_gadget; jio_configurator_gadget;
return RSVP.Queue() return RSVP.Queue()
.push(function() { .push(function() {
return RSPV.all([ return RSVP.all([
gadget.getDeclaredGadget("jio_cribjs"), gadget.getDeclaredGadget("jio_cribjs"),
gadget.getDeclaredGadget("jio_configurator")]); gadget.getDeclaredGadget("jio_configurator")]);
}) })
...@@ -19,14 +19,14 @@ ...@@ -19,14 +19,14 @@
}) })
.push(function (jio_string) { .push(function (jio_string) {
return jio_cribjs_gadget.load({ return jio_cribjs_gadget.load({
path: document.location.href, path: document.location.origin,
jio_config: JSON.parse(jio_string), jio_config: JSON.parse(jio_string),
application_id: "cribjs" application_id: "cribjs"
}) })
}) })
.push(function (url_list) { .push(function (url_list) {
console.log(url_list); console.log(url_list);
document.location = document.location.href + "/crib-editor/"; document.location = document.location.origin + "/crib-editor/";
}) })
} }
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
.declareMethod('render', function (options) { .declareMethod('render', function (options) {
var gadget = this, var gadget = this,
jio_configuration_string = ""; jio_configuration_string = "";
console.log("rendering");
if (localStorage.hasOwnProperty("crib_js_loader_jio")) { if (localStorage.hasOwnProperty("crib_js_loader_jio")) {
jio_configuration_string = localStorage.getItem("crib_js_loader_jio"); jio_configuration_string = localStorage.getItem("crib_js_loader_jio");
} else { } else {
...@@ -46,12 +45,11 @@ ...@@ -46,12 +45,11 @@
return gadget.getDeclaredGadget('jio_configurator'); return gadget.getDeclaredGadget('jio_configurator');
}) })
.push(function (jio_configurator_gadget) { .push(function (jio_configurator_gadget) {
console.log(jio_configuration_string);
return jio_configurator_gadget.render({value: jio_configuration_string}); return jio_configurator_gadget.render({value: jio_configuration_string});
}) })
.push(function () { .push(function () {
return loopEventListener( return loopEventListener(
gadget.props.element.querySelector("form"), gadget.props.element.querySelector("form.loading"),
'submit', 'submit',
false, false,
function (event) {loadCribJS(gadget, event)} 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 @@ ...@@ -8,10 +8,10 @@
<title>Jio Gadget</title> <title>Jio Gadget</title>
<!-- renderjs --> <!-- renderjs -->
<script src="../lib/rsvp.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/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 --> <!-- custom script -->
<script src="gadget_jio.js" type="text/javascript"></script> <script src="gadget_jio.js" type="text/javascript"></script>
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<title>CribJS Loader</title> <title>CribJS Loader</title>
<script src="../lib/rsvp.js"></script> <script src="/lib/rsvp.js"></script>
<script src="../lib/renderjs.js"></script> <script src="/lib/renderjs.js"></script>
<script src="gadget_jio_configurator.js"></script> <script src="gadget_jio_configurator.js"></script>
</head> </head>
<body> <body>
......
...@@ -6,15 +6,15 @@ ...@@ -6,15 +6,15 @@
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<title>CribJS Loader</title> <title>CribJS Loader</title>
<script src="../lib/rsvp.js"></script> <script src="/lib/rsvp.js"></script>
<script src="../lib/renderjs.js"></script> <script src="/lib/renderjs.js"></script>
<script src="gadget_jio_cribjs.js"></script> <script src="gadget_jio_cribjs.js"></script>
</head> </head>
<body> <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-scope="crib_sw_gadget"
data-gadget-sandbox="public"></div> 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-scope="jio_gadget"
data-gadget-sandbox="public"></div> data-gadget-sandbox="public"></div>
</body> </body>
......
...@@ -52,9 +52,8 @@ ...@@ -52,9 +52,8 @@
}) })
.push(function(response_list) { .push(function(response_list) {
var promise_list = [], var promise_list = [],
i, i_len, url, index, response, location, location_len, i, i_len, url, index, response, location, location_len;
new_url; location = document.location.origin;
location = document.location.href;
location_len = location.length location_len = location.length
for (i = 0, i_len = response_list.length; i < i_len; i += 1) { for (i = 0, i_len = response_list.length; i < i_len; i += 1) {
url = url_list[i] url = url_list[i]
...@@ -62,13 +61,8 @@ ...@@ -62,13 +61,8 @@
if (index != -1) if (index != -1)
url = url.substr(index + location_len); url = url.substr(index + location_len);
console.log(path_to_load + url); 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( 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); 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 @@ ...@@ -41,21 +41,19 @@
/* CURSOR */ /* CURSOR */
.CodeMirror-cursor { .CodeMirror div.CodeMirror-cursor {
border-left: 1px solid black; border-left: 1px solid black;
border-right: none;
width: 0;
} }
/* Shown when moving in bi-directional text */ /* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor { .CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver; border-left: 1px solid silver;
} }
.cm-fat-cursor .CodeMirror-cursor { .CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
width: auto; width: auto;
border: 0; border: 0;
background: #7e7; background: #7e7;
} }
.cm-fat-cursor div.CodeMirror-cursors { .CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1; z-index: 1;
} }
...@@ -84,7 +82,7 @@ ...@@ -84,7 +82,7 @@
} }
/* Can style cursor different in overwrite (non-insert) mode */ /* 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; } .cm-tab { display: inline-block; text-decoration: inherit; }
...@@ -165,7 +163,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} ...@@ -165,7 +163,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
} }
/* The fake, visible scrollbars. Used to force redraw during scrolling /* 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. */ flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute; position: absolute;
...@@ -286,19 +284,19 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} ...@@ -286,19 +284,19 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
overflow: hidden; overflow: hidden;
visibility: hidden; visibility: hidden;
} }
.CodeMirror-cursor { position: absolute; }
.CodeMirror-measure pre { position: static; } .CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor {
position: absolute;
border-right: none;
width: 0;
}
div.CodeMirror-cursors { div.CodeMirror-cursors {
visibility: hidden; visibility: hidden;
position: relative; position: relative;
z-index: 3; z-index: 3;
} }
div.CodeMirror-dragcursors {
visibility: visible;
}
.CodeMirror-focused div.CodeMirror-cursors { .CodeMirror-focused div.CodeMirror-cursors {
visibility: visible; visibility: visible;
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
return define([], mod); return define([], mod);
else // Plain browser env else // Plain browser env
(this || window).CodeMirror = mod(); this.CodeMirror = mod();
})(function() { })(function() {
"use strict"; "use strict";
...@@ -21,29 +21,27 @@ ...@@ -21,29 +21,27 @@
// Kludges for bugs and behavior differences that can't be feature // Kludges for bugs and behavior differences that can't be feature
// detected are enabled based on userAgent etc sniffing. // detected are enabled based on userAgent etc sniffing.
var userAgent = navigator.userAgent;
var platform = navigator.platform;
var gecko = /gecko\/\d/i.test(userAgent); var gecko = /gecko\/\d/i.test(navigator.userAgent);
var ie_upto10 = /MSIE \d/.test(userAgent); var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent); var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
var ie = ie_upto10 || ie_11up; var ie = ie_upto10 || ie_11up;
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
var webkit = /WebKit\//.test(userAgent); var webkit = /WebKit\//.test(navigator.userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
var chrome = /Chrome\//.test(userAgent); var chrome = /Chrome\//.test(navigator.userAgent);
var presto = /Opera\//.test(userAgent); var presto = /Opera\//.test(navigator.userAgent);
var safari = /Apple Computer/.test(navigator.vendor); var safari = /Apple Computer/.test(navigator.vendor);
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
var phantom = /PhantomJS/.test(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. // This is woefully incomplete. Suggestions for alternative methods welcome.
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
var mac = ios || /Mac/.test(platform); var mac = ios || /Mac/.test(navigator.platform);
var windows = /win/i.test(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 = Number(presto_version[1]);
if (presto_version && presto_version >= 15) { presto = false; webkit = true; } if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
...@@ -89,7 +87,6 @@ ...@@ -89,7 +87,6 @@
focused: false, focused: false,
suppressEdits: false, // used to disable editing during key handlers when in readOnly mode 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 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
selectingText: false,
draggingText: false, draggingText: false,
highlight: new Delayed(), // stores highlight worker timeout highlight: new Delayed(), // stores highlight worker timeout
keySeq: null, // Unfinished key sequence keySeq: null, // Unfinished key sequence
...@@ -410,7 +407,7 @@ ...@@ -410,7 +407,7 @@
if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); 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). // 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"; if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
} }
...@@ -445,43 +442,29 @@ ...@@ -445,43 +442,29 @@
this.horiz.firstChild.style.width = "0"; this.horiz.firstChild.style.width = "0";
} }
if (!this.checkedZeroWidth && measure.clientHeight > 0) { if (!this.checkedOverlay && measure.clientHeight > 0) {
if (sWidth == 0) this.zeroWidthHack(); if (sWidth == 0) this.overlayHack();
this.checkedZeroWidth = true; this.checkedOverlay = true;
} }
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
}, },
setScrollLeft: function(pos) { setScrollLeft: function(pos) {
if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
}, },
setScrollTop: function(pos) { setScrollTop: function(pos) {
if (this.vert.scrollTop != pos) this.vert.scrollTop = 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"; var w = mac && !mac_geMountainLion ? "12px" : "18px";
this.horiz.style.height = this.vert.style.width = w; this.horiz.style.minHeight = this.vert.style.minWidth = w;
this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; var self = this;
this.disableHoriz = new Delayed; var barMouseDown = function(e) {
this.disableVert = new Delayed; if (e_target(e) != self.vert && e_target(e) != self.horiz)
}, operation(self.cm, onMouseDown)(e);
enableZeroWidthBar: function(bar, delay) { };
bar.style.pointerEvents = "auto"; on(this.vert, "mousedown", barMouseDown);
function maybeDisable() { on(this.horiz, "mousedown", barMouseDown);
// 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);
}, },
clear: function() { clear: function() {
var parent = this.horiz.parentNode; var parent = this.horiz.parentNode;
...@@ -823,7 +806,7 @@ ...@@ -823,7 +806,7 @@
// given line. // given line.
function updateWidgetHeight(line) { function updateWidgetHeight(line) {
if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) 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 // Do a bulk-read of the DOM positions and sizes needed to draw the
...@@ -1094,6 +1077,10 @@ ...@@ -1094,6 +1077,10 @@
if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } 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, // This will be set to an array of strings when copying, so that,
// when pasting, we know what kind of selections the copied text // when pasting, we know what kind of selections the copied text
// was made out of. // was made out of.
...@@ -1148,7 +1135,6 @@ ...@@ -1148,7 +1135,6 @@
var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
if (pasted) { if (pasted) {
e.preventDefault(); e.preventDefault();
if (!cm.isReadOnly() && !cm.options.disableInput)
runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); }); runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
return true; return true;
} }
...@@ -1251,14 +1237,13 @@ ...@@ -1251,14 +1237,13 @@
}); });
on(te, "paste", function(e) { on(te, "paste", function(e) {
if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return if (handlePaste(e, cm)) return true;
cm.state.pasteIncoming = true; cm.state.pasteIncoming = true;
input.fastPoll(); input.fastPoll();
}); });
function prepareCopyCut(e) { function prepareCopyCut(e) {
if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) { if (cm.somethingSelected()) {
lastCopied = cm.getSelections(); lastCopied = cm.getSelections();
if (input.inaccurateSelection) { if (input.inaccurateSelection) {
...@@ -1286,7 +1271,7 @@ ...@@ -1286,7 +1271,7 @@
on(te, "copy", prepareCopyCut); on(te, "copy", prepareCopyCut);
on(display.scroller, "paste", function(e) { on(display.scroller, "paste", function(e) {
if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return; if (eventInWidget(display, e)) return;
cm.state.pasteIncoming = true; cm.state.pasteIncoming = true;
input.focus(); input.focus();
}); });
...@@ -1298,7 +1283,6 @@ ...@@ -1298,7 +1283,6 @@
on(te, "compositionstart", function() { on(te, "compositionstart", function() {
var start = cm.getCursor("from"); var start = cm.getCursor("from");
if (input.composing) input.composing.range.clear()
input.composing = { input.composing = {
start: start, start: start,
range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
...@@ -1420,7 +1404,7 @@ ...@@ -1420,7 +1404,7 @@
// in which case reading its value would be expensive. // in which case reading its value would be expensive.
if (this.contextMenuPending || !cm.state.focused || if (this.contextMenuPending || !cm.state.focused ||
(hasSelection(input) && !prevInput && !this.composing) || (hasSelection(input) && !prevInput && !this.composing) ||
cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
return false; return false;
var text = input.value; var text = input.value;
...@@ -1547,10 +1531,6 @@ ...@@ -1547,10 +1531,6 @@
} }
}, },
readOnlyChanged: function(val) {
if (!val) this.reset();
},
setUneditable: nothing, setUneditable: nothing,
needsContentAttribute: false needsContentAttribute: false
...@@ -1569,11 +1549,10 @@ ...@@ -1569,11 +1549,10 @@
init: function(display) { init: function(display) {
var input = this, cm = input.cm; var input = this, cm = input.cm;
var div = input.div = display.lineDiv; var div = input.div = display.lineDiv;
div.contentEditable = "true";
disableBrowserMagic(div); disableBrowserMagic(div);
on(div, "paste", function(e) { on(div, "paste", function(e) { handlePaste(e, cm); })
if (!signalDOMEvent(cm, e)) handlePaste(e, cm);
})
on(div, "compositionstart", function(e) { on(div, "compositionstart", function(e) {
var data = e.data; var data = e.data;
...@@ -1611,12 +1590,11 @@ ...@@ -1611,12 +1590,11 @@
on(div, "input", function() { on(div, "input", function() {
if (input.composing) return; if (input.composing) return;
if (cm.isReadOnly() || !input.pollContent()) if (!input.pollContent())
runInOp(input.cm, function() {regChange(cm);}); runInOp(input.cm, function() {regChange(cm);});
}); });
function onCopyCut(e) { function onCopyCut(e) {
if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) { if (cm.somethingSelected()) {
lastCopied = cm.getSelections(); lastCopied = cm.getSelections();
if (e.type == "cut") cm.replaceSelection("", null, "cut"); if (e.type == "cut") cm.replaceSelection("", null, "cut");
...@@ -1692,13 +1670,8 @@ ...@@ -1692,13 +1670,8 @@
try { var rng = range(start.node, start.offset, end.offset, end.node); } 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 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 (rng) {
if (!gecko && this.cm.state.focused) {
sel.collapse(start.node, start.offset);
if (!rng.collapsed) sel.addRange(rng);
} else {
sel.removeAllRanges(); sel.removeAllRanges();
sel.addRange(rng); sel.addRange(rng);
}
if (old && sel.anchorNode == null) sel.addRange(old); if (old && sel.anchorNode == null) sel.addRange(old);
else if (gecko) this.startGracePeriod(); else if (gecko) this.startGracePeriod();
} }
...@@ -1842,26 +1815,19 @@ ...@@ -1842,26 +1815,19 @@
this.div.focus(); this.div.focus();
}, },
applyComposition: function(composing) { applyComposition: function(composing) {
if (this.cm.isReadOnly()) if (composing.data && composing.data != composing.startData)
operation(this.cm, regChange)(this.cm)
else if (composing.data && composing.data != composing.startData)
operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
}, },
setUneditable: function(node) { setUneditable: function(node) {
node.contentEditable = "false" node.setAttribute("contenteditable", "false");
}, },
onKeyPress: function(e) { onKeyPress: function(e) {
e.preventDefault(); e.preventDefault();
if (!this.cm.isReadOnly())
operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); 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, onContextMenu: nothing,
resetPosition: nothing, resetPosition: nothing,
...@@ -2159,7 +2125,7 @@ ...@@ -2159,7 +2125,7 @@
// Give beforeSelectionChange handlers a change to influence a // Give beforeSelectionChange handlers a change to influence a
// selection update. // selection update.
function filterSelectionChange(doc, sel, options) { function filterSelectionChange(doc, sel) {
var obj = { var obj = {
ranges: sel.ranges, ranges: sel.ranges,
update: function(ranges) { update: function(ranges) {
...@@ -2167,8 +2133,7 @@ ...@@ -2167,8 +2133,7 @@
for (var i = 0; i < ranges.length; i++) for (var i = 0; i < ranges.length; i++)
this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
clipPos(doc, ranges[i].head)); clipPos(doc, ranges[i].head));
}, }
origin: options && options.origin
}; };
signal(doc, "beforeSelectionChange", doc, obj); signal(doc, "beforeSelectionChange", doc, obj);
if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
...@@ -2194,7 +2159,7 @@ ...@@ -2194,7 +2159,7 @@
function setSelectionNoUndo(doc, sel, options) { function setSelectionNoUndo(doc, sel, options) {
if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
sel = filterSelectionChange(doc, sel, options); sel = filterSelectionChange(doc, sel);
var bias = options && options.bias || var bias = options && options.bias ||
(cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
...@@ -2228,9 +2193,8 @@ ...@@ -2228,9 +2193,8 @@
var out; var out;
for (var i = 0; i < sel.ranges.length; i++) { for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[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, bias, mayClear);
var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); var newHead = skipAtomic(doc, range.head, bias, mayClear);
var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
if (out || newAnchor != range.anchor || newHead != range.head) { if (out || newAnchor != range.anchor || newHead != range.head) {
if (!out) out = sel.ranges.slice(0, i); if (!out) out = sel.ranges.slice(0, i);
out[i] = new Range(newAnchor, newHead); out[i] = new Range(newAnchor, newHead);
...@@ -2239,12 +2203,18 @@ ...@@ -2239,12 +2203,18 @@
return out ? normalizeSelection(out, sel.primIndex) : sel; return out ? normalizeSelection(out, sel.primIndex) : sel;
} }
function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { // Ensure a given position is not inside an atomic range.
var line = getLine(doc, pos.line); function skipAtomic(doc, pos, bias, mayClear) {
if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { 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; var sp = line.markedSpans[i], m = sp.marker;
if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
(sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
if (mayClear) { if (mayClear) {
signal(m, "beforeCursorEnter"); signal(m, "beforeCursorEnter");
if (m.explicitlyCleared) { if (m.explicitlyCleared) {
...@@ -2253,45 +2223,34 @@ ...@@ -2253,45 +2223,34 @@
} }
} }
if (!m.atomic) continue; if (!m.atomic) continue;
var newPos = m.find(dir < 0 ? -1 : 1);
if (oldPos) { if (cmp(newPos, curPos) == 0) {
var near = m.find(dir < 0 ? 1 : -1), diff; newPos.ch += dir;
if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, line); if (newPos.ch < 0) {
if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
return skipAtomicInner(doc, near, pos, dir, mayClear); 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);
} }
flipped = true; newPos = pos; dir = -dir;
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;
} }
} }
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;
} }
return curPos;
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);
} }
} }
...@@ -2311,7 +2270,7 @@ ...@@ -2311,7 +2270,7 @@
var range = doc.sel.ranges[i]; var range = doc.sel.ranges[i];
var collapsed = range.empty(); var collapsed = range.empty();
if (collapsed || cm.options.showCursorWhenSelecting) if (collapsed || cm.options.showCursorWhenSelecting)
drawSelectionCursor(cm, range.head, curFragment); drawSelectionCursor(cm, range, curFragment);
if (!collapsed) if (!collapsed)
drawSelectionRange(cm, range, selFragment); drawSelectionRange(cm, range, selFragment);
} }
...@@ -2319,8 +2278,8 @@ ...@@ -2319,8 +2278,8 @@
} }
// Draws a cursor for the given range // Draws a cursor for the given range
function drawSelectionCursor(cm, head, output) { function drawSelectionCursor(cm, range, output) {
var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine); var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
cursor.style.left = pos.left + "px"; cursor.style.left = pos.left + "px";
...@@ -2444,8 +2403,8 @@ ...@@ -2444,8 +2403,8 @@
doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
if (doc.frontier >= cm.display.viewFrom) { // Visible if (doc.frontier >= cm.display.viewFrom) { // Visible
var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength; var oldStyles = line.styles;
var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true); var highlighted = highlightLine(cm, line, state, true);
line.styles = highlighted.styles; line.styles = highlighted.styles;
var oldCls = line.styleClasses, newCls = highlighted.classes; var oldCls = line.styleClasses, newCls = highlighted.classes;
if (newCls) line.styleClasses = newCls; if (newCls) line.styleClasses = newCls;
...@@ -2454,9 +2413,8 @@ ...@@ -2454,9 +2413,8 @@
oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); 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]; for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
if (ischange) changedLines.push(doc.frontier); if (ischange) changedLines.push(doc.frontier);
line.stateAfter = tooLong ? state : copyState(doc.mode, state); line.stateAfter = copyState(doc.mode, state);
} else { } else {
if (line.text.length <= cm.options.maxHighlightLength)
processLine(cm, line.text, state); processLine(cm, line.text, state);
line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
} }
...@@ -3020,12 +2978,12 @@ ...@@ -3020,12 +2978,12 @@
var callbacks = group.delayedCallbacks, i = 0; var callbacks = group.delayedCallbacks, i = 0;
do { do {
for (; i < callbacks.length; i++) for (; i < callbacks.length; i++)
callbacks[i].call(null); callbacks[i]();
for (var j = 0; j < group.ops.length; j++) { for (var j = 0; j < group.ops.length; j++) {
var op = group.ops[j]; var op = group.ops[j];
if (op.cursorActivityHandlers) if (op.cursorActivityHandlers)
while (op.cursorActivityCalled < op.cursorActivityHandlers.length) while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);
} }
} while (i < callbacks.length); } while (i < callbacks.length);
} }
...@@ -3119,8 +3077,7 @@ ...@@ -3119,8 +3077,7 @@
if (cm.state.focused && op.updateInput) if (cm.state.focused && op.updateInput)
cm.display.input.reset(op.typing); cm.display.input.reset(op.typing);
if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())) if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
ensureFocus(op.cm);
} }
function endOperation_finish(op) { function endOperation_finish(op) {
...@@ -3435,7 +3392,7 @@ ...@@ -3435,7 +3392,7 @@
return dx * dx + dy * dy > 20 * 20; return dx * dx + dy * dy > 20 * 20;
} }
on(d.scroller, "touchstart", function(e) { on(d.scroller, "touchstart", function(e) {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { if (!isMouseLikeTouchEvent(e)) {
clearTimeout(touchFinished); clearTimeout(touchFinished);
var now = +new Date; var now = +new Date;
d.activeTouch = {start: now, moved: false, d.activeTouch = {start: now, moved: false,
...@@ -3486,11 +3443,9 @@ ...@@ -3486,11 +3443,9 @@
on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
d.dragFunctions = { d.dragFunctions = {
enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
start: function(e){onDragStart(cm, e);}, start: function(e){onDragStart(cm, e);},
drop: operation(cm, onDrop), drop: operation(cm, onDrop)
leave: function() {clearDragCursor(cm);}
}; };
var inp = d.input.getField(); var inp = d.input.getField();
...@@ -3507,9 +3462,8 @@ ...@@ -3507,9 +3462,8 @@
var funcs = cm.display.dragFunctions; var funcs = cm.display.dragFunctions;
var toggle = value ? on : off; var toggle = value ? on : off;
toggle(cm.display.scroller, "dragstart", funcs.start); toggle(cm.display.scroller, "dragstart", funcs.start);
toggle(cm.display.scroller, "dragenter", funcs.enter); toggle(cm.display.scroller, "dragenter", funcs.simple);
toggle(cm.display.scroller, "dragover", funcs.over); toggle(cm.display.scroller, "dragover", funcs.simple);
toggle(cm.display.scroller, "dragleave", funcs.leave);
toggle(cm.display.scroller, "drop", funcs.drop); toggle(cm.display.scroller, "drop", funcs.drop);
} }
} }
...@@ -3564,7 +3518,7 @@ ...@@ -3564,7 +3518,7 @@
// not interfere with, such as a scrollbar or widget. // not interfere with, such as a scrollbar or widget.
function onMouseDown(e) { function onMouseDown(e) {
var cm = this, display = cm.display; 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; display.shift = e.shiftKey;
if (eventInWidget(display, e)) { if (eventInWidget(display, e)) {
...@@ -3582,10 +3536,7 @@ ...@@ -3582,10 +3536,7 @@
switch (e_button(e)) { switch (e_button(e)) {
case 1: case 1:
// #3261: make sure, that we're not starting a second selection if (start)
if (cm.state.selectingText)
cm.state.selectingText(e);
else if (start)
leftButtonDown(cm, e, start); leftButtonDown(cm, e, start);
else if (e_target(e) == display.scroller) else if (e_target(e) == display.scroller)
e_preventDefault(e); e_preventDefault(e);
...@@ -3620,7 +3571,7 @@ ...@@ -3620,7 +3571,7 @@
} }
var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; 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 && type == "single" && (contained = sel.contains(start)) > -1 &&
(cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
(cmp(contained.to(), start) > 0 || start.xRel < 0)) (cmp(contained.to(), start) > 0 || start.xRel < 0))
...@@ -3705,8 +3656,7 @@ ...@@ -3705,8 +3656,7 @@
setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
{scroll: false, origin: "*mouse"}); {scroll: false, origin: "*mouse"});
} else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { } 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), setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
{scroll: false, origin: "*mouse"});
startSel = doc.sel; startSel = doc.sel;
} else { } else {
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
...@@ -3784,7 +3734,6 @@ ...@@ -3784,7 +3734,6 @@
} }
function done(e) { function done(e) {
cm.state.selectingText = false;
counter = Infinity; counter = Infinity;
e_preventDefault(e); e_preventDefault(e);
display.input.focus(); display.input.focus();
...@@ -3798,14 +3747,13 @@ ...@@ -3798,14 +3747,13 @@
else extend(e); else extend(e);
}); });
var up = operation(cm, done); var up = operation(cm, done);
cm.state.selectingText = up;
on(document, "mousemove", move); on(document, "mousemove", move);
on(document, "mouseup", up); on(document, "mouseup", up);
} }
// Determines whether an event happened in the gutter, and fires the // Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event. // 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; } try { var mX = e.clientX, mY = e.clientY; }
catch(e) { return false; } catch(e) { return false; }
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
...@@ -3822,14 +3770,14 @@ ...@@ -3822,14 +3770,14 @@
if (g && g.getBoundingClientRect().right >= mX) { if (g && g.getBoundingClientRect().right >= mX) {
var line = lineAtHeight(cm.doc, mY); var line = lineAtHeight(cm.doc, mY);
var gutter = cm.options.gutters[i]; var gutter = cm.options.gutters[i];
signal(cm, type, cm, line, gutter, e); signalfn(cm, type, cm, line, gutter, e);
return e_defaultPrevented(e); return e_defaultPrevented(e);
} }
} }
} }
function clickInGutter(cm, 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 // Kludge to work around strange IE behavior where it'll sometimes
...@@ -3838,27 +3786,20 @@ ...@@ -3838,27 +3786,20 @@
function onDrop(e) { function onDrop(e) {
var cm = this; var cm = this;
clearDragCursor(cm);
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
return; return;
e_preventDefault(e); e_preventDefault(e);
if (ie) lastDrop = +new Date; if (ie) lastDrop = +new Date;
var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; 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 // Might be a file drop, in which case we simply extract the text
// and insert it. // and insert it.
if (files && files.length && window.FileReader && window.File) { if (files && files.length && window.FileReader && window.File) {
var n = files.length, text = Array(n), read = 0; var n = files.length, text = Array(n), read = 0;
var loadFile = function(file, i) { var loadFile = function(file, i) {
if (cm.options.allowDropFileTypes &&
indexOf(cm.options.allowDropFileTypes, file.type) == -1)
return;
var reader = new FileReader; var reader = new FileReader;
reader.onload = operation(cm, function() { reader.onload = operation(cm, function() {
var content = reader.result; text[i] = reader.result;
if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
text[i] = content;
if (++read == n) { if (++read == n) {
pos = clipPos(cm.doc, pos); pos = clipPos(cm.doc, pos);
var change = {from: pos, to: pos, var change = {from: pos, to: pos,
...@@ -3917,25 +3858,6 @@ ...@@ -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 // SCROLL EVENTS
// Sync the scrollable area and scrollbars, ensure the viewport // Sync the scrollable area and scrollbars, ensure the viewport
...@@ -4000,9 +3922,8 @@ ...@@ -4000,9 +3922,8 @@
var display = cm.display, scroll = display.scroller; var display = cm.display, scroll = display.scroller;
// Quit if there's nothing to scroll here // Quit if there's nothing to scroll here
var canScrollX = scroll.scrollWidth > scroll.clientWidth; if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
var canScrollY = scroll.scrollHeight > scroll.clientHeight; dy && scroll.scrollHeight > scroll.clientHeight)) return;
if (!(dx && canScrollX || dy && canScrollY)) return;
// Webkit browsers on OS X abort momentum scrolls when the target // Webkit browsers on OS X abort momentum scrolls when the target
// of the scroll event is removed from the scrollable element. // of the scroll event is removed from the scrollable element.
...@@ -4026,14 +3947,9 @@ ...@@ -4026,14 +3947,9 @@
// scrolling entirely here. It'll be slightly off from native, but // scrolling entirely here. It'll be slightly off from native, but
// better than glitching out. // better than glitching out.
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { 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))); 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))); 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); e_preventDefault(e);
display.wheelStartX = null; // Abort measurement, if in progress display.wheelStartX = null; // Abort measurement, if in progress
return; return;
...@@ -4083,7 +3999,7 @@ ...@@ -4083,7 +3999,7 @@
cm.display.input.ensurePolled(); cm.display.input.ensurePolled();
var prevShift = cm.display.shift, done = false; var prevShift = cm.display.shift, done = false;
try { try {
if (cm.isReadOnly()) cm.state.suppressEdits = true; if (isReadOnly(cm)) cm.state.suppressEdits = true;
if (dropShift) cm.display.shift = false; if (dropShift) cm.display.shift = false;
done = bound(cm) != Pass; done = bound(cm) != Pass;
} finally { } finally {
...@@ -4262,13 +4178,12 @@ ...@@ -4262,13 +4178,12 @@
// right-click take effect on it. // right-click take effect on it.
function onContextMenu(cm, e) { function onContextMenu(cm, e) {
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
if (signalDOMEvent(cm, e, "contextmenu")) return;
cm.display.input.onContextMenu(e); cm.display.input.onContextMenu(e);
} }
function contextMenuInGutter(cm, e) { function contextMenuInGutter(cm, e) {
if (!hasHandler(cm, "gutterContextMenu")) return false; if (!hasHandler(cm, "gutterContextMenu")) return false;
return gutterEvent(cm, e, "gutterContextMenu", false); return gutterEvent(cm, e, "gutterContextMenu", false, signal);
} }
// UPDATING // UPDATING
...@@ -4816,9 +4731,10 @@ ...@@ -4816,9 +4731,10 @@
function findPosH(doc, pos, dir, unit, visually) { function findPosH(doc, pos, dir, unit, visually) {
var line = pos.line, ch = pos.ch, origDir = dir; var line = pos.line, ch = pos.ch, origDir = dir;
var lineObj = getLine(doc, line); var lineObj = getLine(doc, line);
var possible = true;
function findNextLine() { function findNextLine() {
var l = line + dir; 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; line = l;
return lineObj = getLine(doc, l); return lineObj = getLine(doc, l);
} }
...@@ -4828,16 +4744,14 @@ ...@@ -4828,16 +4744,14 @@
if (!boundToLine && findNextLine()) { if (!boundToLine && findNextLine()) {
if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
else ch = dir < 0 ? lineObj.text.length : 0; else ch = dir < 0 ? lineObj.text.length : 0;
} else return false } else return (possible = false);
} else ch = next; } else ch = next;
return true; return true;
} }
if (unit == "char") { if (unit == "char") moveOnce();
moveOnce() else if (unit == "column") moveOnce(true);
} else if (unit == "column") { else if (unit == "word" || unit == "group") {
moveOnce(true)
} else if (unit == "word" || unit == "group") {
var sawType = null, group = unit == "group"; var sawType = null, group = unit == "group";
var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
for (var first = true;; first = false) { for (var first = true;; first = false) {
...@@ -4857,8 +4771,8 @@ ...@@ -4857,8 +4771,8 @@
if (dir > 0 && !moveOnce(!first)) break; if (dir > 0 && !moveOnce(!first)) break;
} }
} }
var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true); var result = skipAtomic(doc, Pos(line, ch), origDir, true);
if (!cmp(pos, result)) result.hitSide = true; if (!possible) result.hitSide = true;
return result; return result;
} }
...@@ -5150,7 +5064,7 @@ ...@@ -5150,7 +5064,7 @@
execCommand: function(cmd) { execCommand: function(cmd) {
if (commands.hasOwnProperty(cmd)) if (commands.hasOwnProperty(cmd))
return commands[cmd].call(null, this); return commands[cmd](this);
}, },
triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
...@@ -5245,7 +5159,6 @@ ...@@ -5245,7 +5159,6 @@
signal(this, "overwriteToggle", this, this.state.overwrite); signal(this, "overwriteToggle", this, this.state.overwrite);
}, },
hasFocus: function() { return this.display.input.getField() == activeElt(); }, hasFocus: function() { return this.display.input.getField() == activeElt(); },
isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); },
scrollTo: methodOp(function(x, y) { scrollTo: methodOp(function(x, y) {
if (x != null || y != null) resolveScrollToPos(this); if (x != null || y != null) resolveScrollToPos(this);
...@@ -5443,12 +5356,11 @@ ...@@ -5443,12 +5356,11 @@
cm.display.disabled = true; cm.display.disabled = true;
} else { } else {
cm.display.disabled = false; 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("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
option("dragDrop", true, dragDropChanged); option("dragDrop", true, dragDropChanged);
option("allowDropFileTypes", null);
option("cursorBlinkRate", 530); option("cursorBlinkRate", 530);
option("cursorScrollMargin", 0); option("cursorScrollMargin", 0);
...@@ -5753,8 +5665,8 @@ ...@@ -5753,8 +5665,8 @@
var range = cm.listSelections()[i]; var range = cm.listSelections()[i];
cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input"); cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
cm.indentLine(range.from().line + 1, null, true); cm.indentLine(range.from().line + 1, null, true);
}
ensureCursorVisible(cm); ensureCursorVisible(cm);
}
}); });
}, },
toggleOverwrite: function(cm) {cm.toggleOverwrite();} toggleOverwrite: function(cm) {cm.toggleOverwrite();}
...@@ -6682,7 +6594,7 @@ ...@@ -6682,7 +6594,7 @@
parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); 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) { function addLineWidget(doc, handle, node, options) {
...@@ -6871,9 +6783,7 @@ ...@@ -6871,9 +6783,7 @@
function getLineStyles(cm, line, updateFrontier) { function getLineStyles(cm, line, updateFrontier) {
if (!line.styles || line.styles[0] != cm.state.modeGen) { if (!line.styles || line.styles[0] != cm.state.modeGen) {
var state = getStateBefore(cm, lineNo(line)); var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state);
line.stateAfter = state;
line.styles = result.styles; line.styles = result.styles;
if (result.classes) line.styleClasses = result.classes; if (result.classes) line.styleClasses = result.classes;
else if (line.styleClasses) line.styleClasses = null; else if (line.styleClasses) line.styleClasses = null;
...@@ -6890,7 +6800,7 @@ ...@@ -6890,7 +6800,7 @@
var stream = new StringStream(text, cm.options.tabSize); var stream = new StringStream(text, cm.options.tabSize);
stream.start = stream.pos = startAt || 0; stream.start = stream.pos = startAt || 0;
if (text == "") callBlankLine(mode, state); if (text == "") callBlankLine(mode, state);
while (!stream.eol()) { while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
readToken(mode, stream, state); readToken(mode, stream, state);
stream.start = stream.pos; stream.start = stream.pos;
} }
...@@ -7008,7 +6918,7 @@ ...@@ -7008,7 +6918,7 @@
txt.setAttribute("cm-text", "\t"); txt.setAttribute("cm-text", "\t");
builder.col += tabWidth; builder.col += tabWidth;
} else if (m[0] == "\r" || m[0] == "\n") { } 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]); txt.setAttribute("cm-text", m[0]);
builder.col += 1; builder.col += 1;
} else { } else {
...@@ -7092,7 +7002,7 @@ ...@@ -7092,7 +7002,7 @@
if (nextChange == pos) { // Update current marker set if (nextChange == pos) { // Update current marker set
spanStyle = spanEndStyle = spanStartStyle = title = css = ""; spanStyle = spanEndStyle = spanStartStyle = title = css = "";
collapsed = null; nextChange = Infinity; collapsed = null; nextChange = Infinity;
var foundBookmarks = [], endStyles var foundBookmarks = [];
for (var j = 0; j < spans.length; ++j) { for (var j = 0; j < spans.length; ++j) {
var sp = spans[j], m = sp.marker; var sp = spans[j], m = sp.marker;
if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
...@@ -7103,9 +7013,9 @@ ...@@ -7103,9 +7013,9 @@
spanEndStyle = ""; spanEndStyle = "";
} }
if (m.className) spanStyle += " " + m.className; 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.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.title && !title) title = m.title;
if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
collapsed = sp; collapsed = sp;
...@@ -7113,17 +7023,14 @@ ...@@ -7113,17 +7023,14 @@
nextChange = sp.from; 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) { if (collapsed && (collapsed.from || 0) == pos) {
buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
collapsed.marker, collapsed.from == null); collapsed.marker, collapsed.from == null);
if (collapsed.to == null) return; if (collapsed.to == null) return;
if (collapsed.to == pos) collapsed = false; 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; if (pos >= len) break;
...@@ -7375,7 +7282,6 @@ ...@@ -7375,7 +7282,6 @@
this.id = ++nextDocId; this.id = ++nextDocId;
this.modeOption = mode; this.modeOption = mode;
this.lineSep = lineSep; this.lineSep = lineSep;
this.extend = false;
if (typeof text == "string") text = this.splitLines(text); if (typeof text == "string") text = this.splitLines(text);
updateDoc(this, {from: start, to: start, text: text}); updateDoc(this, {from: start, to: start, text: text});
...@@ -7463,11 +7369,10 @@ ...@@ -7463,11 +7369,10 @@
extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
}), }),
extendSelections: docMethodOp(function(heads, options) { extendSelections: docMethodOp(function(heads, options) {
extendSelections(this, clipPosArray(this, heads), options); extendSelections(this, clipPosArray(this, heads, options));
}), }),
extendSelectionsBy: docMethodOp(function(f, options) { extendSelectionsBy: docMethodOp(function(f, options) {
var heads = map(this.sel.ranges, f); extendSelections(this, map(this.sel.ranges, f), options);
extendSelections(this, clipPosArray(this, heads), options);
}), }),
setSelections: docMethodOp(function(ranges, primary, options) { setSelections: docMethodOp(function(ranges, primary, options) {
if (!ranges.length) return; if (!ranges.length) return;
...@@ -7592,7 +7497,7 @@ ...@@ -7592,7 +7497,7 @@
removeLineWidget: function(widget) { widget.clear(); }, removeLineWidget: function(widget) { widget.clear(); },
markText: function(from, to, options) { 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) { setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
...@@ -8153,30 +8058,24 @@ ...@@ -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) { var off = CodeMirror.off = function(emitter, type, f) {
if (emitter.removeEventListener) if (emitter.removeEventListener)
emitter.removeEventListener(type, f, false); emitter.removeEventListener(type, f, false);
else if (emitter.detachEvent) else if (emitter.detachEvent)
emitter.detachEvent("on" + type, f); emitter.detachEvent("on" + type, f);
else { else {
var handlers = getHandlers(emitter, type, false) var arr = emitter._handlers && emitter._handlers[type];
for (var i = 0; i < handlers.length; ++i) if (!arr) return;
if (handlers[i] == f) { handlers.splice(i, 1); break; } 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 signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
var handlers = getHandlers(emitter, type, true) var arr = emitter._handlers && emitter._handlers[type];
if (!handlers.length) return; if (!arr) return;
var args = Array.prototype.slice.call(arguments, 2); 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; var orphanDelayedCallbacks = null;
...@@ -8189,8 +8088,8 @@ ...@@ -8189,8 +8088,8 @@
// them to be executed when the last operation ends, or, if no // them to be executed when the last operation ends, or, if no
// operation is active, when a timeout fires. // operation is active, when a timeout fires.
function signalLater(emitter, type /*, values...*/) { function signalLater(emitter, type /*, values...*/) {
var arr = getHandlers(emitter, type, false) var arr = emitter._handlers && emitter._handlers[type];
if (!arr.length) return; if (!arr) return;
var args = Array.prototype.slice.call(arguments, 2), list; var args = Array.prototype.slice.call(arguments, 2), list;
if (operationGroup) { if (operationGroup) {
list = operationGroup.delayedCallbacks; list = operationGroup.delayedCallbacks;
...@@ -8230,7 +8129,8 @@ ...@@ -8230,7 +8129,8 @@
} }
function hasHandler(emitter, type) { 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 // Add on and off methods to a constructor's prototype, to make
...@@ -8277,7 +8177,7 @@ ...@@ -8277,7 +8177,7 @@
// The inverse of countColumn -- find the offset that corresponds to // The inverse of countColumn -- find the offset that corresponds to
// a particular column. // a particular column.
var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) { function findColumn(string, goal, tabSize) {
for (var pos = 0, col = 0;;) { for (var pos = 0, col = 0;;) {
var nextTab = string.indexOf("\t", pos); var nextTab = string.indexOf("\t", pos);
if (nextTab == -1) nextTab = string.length; if (nextTab == -1) nextTab = string.length;
...@@ -8570,16 +8470,14 @@ ...@@ -8570,16 +8470,14 @@
// KEY NAMES // KEY NAMES
var keyNames = CodeMirror.keyNames = { var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
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", 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", 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 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() { (function() {
// Number keys // Number keys
for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
...@@ -8884,7 +8782,7 @@ ...@@ -8884,7 +8782,7 @@
// THE END // THE END
CodeMirror.version = "5.11.0"; CodeMirror.version = "5.5.0";
return CodeMirror; return CodeMirror;
}); });
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
Annotation.prototype.computeScale = function() { Annotation.prototype.computeScale = function() {
var cm = this.cm; var cm = this.cm;
var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) / var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
cm.getScrollerElement().scrollHeight cm.heightAtLine(cm.lastLine() + 1, "local");
if (hScale != this.hScale) { if (hScale != this.hScale) {
this.hScale = hScale; this.hScale = hScale;
return true; return true;
...@@ -100,9 +100,6 @@ ...@@ -100,9 +100,6 @@
elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: " elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
+ (top + this.buttonHeight) + "px; height: " + height + "px"; + (top + this.buttonHeight) + "px; height: " + height + "px";
elt.className = this.options.className; elt.className = this.options.className;
if (ann.id) {
elt.setAttribute("annotation-id", ann.id);
}
} }
this.div.textContent = ""; this.div.textContent = "";
this.div.appendChild(frag); this.div.appendChild(frag);
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
query.lastIndex = stream.pos; query.lastIndex = stream.pos;
var match = query.exec(stream.string); var match = query.exec(stream.string);
if (match && match.index == stream.pos) { if (match && match.index == stream.pos) {
stream.pos += match[0].length || 1; stream.pos += match[0].length;
return "searching"; return "searching";
} else if (match) { } else if (match) {
stream.pos = match.index; stream.pos = match.index;
...@@ -76,21 +76,11 @@ ...@@ -76,21 +76,11 @@
else if (confirm(shortText)) fs[0](); 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) { function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/); var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
if (isRE) { if (isRE) {
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); } try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
catch(e) {} // Not a regular expression after all, do a string search catch(e) {} // Not a regular expression after all, do a string search
} else {
query = parseString(query)
} }
if (typeof query == "string" ? query == "" : query.test("")) if (typeof query == "string" ? query == "" : query.test(""))
query = /x^/; query = /x^/;
...@@ -117,19 +107,11 @@ ...@@ -117,19 +107,11 @@
if (state.query) return findNext(cm, rev); if (state.query) return findNext(cm, rev);
var q = cm.getSelection() || state.lastQuery; var q = cm.getSelection() || state.lastQuery;
if (persistent && cm.openDialog) { if (persistent && cm.openDialog) {
var hiding = null
persistentDialog(cm, queryDialog, q, function(query, event) { persistentDialog(cm, queryDialog, q, function(query, event) {
CodeMirror.e_stop(event); CodeMirror.e_stop(event);
if (!query) return; if (!query) return;
if (query != state.queryText) startSearch(cm, state, query); if (query != state.queryText) startSearch(cm, state, query);
if (hiding) hiding.style.opacity = 1 findNext(cm, event.shiftKey);
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
})
}); });
} else { } else {
dialog(cm, queryDialog, "Search for:", q, function(query) { dialog(cm, queryDialog, "Search for:", q, function(query) {
...@@ -142,7 +124,7 @@ ...@@ -142,7 +124,7 @@
} }
} }
function findNext(cm, rev, callback) {cm.operation(function() { function findNext(cm, rev) {cm.operation(function() {
var state = getSearchState(cm); var state = getSearchState(cm);
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
if (!cursor.find(rev)) { if (!cursor.find(rev)) {
...@@ -152,7 +134,6 @@ ...@@ -152,7 +134,6 @@
cm.setSelection(cursor.from(), cursor.to()); cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20); cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
state.posFrom = cursor.from(); state.posTo = cursor.to(); state.posFrom = cursor.from(); state.posTo = cursor.to();
if (callback) callback(cursor.from(), cursor.to())
});} });}
function clearSearch(cm) {cm.operation(function() { function clearSearch(cm) {cm.operation(function() {
...@@ -165,11 +146,18 @@ ...@@ -165,11 +146,18 @@
});} });}
var replaceQueryDialog = 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 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() { cm.operation(function() {
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
if (typeof query != "string") { if (typeof query != "string") {
...@@ -178,19 +166,6 @@ ...@@ -178,19 +166,6 @@
} else cursor.replace(text); } 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 { } else {
clearSearch(cm); clearSearch(cm);
var cursor = getSearchCursor(cm, query, cm.getCursor()); var cursor = getSearchCursor(cm, query, cm.getCursor());
...@@ -204,8 +179,7 @@ ...@@ -204,8 +179,7 @@
cm.setSelection(cursor.from(), cursor.to()); cm.setSelection(cursor.from(), cursor.to());
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
confirmDialog(cm, doReplaceConfirm, "Replace?", confirmDialog(cm, doReplaceConfirm, "Replace?",
[function() {doReplace(match);}, advance, [function() {doReplace(match);}, advance]);
function() {replaceAll(cm, query, text)}]);
}; };
var doReplace = function(match) { var doReplace = function(match) {
cursor.replace(typeof query == "string" ? text : 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') { ...@@ -666,137 +666,81 @@ if (typeof document.contains !== 'function') {
} }
} }
;/*! RenderJs */ ;/*! RenderJs */
/*global console*/
/*jslint nomen: true*/ /*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. * renderJs - Generic Gadget library renderer.
* http://www.renderjs.org/documentation * http://www.renderjs.org/documentation
*/ */
(function (document, window, RSVP, DOMParser, Channel, MutationObserver, (function (document, window, RSVP, DOMParser, Channel, MutationObserver,
Node) { Node, FileReader, Blob) {
"use strict"; "use strict";
var gadget_model_dict = {}, function readBlobAsDataURL(blob) {
javascript_registration_dict = {}, var fr = new FileReader();
stylesheet_registration_dict = {}, return new RSVP.Promise(function (resolve, reject) {
gadget_loading_klass, fr.addEventListener("load", function (evt) {
loading_klass_promise, resolve(evt.target.result);
renderJS, });
Monitor; fr.addEventListener("error", reject);
fr.readAsDataURL(blob);
///////////////////////////////////////////////////////////////// }, function () {
// Helper functions fr.abort();
///////////////////////////////////////////////////////////////// });
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 optionalize(key, value, dict) { function ajax(url) {
var key_list = key.split("."), var xhr;
kk, function resolver(resolve, reject) {
i; function handler() {
for (i = 0; i < key_list.length; i += 1) { try {
kk = key_list[i]; if (xhr.readyState === 0) {
if (i === key_list.length - 1) { // UNSENT
dict[kk] = value; 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 { } else {
if (!dict.hasOwnProperty(kk)) { resolve(xhr);
dict[kk] = {};
} }
dict = dict[kk];
} }
} catch (e) {
reject(e);
} }
} }
subhashes = hash.split('&'); xhr = new XMLHttpRequest();
for (index in subhashes) { xhr.open("GET", url);
if (subhashes.hasOwnProperty(index)) { xhr.onreadystatechange = handler;
subhash = subhashes[index]; xhr.setRequestHeader('Accept', 'text/html');
if (subhash !== '') { xhr.withCredentials = true;
keyvalue = subhash.split('='); xhr.send();
if (keyvalue.length === 2) {
optionalize(decodeURIComponent(keyvalue[0]),
decodeURIComponent(keyvalue[1]),
options);
}
}
}
} }
if (gadget.render !== undefined) { function canceller() {
return gadget.render(options); if ((xhr !== undefined) && (xhr.readyState !== xhr.DONE)) {
xhr.abort();
} }
} }
return new RSVP.Promise(resolver, canceller);
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;
} }
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) { function removeHash(url) {
var index = url.indexOf('#'); var index = url.indexOf('#');
if (index > 0) { if (index > 0) {
...@@ -1126,8 +1070,6 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1126,8 +1070,6 @@ function loopEventListener(target, type, useCapture, callback) {
}; };
RenderJSGadget.declareAcquiredMethod("aq_reportServiceError", RenderJSGadget.declareAcquiredMethod("aq_reportServiceError",
"reportServiceError"); "reportServiceError");
RenderJSGadget.declareAcquiredMethod("aq_pleasePublishMyState",
"pleasePublishMyState");
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// RenderJSGadget.allowPublicAcquisition // RenderJSGadget.allowPublicAcquisition
...@@ -1148,22 +1090,6 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -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 // RenderJSEmbeddedGadget
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -1350,6 +1276,33 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -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 // RenderJSGadget.declareGadget
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -1385,6 +1338,8 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1385,6 +1338,8 @@ function loopEventListener(target, type, useCapture, callback) {
method = privateDeclarePublicGadget; method = privateDeclarePublicGadget;
} else if (options.sandbox === "iframe") { } else if (options.sandbox === "iframe") {
method = privateDeclareIframeGadget; method = privateDeclareIframeGadget;
} else if (options.sandbox === "dataurl") {
method = privateDeclareDataUrlGadget;
} else { } else {
throw new Error("Unsupported sandbox options '" + throw new Error("Unsupported sandbox options '" +
options.sandbox + "'"); options.sandbox + "'");
...@@ -1497,8 +1452,7 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1497,8 +1452,7 @@ function loopEventListener(target, type, useCapture, callback) {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.getAbsoluteURL = function (url, base_url) { renderJS.getAbsoluteURL = function (url, base_url) {
var doc, base, link, var doc, base, link,
html = "<!doctype><html><head></head></html>", html = "<!doctype><html><head></head></html>";
isAbsoluteOrDataURL = new RegExp('^(?:[a-z]+:)?//|data:', 'i');
if (url && base_url && !isAbsoluteOrDataURL.test(url)) { if (url && base_url && !isAbsoluteOrDataURL.test(url)) {
doc = (new DOMParser()).parseFromString(html, 'text/html'); doc = (new DOMParser()).parseFromString(html, 'text/html');
...@@ -1576,10 +1530,9 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1576,10 +1530,9 @@ function loopEventListener(target, type, useCapture, callback) {
// renderJS.declareGadgetKlass // renderJS.declareGadgetKlass
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
renderJS.declareGadgetKlass = function (url) { renderJS.declareGadgetKlass = function (url) {
var result, var result;
xhr;
function parse() { function parse(xhr) {
var tmp_constructor, var tmp_constructor,
key, key,
parsed_html; parsed_html;
...@@ -1604,8 +1557,6 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1604,8 +1557,6 @@ function loopEventListener(target, type, useCapture, callback) {
tmp_constructor.prototype.constructor = tmp_constructor; tmp_constructor.prototype.constructor = tmp_constructor;
tmp_constructor.prototype.__path = url; tmp_constructor.prototype.__path = url;
tmp_constructor.prototype.__acquired_method_dict = {}; 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/HTML_in_XMLHttpRequest
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser // https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM // https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
...@@ -1627,50 +1578,18 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1627,50 +1578,18 @@ function loopEventListener(target, type, useCapture, callback) {
return gadget_model_dict[url]; 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)) { if (gadget_model_dict.hasOwnProperty(url)) {
// Return klass object if it already exists // Return klass object if it already exists
result = RSVP.resolve(gadget_model_dict[url]); result = RSVP.resolve(gadget_model_dict[url]);
} else { } else {
// Fetch the HTML page and parse it // 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; return result;
}; };
...@@ -1696,10 +1615,9 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1696,10 +1615,9 @@ function loopEventListener(target, type, useCapture, callback) {
required_js_list: [] required_js_list: []
}, },
i, i,
element, element;
isAbsoluteURL = new RegExp('^(?:[a-z]+:)?//', 'i');
if (!url || !isAbsoluteURL.test(url)) { if (!url || !isAbsoluteOrDataURL.test(url)) {
throw new Error("The url should be absolute: " + url); throw new Error("The url should be absolute: " + url);
} }
...@@ -1749,39 +1667,6 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1749,39 +1667,6 @@ function loopEventListener(target, type, useCapture, callback) {
// Bootstrap process. Register the self gadget. // 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() { function bootstrap() {
var url = removeHash(window.location.href), var url = removeHash(window.location.href),
tmp_constructor, tmp_constructor,
...@@ -1808,26 +1693,6 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1808,26 +1693,6 @@ function loopEventListener(target, type, useCapture, callback) {
}, },
reportServiceError: function (param_list) { reportServiceError: function (param_list) {
letsCrash(param_list[0]); 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 // Stop acquisition on the last acquisition gadget
...@@ -1869,10 +1734,6 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1869,10 +1734,6 @@ function loopEventListener(target, type, useCapture, callback) {
// Create the root gadget instance and put it in the loading stack // Create the root gadget instance and put it in the loading stack
root_gadget = new gadget_model_dict[url](); root_gadget = new gadget_model_dict[url]();
tmp_constructor.declareService(function () {
return listenHashChange(this);
});
setAqParent(root_gadget, last_acquisition_gadget); setAqParent(root_gadget, last_acquisition_gadget);
} else { } else {
...@@ -1959,8 +1820,6 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -1959,8 +1820,6 @@ function loopEventListener(target, type, useCapture, callback) {
} }
tmp_constructor.prototype.__acquired_method_dict = {}; tmp_constructor.prototype.__acquired_method_dict = {};
tmp_constructor.allowPublicAcquisition("pleasePublishMyState",
pleasePublishMyState);
gadget_loading_klass = tmp_constructor; gadget_loading_klass = tmp_constructor;
function init() { function init() {
...@@ -2113,9 +1972,6 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -2113,9 +1972,6 @@ function loopEventListener(target, type, useCapture, callback) {
//we consider current gadget is parent gadget //we consider current gadget is parent gadget
//redifine last acquisition gadget //redifine last acquisition gadget
iframe_top_gadget = true; iframe_top_gadget = true;
tmp_constructor.declareService(function () {
return listenHashChange(this);
});
setAqParent(root_gadget, last_acquisition_gadget); setAqParent(root_gadget, last_acquisition_gadget);
} else { } else {
throw error; throw error;
...@@ -2164,4 +2020,5 @@ function loopEventListener(target, type, useCapture, callback) { ...@@ -2164,4 +2020,5 @@ function loopEventListener(target, type, useCapture, callback) {
} }
bootstrap(); bootstrap();
}(document, window, RSVP, DOMParser, Channel, MutationObserver, Node)); }(document, window, RSVP, DOMParser, Channel, MutationObserver, Node,
\ No newline at end of file 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