Lively Kernel canvas
// Author: Philip Weaver
// Email: philip@philmaker.com
// Comments in right margin might not line up unless using Verdana 10 Bold on Mac OS X, TextWrangler
// I am getting more comfortable with Lively and I need to review and tidy up a bit
// particularly how I may sometimes be incorrectly passing bogus shapes, rectangles, extents, and positions
// also I know I should probably be using styling notation more than calling style methods - I'll fix that later
//Config.modulesOnWorldLoad.push('GridLayout.js');
Object.subclass('philmaker.foundation.Utility', {
initialize : function($super) {
$super();
}
});
philmaker.foundation.Utility.getSubmorphByClass = function(morph, clazz) { // could instead use Morph.addMethods
// use Namespace.addMethods ???
var result = null;
morph.withAllSubmorphsDo(function() { // not sure what the second parameter 'rest' does (does it rest?)
if (result == null) {
if (this instanceof clazz) {
result = this;
}
}
});
return result;
};
philmaker.foundation.Utility.getSubmorphsByClass = function(morph, clazz) {
var results = [];
morph.withAllSubmorphsDo(function() {
if (this instanceof clazz) {
results.push(this);
}
});
return results;
};
philmaker.foundation.Utility.getSubmorphByName = function(morph, name) {
var result = null;
morph.withAllSubmorphsDo(function() {
if (result == null) {
if ((this.name) && (this.name == name)) {
result = this;
}
}
});
return result;
};
philmaker.foundation.Utility.getOpenLocation = function() {
var point = WorldMorph.current().lastMenuLocation;
if (! point) {
var point = WorldMorph.current().firstHand().getPosition();
}
return point;
};
philmaker.foundation.Utility.getSelectedMorphs = function() {
var results = [];
var world = WorldMorph.current();
world.withAllSubmorphsDo(function() {
if (this instanceof SelectionMorph) {
var selectionMorph = this;
selectionMorph.selectedMorphs.forEach(function(morph) {
results.push(morph);
});
}
});
return results;
};
philmaker.foundation.Utility.createCodeNoteWithFunctionBody = function(func, comments) { // todo: consider looking up from the Class browser instead
var source = func.toString();
if (true) {
if (true) {
source = source.replace('function () \n{', '');
} else {
source = source.replace(new RegExp('function\s*\(\)\s*'), '');
}
source = source.substr(0, source.length - 2);
//source = source.replace('\n ', '\nxxxxx', ['g']);
source = source.replace(new RegExp('\n.{2}', ['g']), '\n'); // instead of . should be able to use /s ???
var pattern = new RegExp('\n.*{', ['g']);
if (false) {
pattern = new RegExp('\s*\n.*{', ['g']); // prefer to correct the space padding - for example, appearing after 'try'
}
source = source.replace(pattern, ' {');
}
var codeNote = new philmaker.playground.RunnableCodeNote();
var textMorph = philmaker.foundation.Utility.getSubmorphByClass(codeNote, TextMorph);
var text = source;
if (comments) {
text = comments + text;
}
textMorph.setTextString(text);
return codeNote;
};
philmaker.foundation.Utility.revertWorldToPreviousRevision = function(filename) { // example: pweaver-widgets.xhtml
// http://livelykernel.sunlabs.com/repository/lively-wiki/!svn/bc/REVISIONID/PAGE-NAME.xhtml
var revisions = philmaker.foundation.Utility.findRevisions(filename);
var revision = revisions[1];
console.log('previous revision for: ' + filename + ' is: ' + revision);
philmaker.foundation.Utility.revertToRevision(filename, revision);
console.log('finished reverting file');
};
philmaker.foundation.Utility.findRevisions = function(filename) {
var url = URL.source.getDirectory();
var flieDirectory = new FileDirectory(url);
var svnResource = new SVNResource(url.toString(), Record.newPlainInstance({
URL : url + filename,
Metadata : null,
HeadRevision : null
}));
svnResource.fetchMetadata(true, null);
var timestamps = svnResource.getMetadata();
var revisions = timestamps.collect(function(each) {
return each.toString().match(/.*Revision (.*)/)[1]
});
return revisions;
};
philmaker.foundation.Utility.revertToRevision = function(filename, revision) {
var flieDirectory = new FileDirectory(URL.source);
var content = flieDirectory.fileContent(filename, revision);
flieDirectory.writeFileNamed(filename, content);
};
TextMorph.subclass('philmaker.foundation.TextMorph', { // todo: allow setting of font family alternates
initialize : function($super, rectangle, text) {
$super(rectangle, text);
},
setBold : function(bold) {
var style = 'unbold';
if (bold) {
style = 'bold';
}
this.setSelectionRange(0, this.textString.length);
this.emphasizeBoldItalic({
style : style
});
this.setSelectionRange(0, 0);
},
setAlignment : function(alignment) {
try {
console.log('philmaker.foundation.TextMorph.setAlignment');
this.setSelectionRange(0, this.textString.length);
this.emphasizeSelection({
align : alignment
});
} catch (e) {
console.log('philmaker.foundation.TextMorph.setAlignment error: ' + e);
}
},
/*
setAlignment : function(alignment) {
try {
console.log('philmaker.foundation.TextMorph.setAlignment');
console.log('alignment: ' + alignment);
console.log('this.textString: ' + this.textString);
this.setSelectionRange(0, this.textString.length);
console.log('after setSelectionRange');
if (this.hasNullSelection()) { // next several lines of code are from TextMorph.emphasizeSelection
return;
}
var text = new lively.Text.Text(this.textString, this.textStyle); // changed thisModule.Text to lively.Text.Text (from TextMorph.emphasizeSelection)
text.emphasize(alignment, 0, this.textString.length - 2);
this.textStyle = text.style;
//this.composeAfterEdits();
} catch (e) {
console.log('philmaker.foundation.TextMorph.setAlignment error: ' + e);
}
},
*/
onKeyPress : function($super, event) { // todo: I actually need to patch TextMorph.onKeyPress
// investigate being able to patch with a wrapper around the original method
if (! this.acceptInput) return true;
var result = $super(event);
if (! event.isMetaDown() && ! event.isCtrlDown()) return false;
if (event.getKeyChar().toLowerCase() === 'a' || event.getKeyCode() === 97) { // todo: also handle undo/redo
if (false) {
this.doSelectAll(true); // I don't like this behavior inside doSelectAll: this.charsTyped.length
} else { // so I'm not using it
this.setSelectionRange(0, this.textString.length);
}
event.stop();
return true;
} else {
return result;
}
},
isDoubleClick : function() {
},
onMouseDown : function($super, evt) { // fixing in my subclass first and later will patch TextMorph mouse handlers
// goal is double-click drag word accumulation and triple-click drag line accumulation
var lastClick = this.lastClick;
this.lastClick = new Date();
$super(evt);
if (lastClick != null) {
if (false) {
console.log('this click: ' + this.lastClick.getTime());
console.log('last click: ' + lastClick.getTime());
console.log('delta: ' + (this.lastClick.getTime() - lastClick.getTime()));
}
if (this.lastClick.getTime() - lastClick.getTime() < 300) {
if (this.selectionRange[0] == 0 || this.selectionRange[0] == this.textString.length) {
this.setSelectionRange(0, this.textString.length);
} else {
this.selectionRange = this.locale.selectWord(this.textString, this.selectionRange[0]);
this.selectionPivot = this.selectionRange[0];
}
this.setSelection(this.getSelectionString());
this.drawSelection();
}
}
return true;
},
extendSelectionEvt : function(evt) {
var charIx = this.charOfPoint(this.localize(evt.mousePoint));
if (charIx < 0) {
return;
}
var oldSelectionRange = this.selectionRange;
var oldSelectionPivot = this.selectionPivot;
var selectionRange = this.locale.selectWord(this.textString, charIx);
this.setSelectionRange(oldSelectionPivot, selectionRange[1] + 1); // fixme: haven't studied why I'm needing + 1 (pjw)
},
onMouseUp : function(evt) {
this.isSelecting = false;
if ((this.selectionRange[1] != this.selectionRange[0] - 1) ||
(this.priorSelection[1] != this.priorSelection[0] - 1) ||
(this.selectionRange[0] != this.priorSelection[0]) ) {
this.previousSelection = this.priorSelection;
return;
}
}
});
Morph.subclass('philmaker.foundation.BasicMorph', { // just a base class for fixed morphs
// not yet employed - just created this class as a reminder
initialize : function($super, shape) {
$super(shape);
this.openForDragAndDrop = false;
this.suppressHandles = true;
this.setFillOpacity(0.0);
this.setStrokeOpacity(0.0);
}
});
Object.subclass('philmaker.foundation.Insets', {
initialize : function(top, left, bottom, right) {
this.top = top;
this.left = left;
this.bottom = bottom;
this.right = right;
}
});
BoxMorph.subclass('philmaker.foundation.BoxLayoutMorph', { // fixme: need to convert this into a LayoutManager
// this is sort of quick and dirty because I can't get existing layouts to do exactly I want
openForDragAndDrop : false, // fixme: need to provide clipping or submorph resizing; example: so TextMorphs do not extend too far
initialize : function($super, rectangle) {
$super(rectangle);
this.orientation = 'horizontal';
this.suppressHandles = true;
this.setFillOpacity(0.0);
this.setBorderWidth(0);
},
setOrientation : function(orientation) {
this.orientation = orientation;
},
addMorph : function($super, morph, constraints) { // so I can pass in constaints
if (constraints) {
morph.constraints = constraints;
this.packageConstraints(morph);
}
return $super(morph);
},
adjustForNewBounds : function ($super) { // fixme: this should actually all be in a LayoutManager
// allow for passing integers instead of decimals (for fixed width)
$super(); // fixme: this does not appear to resize correctly from corners other that southeast
// also need to prevent TextMorphs from overlapping
var position = this.getPosition();
var extent = this.getExtent();
var i = 0;
var offset = 0;
var boxLayoutMorph = this;
this.submorphs.forEach(function(submorph) {
boxLayoutMorph.unpackageConstraints(submorph);
});
if (this.orientation == 'vertical') { // fixme: need to combine vertical and horizontal handling into one abstract case
var flexibleExtent = extent.y; // also make sure features of each case are in sync before doing so
this.submorphs.forEach(function(submorph) {
if (submorph.constraints) {
var weight = submorph.constraints.weight;
if (weight > 1) {
flexibleExtent = flexibleExtent - weight;
}
}
});
this.submorphs.forEach(function(submorph) {
if (submorph.constraints) {
var weight = submorph.constraints.weight;
var margin = submorph.constraints.margin;
var alignX = submorph.constraints.alignX;
var existingExtent = submorph.getExtent();
var newPosition = pt(margin.left, offset + margin.top);
submorph.setPosition(newPosition); // IMPORTANT: need to heed the preferred height of the morph above it (TextMorph)
var calculatedExtent;
if (weight <= 1) {
calculatedExtent = pt(extent.x - (margin.left + margin.right), (flexibleExtent * weight) - (margin.top + margin.bottom));
} else {
calculatedExtent = pt(extent.x - (margin.left + margin.right), weight - (margin.top + margin.bottom));
}
if (i == 1) {
calculatedExtent.y = calculatedExtent.y - 1; // so the lower handle is usable, FIXME: need to do this for the last not the first
} // actually need to make sure that all corners are grabable
if (alignX == 'center') { // need to adjust the margins (but center within the margins)
var delta = (calculatedExtent.x - existingExtent.x) / 2;
newPosition.x = newPosition.x + delta;
submorph.setPosition(newPosition);
submorph.setExtent(calculatedExtent);
} else {
submorph.setExtent(calculatedExtent);
}
calculatedExtent = submorph.getExtent();
offset = offset + calculatedExtent.y + margin.top + margin.bottom;
i++;
}
});
} else {
var flexibleExtent = extent.x;
this.submorphs.forEach(function(submorph) {
if (submorph.constraints) {
var weight = submorph.constraints.weight;
if (weight > 1) {
flexibleExtent = flexibleExtent - weight;
}
}
});
this.submorphs.forEach(function(submorph) {
if (submorph.constraints) {
var weight = submorph.constraints.weight;
var margin = submorph.constraints.margin;
margin = new philmaker.foundation.Insets(margin.top, margin.left, margin.bottom, margin.right);
var alignX = submorph.constraints.alignX;
var existingExtent = submorph.getExtent();
var newPosition = pt(offset + margin.left, margin.top);
submorph.setPosition(newPosition);
var calculatedExtent;
if (weight <= 1) {
calculatedExtent = pt((flexibleExtent * weight) - (margin.left + margin.right), extent.y - (margin.top + margin.bottom));
} else {
// does not position correctly with a final fixed element : situation was RunnableCodeNoteControls
calculatedExtent = pt(weight - (margin.left + margin.right), extent.y - (margin.top + margin.bottom));
}
if (i == 1) {
calculatedExtent.x = calculatedExtent.x - 1; // so the lower handle is draggable, FIXME: should do this for the last not the first
} // might actually need to inset on each side (or some other Lively API solution)
if (alignX == 'center') { // need to adjust the margins (but center within the margins)
var delta = (calculatedExtent.x - existingExtent.x) / 2;
newPosition.x = newPosition.x + delta;
submorph.setPosition(newPosition);
submorph.setExtent(calculatedExtent);
} else {
submorph.setExtent(calculatedExtent);
}
offset = offset + calculatedExtent.x + margin.left + margin.right;
i++;
}
});
}
},
packageConstraints : function(morph) {
var constraints = morph.constraints;
var margin = morph.constraints.margin;
if (! margin) {
margin = new philmaker.foundation.Insets(0, 0, 0, 0);
}
constraints.margin = {
top : margin.top,
left : margin.left,
bottom : margin.bottom,
right : margin.right,
}
morph.layoutConstraints = JSON.serialize(constraints);
},
unpackageConstraints : function(morph) {
if (morph.layoutConstraints) {
morph.constraints = JSON.unserialize(morph.layoutConstraints);
}
}
});
Object.subclass('philmaker.foundation.BoxLayoutConstraints', { // object with chainable setter methods
initialize : function() {
}
});
Object.subclass('philmaker.foundation.GridLayoutConstraints', { // object with chainable setter methods
initialize : function() {
}
});
ImageMorph.subclass('philmaker.foundation.ImageMorph', { // provide an interface for changing the image source and hyperlinks url
// better = inspector which adds function interface
initialize : function($super, rectangle, imagePath) { // select function and it populates (last issued command on that function somehow)
$super(rectangle, imagePath);
this.setFillOpacity(0.0);
}
});
Morph.subclass('philmaker.foundation.RatingMorph', { // be able to customize the number of stars/bounds: maybe initially 1-20 max
// do an overlay perhaps 5 of 10
openForDragAndDrop: false, // investigate inspection by turnover = or maybe a drawer sliding out (actually why would this need inspection anyway?)
reshape : Functions.Null, // idea: allow partial fill of each star to act more like a slider
styleClass: [],
initialize : function($super) {
var rectangle = new Rectangle(400, 400, 236, 26);
$super(new lively.scene.Rectangle(rectangle)); // how to set/reset this after calling super?
this.setMaximum(10);
var color = Color.hsb(0.0, 0.0, 0.5);
this.setFill(color);
this.setFillOpacity(0.8);
this.shapeRoundEdgesBy(13);
this.litColor = Color.hsb(60, 1.0, 0.9);
this.unlitColor = Color.white;
var x = 8;
var y = 3;
var maximum = this.getMaximum();
for (var i = 0; i < maximum; i++) {
var ratingStarMorph = new philmaker.foundation.RatingStarMorph(i);
ratingStarMorph.setPosition(pt(x, y));
this.addMorph(ratingStarMorph);
x = x + 22;
}
this.setValue(1);
},
setMaximum : function(maximum) {
this.maximum = maximum;
},
getMaximum : function() {
return this.maximum;
},
setValue : function(value) {
this.value = value;
this.updateStars(this.value);
},
setTemporaryValue : function(temporaryValue) {
this.temporaryValue = temporaryValue;
this.updateStars(this.temporaryValue);
},
updateStars : function(value) {
this.submorphs.forEach(function(submorph) {
if (submorph.index < value) {
submorph.setLit(true);
} else {
submorph.setLit(false);
}
});
},
setLitColor : function(litColor) {
this.litColor = litColor;
this.setValue(this.value);
},
setUnlitColor : function(unlitColor) {
this.unlitColor = unlitColor;
this.setValue(this.value);
},
onMouseOut: function($super, event) {
this.setValue(this.value);
}
});
Morph.subclass('philmaker.foundation.RatingStarMorph', {
suppressHandles : true,
openForDragAndDrop : false,
styleClass : [],
handlesMouseDown : Functions.True,
initialize : function($super, index) {
this.index = index;
var vertices = this.createVertices(10, pt(0, 0), 180); // fixme: need to use radians correctly
$super(new lively.scene.Polygon(vertices));
this.setLit(false);
},
createVertices : function(radius, center, startAngle) {
var vertices = [];
var verticeCount = 10;
for (var i = 0; i <= verticeCount; i++) {
var a = startAngle + (2 * Math.PI / verticeCount * i);
var p = Point.polar(radius, a);
if (i % 2 == 0) {
p = p.scaleBy(0.45);
}
vertices.push(p.addPt(center));
}
return vertices;
},
setLit : function(lit) {
this.lit = lit;
if (this.owner) {
if (this.lit) {
this.setFill(this.owner.litColor);
} else {
this.setFill(this.owner.unlitColor);
}
}
},
isLit : function() {
return this.lit;
},
onMouseOver: function($super, event) {
this.owner.setTemporaryValue(this.index + 1);
},
onMouseDown : function($super, event) {
this.owner.setValue(this.index + 1);
},
reshape: Functions.Null
});
Morph.subclass('philmaker.foundation.InstantiationWidget', { // simple text field for making classes - it should list history (or initially just use up and down)
// make sure to use ... ? what?
openForDragAndDrop: false, // also float inside a shiny black round rect - actually use green for GO
styleClass: [], // use the word make in the widget
suppressHandles : true,
// pre-populate the history
initialize: function($super) {
// still place where the hand is - try to start drag
var rectangle = new Rectangle(150, 10, 500, 26); // or at least place somewhere non-covered
$super(new lively.scene.Rectangle(rectangle));
this.initializeHistory();
var color = Color.hsb(0.0, 0.0, 0.5);
color = Color.rgb(51, 212, 103);
this.setFill(color);
this.setFillOpacity(0.8);
this.shapeRoundEdgesBy(13);
this.label = new TextMorph(new Rectangle(0, 0, 50, 30), 'Create:');
this.label.beLabel();
this.label.setFontSize(16);
this.label.setTextColor(Color.white);
this.label.setFillOpacity(0.0);
this.label.setStrokeOpacity(0.0);
this.addMorph(this.label);
this.instantiationTextMorph = new philmaker.foundation.InstantiationTextMorph(this);
this.addMorph(this.instantiationTextMorph);
this.shouldCycleHistory = false;
},
initializeTransientState: function($super) {
$super();
this.initializeHistory();
},
initializePersistentState: function($super, shape) {
$super(shape);
this.initializeHistory();
},
initializeHistory : function() {
this.history = [
'philmaker.playground.WormholeMorph',
'philmaker.playground.BlogEntry',
'philmaker.playground.StructuredContent',
'philmaker.playground.ImageMorph',
'philmaker.playground.RatingMorph',
'philmaker.foundation.InstantiationWidget',
'philmaker.playground.StickyNote',
'philmaker.playground.ScrollableStickyNote',
'philmaker.playground.CodeNote',
'philmaker.playground.RunnableCodeNote'
];
this.historyIndex = 0;
},
nextHistoryItem : function() {
if (this.historyIndex < (this.history.length - 1)) {
this.historyIndex++;
this.instantiationTextMorph.setTextString(this.history[this.historyIndex]);
}
},
previousHistoryItem : function() {
if (this.historyIndex > 0) {
this.historyIndex--;
this.instantiationTextMorph.setTextString(this.history[this.historyIndex]);
}
},
isHistoryItem : function(string) {
if (this.history.indexOf(string) > -1) {
return true;
} else {
return false;
}
},
addHistoryItem : function(string) {
if (this.isHistoryItem(string)) {
this.removeHistoryItem(string);
}
this.history.unshift(string);
this.historyIndex = 0;
},
removeHistoryItem : function(string) {
var sReturn = string;
var index = this.history.indexOf(string);
if (index > -1) {
var string = this.history[index];
this.history.splice(index, 1);
sReturn = string;
} else {
sReturn = null;
}
return sReturn;
},
instantiateClass : function(string) {
try {
string = 'WorldMorph.currentWorld.addMorph(new ' + string + '());';
eval(string);
} catch (e) {
console.log('class instantiation failed');
console.log(e);
}
},
reshape: Functions.Null
});
philmaker.foundation.TextMorph.subclass('philmaker.foundation.InstantiationTextMorph', { // also use autocomplete
openForDragAndDrop: false,
styleClass: [],
suppressHandles : true,
initialize: function($super, instantiationWidget) {
this.instantiationWidget = instantiationWidget;
var rectangle = new Rectangle(70, 5, 420, 20);
$super(rectangle, this.instantiationWidget.history[0]);
this.setStrokeOpacity(0.0);
this.setFillOpacity(0.0);
this.setTextColor(Color.white);
this.setFontSize(16);
if (false) {
this.hasKeyboardFocus = false;
this.beInputLine(50);
this.autoAccept = true;
}
this.focusHaloBorderWidth = 0;
this.applyStyle({
borderWidth : 0,
fill : null,
wrapStyle : lively.Text.WrapStyle.None,
fontSize : 16,
padding : Rectangle.inset(0)
});
},
onKeyDown: function($super, event) {
var key = event.getKeyCode() || event.charCode;
if (key == Event.KEY_DOWN) {
this.instantiationWidget.nextHistoryItem();
event.stop();
} else if (key == Event.KEY_UP) {
this.instantiationWidget.previousHistoryItem();
event.stop();
} else if (key == Event.KEY_RETURN) {
var text = this.textString;
this.instantiationWidget.addHistoryItem(text);
this.instantiationWidget.instantiateClass(text);
event.stop();
} else {
$super(event);
}
},
reshape: Functions.Null
});
Morph.subclass('philmaker.foundation.CommandHistoryWidget', { // InstantiationWidget and PerformActionWidget ought to extend from this
initialize: function($super) {
$super();
}
});
Morph.subclass('philmaker.foundation.PerformActionWidget', {
initialize: function($super) {
$super();
}
});
LinkMorph.subclass('philmaker.foundation.LinkMorph', { // need to integrate WormholeMorph
// consider "Edit Name" in MorphMenu
// this code has been archived
});
var text = '';
text = text + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, ';
text = text + 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ';
text = text + 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ';
text = text + 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ';
text = text + 'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
philmaker.foundation.sampleText = text;
philmaker.foundation.layoutBorders = false;
namespace('philmaker.actions');
Object.subclass('philmaker.actions.BasicAction', {
enabled : false,
performAction : function() {
console.log('BasicAction.performAction');
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.RevertWorld', {
name : 'Revert Any World',
enabled : true,
initialize : function() {
},
performAction : function() {
var codeNote = new philmaker.playground.RunnableCodeNote();
var textMorph = philmaker.foundation.Utility.getSubmorphByClass(codeNote, TextMorph);
textMorph.setTextString('philmaker.foundation.Utility.revertWorldToPreviousRevision(\'pweaver-xxxxx.xhtml\')');
var point = philmaker.foundation.Utility.getOpenLocation();
codeNote.setPosition(point);
var extent = codeNote.getExtent();
extent.y = 70;
codeNote.setExtent(extent);
WorldMorph.current().addMorph(codeNote);
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.ViewChangeSet', {
name : 'View ChangeSet',
enabled : true,
initialize : function() {
},
performAction : function() {
require('lively.ide').toRun(function() {
console.log('ViewChangeSet.performAction lively.ide.SystemBrowser');
var browser = new lively.ide.SystemBrowser();
var point = philmaker.foundation.Utility.getOpenLocation();
browser.openIn(WorldMorph.current(), point);
browser.inPaneSelectNodeNamed('Pane1', 'ChangeSet for World');
try {
browser.inPaneSelectNodeNamed('Pane2', 'preamble');
} catch (e) {
console.log('Exception in ViewChangeSet.performAction (possibly no preamble to select)');
}
});
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.AlterWorldExtent', { // I know I should not be interacting with the canvas directly
// the alternative here is to use the scrollpanes which Lively provides
name : 'Alter World Extent',
enabled : true,
width : null, // 1440
height : 2000,
initialize : function() {
},
performAction : function() {
try {
this.alterWorldExtent();
} catch (e) {
console.log(e);
}
},
alterWorldExtent : function() {
var canvas = WorldMorph.current().canvas();
if (canvas) {
if ((this.width) && (this.width != null)) {
canvas.setAttribute('width', new String(this.width));
}
if ((this.height) && (this.height != null)) {
canvas.setAttribute('height', new String(this.height));
}
if (true) {
var width = canvas.getAttribute('width');
var height = canvas.getAttribute('height');
var extent = WorldMorph.current().getExtent();
if (! width.endsWith('%')) {
extent.x = width;
}
if (! height.endsWith('%')) {
extent.y = height;
}
this.overrideWorldMorphBounds(); // essential
var world = WorldMorph.current();
world.setExtent(extent);
}
}
},
convertPercentageToPixels: function() {
},
overrideWorldMorphBounds : function() {
WorldMorph.prototype.bounds = function() {
var extent = this.getExtent();
return new Rectangle(0, 0, extent.x, extent.y);
};
// overriding WorldMorph.bounds (only) to return the extent instead. This is the call stack:
// HandMorph.reallyHandleMouseEvent
// Morph.morphToReceiveEvent
// Morph.morphToGrabOrReceive
// Morph.fullContainsWorldPoint
// Morph.fullContainsPoint
// Morph.bounds (WorldMorph is returning the incorrect bounds even after calling setBounds)
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.MakeToolboxArray', {
name : 'Make Toolbox Array',
enabled : true,
initialize : function() {
},
performAction : function() {
var point = philmaker.foundation.Utility.getOpenLocation();
this.makeStack(point.copy());
point.x = point.x + 110;
this.makeStack(point);
},
makeStack : function(point) {
for (var i = 0; i < 5; i++) {
var morph = new philmaker.playground.ShelfBox();
morph.setPosition(point);
WorldMorph.current().addMorph(morph);
point.y = point.y + 110;
}
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.MakeRecordArray', {
name : 'Make Record Array',
enabled : true,
initialize : function() {
},
performAction : function() {
var specs = [{
kind : 'Task',
title : 'Take out the Trash',
rating : 8,
tags : ['Chores', 'Incomplete']
}, {
kind : 'Task',
title : 'Feed the Dog',
rating : 10,
tags : ['Chores', 'Complete']
}, {
kind : 'Task',
title : 'Water the Plants',
rating : 4,
tags : ['Chores', 'Incomplete']
}, {
kind : 'Task',
title : 'Fix the Car',
rating : 9,
tags : ['Errands', 'Incomplete']
}, {
kind : 'Task',
title : 'Buy More RAM',
rating : 2,
tags : ['Errands', 'Complete']
}, {
kind : 'Task',
title : 'Get a Haircut',
rating : 6,
tags : ['Errands', 'Incomplete']
}, {
kind : 'Contact',
title : 'Bullwinkle Moose',
rating : 1,
tags : ['Fictional'],
fields : [{
name : 'address',
value : 'Frostbite Falls, Minnesota'
}, {
name : 'phone',
value : '(218) 555-1212'
}]
}];
var point = philmaker.foundation.Utility.getOpenLocation();
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
var record = new philmaker.playground.RecordMorph(spec);
record.setPosition(point.copy());
WorldMorph.current().addMorph(record);
point.y = point.y + record.getExtent().y + 5;
}
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.MakeBadges', {
name : 'Make Badges',
enabled : true,
initialize : function() {
},
performAction : function() {
var specs = [{
text : 'Lively: Making the World Rounder',
enabled : true
}, {
text : 'Lively: Shape Your World',
enabled : true
}, {
text : 'Lively: Back to the Future',
enabled : true
}];
var point = philmaker.foundation.Utility.getOpenLocation();
for (var i = 0; i < specs.length; i++) {
var spec = specs[i];
if (spec.enabled) {
var badge = new philmaker.playground.BadgeMorph(spec.text);
record.setPosition(point.copy());
WorldMorph.current().addMorph(record);
point.y = point.y + record.getExtent().y + 5;
}
}
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.RunnableCodeNoteAction', {
name : 'Runnable Code Note Action',
enabled : true,
initialize : function() {
},
performAction : function() {
var codeNote = philmaker.foundation.Utility.createCodeNoteWithFunctionBody(this.script, this.comments());
var point = philmaker.foundation.Utility.getOpenLocation();
codeNote.setPosition(point);
var extent = codeNote.getExtent();
extent.y = 300;
codeNote.setExtent(extent);
WorldMorph.current().addMorph(codeNote);
},
comments : function() {
return null;
},
script : function() {
;
}
});
philmaker.actions.RunnableCodeNoteAction.subclass('philmaker.actions.ArrangeRecordsByRating', {
name : 'Arrange Records By Rating',
enabled : true,
initialize : function() {
},
performAction : function($super) {
if (true) {
$super();
} else {
this.script();
}
},
comments : function() {
return '// ' + this.name + '\n';
},
script : function() {
var records = philmaker.playground.RecordAssistant.findAllRecords();
records.sort(function(record1, record2) {
var rating1 = philmaker.foundation.Utility.getSubmorphByClass(record1, philmaker.foundation.RatingMorph).value;
var rating2 = philmaker.foundation.Utility.getSubmorphByClass(record2, philmaker.foundation.RatingMorph).value;
if (rating1 > rating2) return -1;
if (rating1 < rating2) return 1;
if (rating1 == rating2) return 0;
});
var position = records[0].getPosition();
records.forEach(function(record) {
position.x = Math.min(position.x, record.getPosition().x);
position.y = Math.min(position.y, record.getPosition().y);
});
records.forEach(function(record) {
var title = philmaker.foundation.Utility.getSubmorphByName(record, 'title').textString;
record.setPosition(pt(position.x, position.y));
position.y = position.y + record.getExtent().y + 4;
});
}
});
philmaker.actions.RunnableCodeNoteAction.subclass('philmaker.actions.ArrangeRecordsByCompleted', {
name : 'Arrange Records By Completed',
enabled : true,
initialize : function() {
},
performAction : function($super) {
if (true) {
$super();
} else {
this.script();
}
},
comments : function() {
return '// ' + this.name + '\n';
},
script : function() {
var getStatusCode = function(record) {
var tags = philmaker.foundation.Utility.getSubmorphsByClass(record, philmaker.playground.TagMorph);
for (var i = 0; i < tags.length; i++) {
var value = tags[i].getValue();
if (value == 'Complete') {
return 2;
} else if (value == 'Incomplete') {
return 1;
}
}
return 0;
};
var records = philmaker.playground.RecordAssistant.findAllRecords();
records.sort(function(record1, record2) {
var status1 = getStatusCode(record1);
var status2 = getStatusCode(record2);
if (status1 > status2) return -1;
if (status1 < status2) return 1;
if (status1 == status2) return 0;
});
var position = records[0].getPosition();
records.forEach(function(record) {
position.x = Math.min(position.x, record.getPosition().x);
position.y = Math.min(position.y, record.getPosition().y);
});
records.forEach(function(record) {
var title = philmaker.foundation.Utility.getSubmorphByName(record, 'title').textString;
record.setPosition(pt(position.x, position.y));
position.y = position.y + record.getExtent().y + 4;
});
}
});
philmaker.actions.RunnableCodeNoteAction.subclass('philmaker.actions.ModifyBlogEntry1', {
name : 'Modify Blog Entry (Script 1)',
enabled : true,
initialize : function() {
},
comments : function() {
return '';
},
script : function() {
var selectedMorphs = philmaker.foundation.Utility.getSelectedMorphs();
selectedMorphs.forEach(function(selectedMorph) {
if (selectedMorph instanceof philmaker.playground.BlogEntry) {
var blogEntry = selectedMorph;
try {
var date = new Date();
date.setYear(2012);
blogEntry.setPostDate(date);
blogEntry.setTitle('Hey Look: Its Flipper!');
blogEntry.setImageUrl('http://www.marocga.com/albums/userpics/normal_dolphin11.jpg');
blogEntry.addTag('Ocean Life');
} catch (e) {
console.log(e);
}
}
}, this);
}
});
philmaker.actions.RunnableCodeNoteAction.subclass('philmaker.actions.ModifyBlogEntry2', {
name : 'Modify Blog Entry (Script 2)',
comments : function() {
return '';
},
script : function() {
var selectedMorphs = philmaker.foundation.Utility.getSelectedMorphs();
selectedMorphs.forEach(function(selectedMorph) {
if (selectedMorph instanceof philmaker.playground.BlogEntry) {
var blogEntry = selectedMorph;
try {
var date = new Date();
blogEntry.setPostDate(date);
blogEntry.setTitle('Dog Days of Summer');
blogEntry.setImageUrl('http://russian.wunderground.com/data/wximagenew/t/thib/61.jpg');
blogEntry.removeTag('Ocean Life');
} catch (e) {
console.log(e);
}
}
}, this);
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.ShelfBoxDemo', {
name : 'ToolBox Demo',
enabled : true,
initialize : function() {
},
performAction : function() {
var point = pt(100, 100);
for (var i = 0; i < 5; i++) {
var morph = new philmaker.playground.ShelfBox();
morph.setPosition(point);
WorldMorph.current().addMorph(morph);
point.y = point.y + 110;
}
var point = pt(400, 400);
for (var i = 0; i < 5; i++) {
WorldMorph.current().addMorph(Morph.makeRectangle(point, pt(60, 30)));
point.y = point.y + 50;
}
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.PrintSubmorphPositions', {
name : 'Print Submorph Positions',
description : 'Print the positions of the morph and submorphs of the selection in the selection tray. ' +
'This can be useful when working locally without persistence to be able to drag arrange morphs then encode those positions.',
enabled : true,
initialize : function() {
},
performAction : function() {
var selectedMorphs = philmaker.foundation.Utility.getSelectedMorphs();
selectedMorphs = selectedMorphs.reverse();
selectedMorphs.forEach(function(selectedMorph, index) {
this.printBounds('selected morph ', index, selectedMorph);
selectedMorph.submorphs.forEach(function(submorph, index2) {
this.printBounds(' submorph ', index2, submorph);
}, this);
}, this);
},
printBounds : function(description, index, morph) {
console.log(description + index + ' position: ' + morph.getPosition() + ' extent: ' + morph.getExtent());
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.InstallCustomWorldMorphMenus', {
name : 'Install Custom WorldMorph Menus',
enabled : true,
initialize : function() {
},
performAction : function() {
var self = this;
var morphMenuOriginal = WorldMorph.prototype.morphMenu;
WorldMorph.prototype.morphMenu = function($super, event) { // I haven't looked at Class.addMixin
var morphMenuOriginal = arguments.callee.morphMenuOriginal; // but for now I'm overriding WorldMorph.morphMenu with a new function
var menuMorph = morphMenuOriginal.apply(this, arguments); // and attaching the original morphMenu function to it
menuMorph.addLine(); // fixme: review doing this with an actual closure instead
self.addComponentsSubMenu(menuMorph);
self.addActionSubMenu(menuMorph);
return menuMorph;
}
WorldMorph.prototype.morphMenu.morphMenuOriginal = morphMenuOriginal;
},
addActionSubMenu : function(menuMorph) {
console.log('philmaker.actions.RunnableCodeNoteAction.type: ' + philmaker.actions.RunnableCodeNoteAction.type);
var excludes = [
philmaker.actions.RunnableCodeNoteAction,
philmaker.actions.InstallCustomWorldMorphMenus,
philmaker.actions.InstallMenuLocationMemory,
philmaker.actions.InstallColorPatch,
philmaker.actions.InstallPathPatch,
philmaker.actions.BasisAction
];
var actions = [];
for (var i in philmaker.actions) { // install the namespace of actions automatically
if (philmaker.actions.hasOwnProperty(i)) {
var value = philmaker.actions[i];
if (value.prototype instanceof philmaker.actions.BasicAction) {
var include = true;
for (var i = 0; i < excludes.length; i++) {
var exclude = excludes[i];
if (value == exclude) {
include = false;
break;
}
}
if (include) {
actions.push(new value());
}
}
}
}
for (var i = 0; i < actions.length; i++) {
var action = actions[i];
var func = function() {
var action = arguments.callee.action;
return action.performAction.apply(action, arguments);
}
func.action = action;
actions[i] = [
action.name,
func
];
}
var submenuDef = ['Custom Actions', actions];
menuMorph.addItem(submenuDef);
},
addComponentsSubMenu : function(menuMorph) {
var components = [
philmaker.playground.ScrollableStickyNote,
philmaker.playground.RunnableCodeNote,
philmaker.playground.RatingMorph,
philmaker.playground.TagMorph,
philmaker.playground.RecordMorph,
philmaker.playground.BlogEntry,
philmaker.playground.StructuredContent,
philmaker.playground.ShelfBox,
philmaker.playground.WormholeMorph,
philmaker.playground.ImageMorph,
philmaker.foundation.InstantiationWidget,
philmaker.playground.StickyNote,
philmaker.playground.CodeNote
];
for (var i = 0; i < components.length; i++) {
var component = components[i];
var func = function() {
var component = arguments.callee.component; // fixme: review doing this with an actual closure instead
component = new component();
var point = philmaker.foundation.Utility.getOpenLocation();
WorldMorph.current().addMorphAt(component, point);
}
func.component = component;
var name = component.type;
var index = name.lastIndexOf('.');
if (index > -1) {
name = name.substring(index + 1);
}
components[i] = [
name,
func
];
}
var submenuDef = ['Custom Components', components];
menuMorph.addItem(submenuDef);
},
addSubMenu : function(menuMorph, name, items) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
var func = function() {
var action = arguments.callee.action;
return action.performAction.apply(action, arguments);
}
func.action = item;
items[i] = [
item.name,
func
];
}
var submenuDef = [name, items];
menuMorph.addItem(submenuDef);
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.InstallMenuLocationMemory', { // could be using the ChangeSet instead
name : 'Install Menu Location Memory',
enabled : true,
initialize : function() {
},
performAction : function() {
var self = this;
var showMorphMenuOriginal = Morph.prototype.showMorphMenu;
Morph.prototype.showMorphMenu = function(event) {
this.world().lastMenuLocation = event.point(); // fixme: review doing this with an actual closure instead
var showMorphMenuOriginal = arguments.callee.showMorphMenuOriginal;
return showMorphMenuOriginal.apply(this, arguments);
}
Morph.prototype.showMorphMenu.showMorphMenuOriginal = showMorphMenuOriginal;
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.InstallColorPatch', {
name : 'Install Color Patch',
performAction : function() {
Color.addMethods({
toLiteral : function() {
return {
r : this.r,
g : this.g,
b : this.b
}
}
});
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.InstallPathPatch', {
name : 'Install lively.scene.Path Patch',
enabled : true,
initialize : function() {
},
performAction : function() {
lively.scene.Path.addMethods({
copy : function($super) {
var result = $super();
result.elements = this.elements;
return result;
}
});
}
});
philmaker.actions.BasicAction.subclass('philmaker.actions.BasisAction', {
name : 'Basis Action',
enabled : true,
initialize : function() {
},
performAction : function() {
console.log('BasisAction.performAction');
}
});
function startup(worldMorph) {
new philmaker.playground.LocalInitializer();
}
/*
Object.extend(Global.document, {
oncontextmenu : function(event) {
console.log('oncontextmenu');
return false;
}.logErrors('Context Menu Handler')
});
*/
Object.subclass('philmaker.playground.WorldInitializer', {
initialize : function() {
console.log('WorldInitializer.initialize');
},
initializePreamble : function() {
TextSelectionMorph.prototype.style.fill = Color.rgb(255, 204, 83);
try {
SimpleInspector.prototype.initialViewExtent = pt(700, 400);
} catch (e) {
console.log(e);
}
try {
InspectorWidget.prototype.initialViewExtent = pt(700, 400);
} catch (e) {
console.log(e);
}
var actions = [{
clazz : philmaker.actions.InstallCustomWorldMorphMenus,
run : true
}, {
clazz : philmaker.actions.InstallMenuLocationMemory,
run : true
}, {
clazz : philmaker.actions.InstallColorPatch, // todo: make sure to report this
run : true
}, {
clazz : philmaker.actions.InstallPathPatch,
run : true
}];
for (var i = 0; i < actions.length; i++) {
var action= actions[i];
if (action.run) {
var clazz = action.clazz;
action = new clazz();
if (action instanceof philmaker.actions.BasicAction) {
action.performAction();
}
}
}
},
initializePostscript : function() {
if (false) {
var action = new philmaker.actions.AlterWorldExtent();
action.performAction();
}
}
});
Object.subclass('philmaker.playground.LocalInitializer', {
initialize : function() {
console.log('LocalInitializer.initialize');
var contenders = [{
clazz : philmaker.playground.ScrollableStickyNote,
instantiate : false
}, {
clazz : philmaker.playground.RunnableCodeNote,
instantiate : false
}, {
clazz : philmaker.playground.RatingMorph,
instantiate : false
}, {
clazz : philmaker.playground.TagMorph,
instantiate : false
}, {
clazz : philmaker.playground.RecordMorph,
instantiate : false
}, {
clazz : philmaker.playground.BlogEntry,
instantiate : true
}, {
clazz : philmaker.playground.StructuredContent,
instantiate : false
}, {
clazz : philmaker.playground.ShelfBox,
instantiate : false
}, {
clazz : philmaker.playground.WormholeMorph,
instantiate : false
}, {
clazz : philmaker.playground.ImageMorph,
instantiate : false
}, {
clazz : philmaker.foundation.InstantiationWidget,
instantiate : false
}, {
clazz : philmaker.playground.StickyNote,
instantiate : false
}, {
clazz : philmaker.playground.CodeNote,
instantiate : false
}, {
clazz : philmaker.playground.BoxLayoutMorph,
instantiate : false
}, {
clazz : MetamorphosisDemo,
instantiate : false
}];
if (true) {
for (var i = 0; i < contenders.length; i++) {
var contender = contenders[i];
if (contender.instantiate) {
var clazz = contender.clazz;
var object = new clazz();
if (object instanceof Morph) {
var morph = object;
WorldMorph.current().addMorph(morph);
}
}
}
}
if (false) {
var morph = new philmaker.playground.RatingMorph();
morph.setFill(Color.blue);
morph.setLitColor(Color.white);
morph.setUnlitColor(Color.blue);
WorldMorph.current().addMorph(morph);
morph.setValue(4);
}
if (false) {
var action = new philmaker.actions.TweakBlogEntry();
action.performAction();
}
}
});
philmaker.foundation.RatingMorph.subclass('philmaker.playground.RatingMorph', {
initialize : function($super) {
$super();
this.setPosition(pt(200, 400));
}
});
Object.subclass('philmaker.playground.BlogPage', { // for mindshare, need to make a page which is indistinguishable from a regular hypertext document
// do this with BlogPage or create a class StructuredContent
initialize: function($super) {
$super();
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.BlogEntry', {
openForDragAndDrop : true,
initialize : function($super) {
$super(new Rectangle(50, 50, 700, 220));
this.setOrientation('horizontal');
this.setFill(Color.white);
this.setFillOpacity(1.0);
this.setBorderColor(Color.hsb(0.0, 0.0, 0.97));
this.setBorderWidth(3);
this.shapeRoundEdgesBy(15);
this.suppressHandles = false;
this.blogEntryDateMorph = new philmaker.playground.BlogEntryDateMorph();
this.center = new philmaker.playground.BlogEntryBody();
this.center.padding = Rectangle.inset(5, 5, 5, 5);
var rectangle = new Rectangle(0, 0, 180, 180);
var imagePath = 'http://russian.wunderground.com/data/wximagenew/t/thib/61.jpg';
this.blogImageMorph = new ImageMorph(rectangle, imagePath);
this.blogImageMorph.setFillOpacity(0.0);
this.blogImageMorph.rotateBy(-0.05);
this.addMorph(this.blogEntryDateMorph, {
weight : 100,
margin : new philmaker.foundation.Insets(20, 10, 25, 5)
});
this.addMorph(this.center, {
weight : 1,
margin : new philmaker.foundation.Insets(20, 5, 25, 5)
});
this.addMorph(this.blogImageMorph, {
weight : 200,
margin : new philmaker.foundation.Insets(20, 5, 25, 10)
});
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.adjustForNewBounds(); // hack for now
},
setPostDate : function(date) {
var blogEntryDateMorph = philmaker.foundation.Utility.getSubmorphByClass(this, philmaker.playground.BlogEntryDateMorph);
blogEntryDateMorph.setDate(date);
},
getPostDate : function() {
return null;
},
setTitle : function(title) {
var textMorph = philmaker.foundation.Utility.getSubmorphByName(this, 'title');
textMorph.setSelectionRange(0, textMorph.textString.length);
textMorph.replaceSelectionWith(title); // todo: investigate: setTextString etc cause freezes when the text is bold
},
getImageUrl : function() {
return null;
},
setImageUrl : function(url) {
var imageMorph = philmaker.foundation.Utility.getSubmorphByClass(this, ImageMorph);
imageMorph.loadFromURL(url);
},
getImageUrl : function() {
return null;
},
addTag : function(tagText) {
var tagsPanel = philmaker.foundation.Utility.getSubmorphByClass(this, philmaker.playground.BlogEntryTagsPanel);
tagsPanel.addTag(tagText);
},
removeTag : function(tagText) {
var tagsPanel = philmaker.foundation.Utility.getSubmorphByClass(this, philmaker.playground.BlogEntryTagsPanel);
tagsPanel.removeTag(tagText);
},
prepareSampleText : function() {
var result = '';
for (var i = 0; i < 1; i++) {
result = result + philmaker.foundation.sampleText + '\n\n';
}
return result;
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.BlogEntryBody', {
initialize : function($super) {
$super(new Rectangle(50, 50, 600, 400));
this.setOrientation('vertical');
this.setFillOpacity(0.0);
this.setBorderWidth(0);
var rectangle = new Rectangle(0, 0, 400, 20);
var titleTextMorph = new philmaker.playground.BlogEntryTextMorph(rectangle, 'Dog Days of Summer', 'title');
titleTextMorph.setBold(true);
titleTextMorph.setFontSize(18);
titleTextMorph.padding = Rectangle.inset(0, 0, 0, 0); // loses padding after font size change
var bodyTextMorph = new philmaker.playground.BlogEntryTextMorph(rectangle, philmaker.foundation.sampleText, 'body');
var tagsPanel = new philmaker.playground.BlogEntryTagsPanel();
this.addMorph(titleTextMorph, {
weight : .25,
margin : new philmaker.foundation.Insets(2, 0, 5, 0)
});
this.addMorph(bodyTextMorph, {
weight : 0.5,
margin : new philmaker.foundation.Insets(5, 0, 5, 0)
});
this.addMorph(tagsPanel, {
weight : .25,
margin : new philmaker.foundation.Insets(15, 0, 0, 0)
});
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.adjustForNewBounds(); // hack for now
}
});
Morph.subclass('philmaker.playground.BlogEntryTagsPanel', {
openForDragAndDrop : true,
initialize : function($super) {
$super(new lively.scene.Rectangle(new Rectangle(50, 50, 600, 400)));
this.setFillOpacity(0.0);
this.setBorderWidth(0);
var tagMorph = new philmaker.playground.TagMorph();
tagMorph.setValue('Photos');
tagMorph.setPosition(pt(0, 0));
this.addMorph(tagMorph);
},
addTag : function(tagText) {
var rightmost = 0;
this.withAllSubmorphsDo(function() {
if (this instanceof philmaker.playground.TagMorph) { // do we care about instanceof?
var position = this.getPosition();
var extent = this.getExtent();
var thisRightmost = position.x + extent.x;
rightmost = Math.max(rightmost, thisRightmost);
}
});
var tagMorph = new philmaker.playground.TagMorph();
tagMorph.setValue(tagText);
tagMorph.setPosition(pt(rightmost + 10, 0));
this.addMorph(tagMorph); // todo: maybe first arrange them tidy as well
},
removeTag : function(tagText) {s
this.withAllSubmorphsDo(function() {
if (this instanceof philmaker.playground.TagMorph) {
var tagMorph = this;
if (tagMorph.getValue() == tagText) {
console.log('removing tag');
tagMorph.remove();
}
}
});
}
});
philmaker.foundation.TextMorph.subclass('philmaker.playground.BlogEntryTextMorph', {
suppressHandles : true,
openForDragAndDrop : false,
styleClass : [],
initialize : function($super, rectangle, text, name) {
$super(rectangle, text);
this.name = name;
this.setFillOpacity(0.0);
this.setBorderWidth(0);
this.setTextColor(Color.hsb(0.0, 0.0, 0.4));
this.focusHaloBorderWidth = 0;
this.padding = Rectangle.inset(0, 0, 0, 0);
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.BlogEntryDateMorph', {
initialize : function($super) {
$super(new Rectangle(0, 0, 100, 300));
this.setOrientation('vertical');
this.setFill(Color.white);
this.setFillOpacity(0.0);
this.setBorderColor(Color.hsb(0.0, 0.0, 0.9));
this.setBorderWidth(0);
this.shapeRoundEdgesBy(0);
var rectangle = new Rectangle(0, 0, 100, 20);
this.monthTextMorph = new philmaker.playground.BlogEntryDateTextMorph(rectangle, 'month');
this.monthTextMorph.setFontSize(24);
this.monthTextMorph.padding = Rectangle.inset(0, 0, 0, 0);
this.dayTextMorph = new philmaker.playground.BlogEntryDateTextMorph(rectangle, 'day');
this.dayTextMorph.setFontSize(24);
this.dayTextMorph.padding = Rectangle.inset(0, 0, 0, 0);
this.yearTextMorph = new philmaker.playground.BlogEntryDateTextMorph(rectangle, 'year');
this.yearTextMorph.setFontSize(24);
this.yearTextMorph.padding = Rectangle.inset(0, 0, 0, 0);
this.addMorph(this.monthTextMorph, {
weight : 20,
margin : new philmaker.foundation.Insets(0, 0, 0, 0),
alignX : 'center'
});
this.addMorph(this.dayTextMorph, {
weight : 20,
margin : new philmaker.foundation.Insets(0, 0, 0, 0),
alignX : 'center'
});
this.addMorph(this.yearTextMorph, {
weight : 20,
margin : new philmaker.foundation.Insets(0, 0, 0, 0),
alignX : 'center'
});
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.setDate(new Date());
this.adjustForNewBounds(); // hack for now
},
setDate : function(date) {
console.log('BlogEntryDateMorph.setDate: ' + date);
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; // fixme: localize, refactor these months of the instance
var month = date.getMonth();
month = months[month];
var day = date.getDate();
day = new String(day);
var year = date.getFullYear();
year = new String(year);
this.monthTextMorph.setSelectionRange(0, this.monthTextMorph.textString.length); // woraround for bolded text
this.monthTextMorph.replaceSelectionWith(month);
this.dayTextMorph.setSelectionRange(0, this.dayTextMorph.textString.length);
this.dayTextMorph.replaceSelectionWith(day);
this.yearTextMorph.setSelectionRange(0, this.yearTextMorph.textString.length);
this.yearTextMorph.replaceSelectionWith(year);
}
});
philmaker.foundation.TextMorph.subclass('philmaker.playground.BlogEntryDateTextMorph', {
suppressHandles : true,
openForDragAndDrop : false,
styleClass : [],
initialize : function($super, rectangle, name) {
$super(rectangle, ' ');
this.myName = name;
this.setFillOpacity(0.0);
this.setBorderWidth(0);
this.setTextColor(Color.hsb(0.0, 0.0, 0.85));
this.focusHaloBorderWidth = 0;
this.beLabel(); // can cause GridLayout alignment difficulty
//this.setAlignment('center');
this.setBold(true);
this.setFontSize(14);
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.StructuredContent', {
initialize : function($super) {
$super(new Rectangle(10, 50, 700, 450));
this.setOrientation('vertical');
this.setFill(Color.white);
this.setFillOpacity(1.0);
this.setBorderColor(Color.hsb(0.0, 0.0, 0.9));
this.setBorderWidth(1);
this.shapeRoundEdgesBy(0);
this.suppressHandles = false;
var rectangle = new Rectangle(0, 0, 150, 500);
this.top = new philmaker.playground.StructuredContentBar();
this.center = new philmaker.playground.StructuredContentHorizontal();
this.center.padding = Rectangle.inset(5, 5, 5, 5);
this.addMorph(this.top, {
weight : 46,
margin : new philmaker.foundation.Insets(10, 10, 0, 10)
});
this.addMorph(this.center, {
weight : .6,
margin : new philmaker.foundation.Insets(5, 0, 0, 0)
});
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.adjustForNewBounds(); // hack for now
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.StructuredContentBar', {
initialize : function($super) {
$super(new Rectangle(0, 0, 0, 0));
this.setOrientation('horizontal');
var hue = 216;
var saturation = 0.35;
hue = 0;
saturation = 0.0;
this.setFill(new lively.paint.LinearGradient(
[
new lively.paint.Stop(0, Color.hsb(hue, saturation, 0.79)),
new lively.paint.Stop(0.45, Color.hsb(hue, saturation, 0.72)),
new lively.paint.Stop(0.65, Color.hsb(hue, saturation, 0.65)),
new lively.paint.Stop(0.85, Color.hsb(hue, saturation, 0.58)),
new lively.paint.Stop(1, Color.hsb(hue, saturation, 0.51))
], lively.paint.LinearGradient.NorthSouth
));
this.setFillOpacity(1.0);
this.setBorderColor(Color.hsb(0.0, 0.0, 0.7));
this.setBorderWidth(0);
this.shapeRoundEdgesBy(10);
var titles = ['One', 'Two', 'Three', 'Four', 'Five', 'Six'];
for (var i = 0; i < titles.length; i++) {
this.button = new philmaker.playground.StructuredContentBarButton(titles[i]);
this.button.padding = Rectangle.inset(5, 5, 5, 5);
var weight = 1 / titles.length;
this.addMorph(this.button, {
weight : weight,
margin : new philmaker.foundation.Insets(0, 0, 0, 0)
});
}
this.adjustForNewBounds(); // hack for now
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.StructuredContentBarButton', { // on mouse over, increase fill opacity
// using BoxLayoutMorph really just for centering of
initialize : function($super, text) { // the nested text component
$super(new Rectangle(0, 0, 0, 0));
this.setFillOpacity(0.0);
this.setBorderWidth(0);
this.shapeRoundEdgesBy(0);
var textMorph = new philmaker.foundation.TextMorph(new Rectangle(0, 0, 0, 0), text);
textMorph.setFillOpacity(0.0);
textMorph.beLabel();
textMorph.setFontFamily('Optima');
textMorph.setFontSize(16);
textMorph.padding = Rectangle.inset(0, 0, 0, 0);
this.addMorph(textMorph, {
weight : 1.0,
margin : new philmaker.foundation.Insets(10, 0, 0, 0),
alignX : 'center'
});
this.adjustForNewBounds(); // hack for now
},
onMouseOver : function() {
this.setFillOpacity(0.1); // fixme: need corner clipping
},
onMouseOut : function() {
this.setFillOpacity(0.0);
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.StructuredContentHorizontal', {
initialize : function($super) {
$super(new Rectangle(100, 50, 800, 650));
this.setOrientation('horizontal');
this.setFill(Color.white);
this.setFillOpacity(1.0);
this.setBorderColor(Color.hsb(0.0, 0.0, 0.9));
this.setBorderWidth(0);
this.shapeRoundEdgesBy(0);
var rectangle = new Rectangle(0, 0, 150, 500);
this.leftTextMorph = new philmaker.playground.StructuredContentTextMorph(rectangle, this.prepareSidebarText(), 'left');
this.leftTextMorph.setFontFamily('Optima');
this.leftTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.center = new philmaker.playground.StructuredContentInner();
this.center.padding = Rectangle.inset(5, 5, 5, 5);
this.rightTextMorph = new philmaker.playground.StructuredContentTextMorph(rectangle, this.prepareSidebarText(), 'right');
this.rightTextMorph.setFontFamily('Optima');
this.rightTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.addMorph(this.leftTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(10, 10, 10, 5)
});
this.addMorph(this.center, {
weight : 0.6,
margin : new philmaker.foundation.Insets(10, 5, 10, 5)
});
this.addMorph(this.rightTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(10, 5, 10, 10)
});
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.adjustForNewBounds(); // hack for now
},
prepareSidebarText : function() {
var result = '';
for (var i = 0; i < 20; i++) {
result = result + 'Sidebar Link' + '\n';
}
return result;
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.StructuredContentInner', {
initialize : function($super) {
$super(new Rectangle(0, 0, 100, 300));
this.setOrientation('vertical');
this.setFill(Color.white);
this.setFillOpacity(1.0);
this.setBorderColor(Color.hsb(0.0, 0.0, 0.9));
this.setBorderWidth(0);
this.shapeRoundEdgesBy(0);
var rectangle = new Rectangle(0, 0, 150, 500);
this.headerTextMorph = new philmaker.playground.StructuredContentTextMorph(rectangle, 'Lively: The Web Done Right', 'header');
this.headerTextMorph.setFontFamily('Optima');
this.headerTextMorph.setFontSize(24);
//this.headerTextMorph.setBold(true); // bug: bold kerning freaks out
this.headerTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.bodyTextMorph = new philmaker.playground.StructuredContentTextMorph(rectangle, this.prepareSampleText(), 'body');
this.bodyTextMorph.setFontFamily('Optima');
this.bodyTextMorph.setFontSize(14);
this.bodyTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.footerTextMorph = new philmaker.playground.StructuredContentTextMorph(rectangle, 'Copyright 2009, Bullwinkle J. Moose', 'footer');
this.footerTextMorph.setFontSize(10);
this.footerTextMorph.setFontFamily('Optima');
this.footerTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.addMorph(this.headerTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(0, 0, 5, 0)
});
this.addMorph(this.bodyTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(5, 0, 5, 0)
});
this.addMorph(this.footerTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(5, 0, 0, 0)
});
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.adjustForNewBounds(); // hack for now
//WorldMorph.current().scheduleForLater(new SchedulableAction(this, 'invokeCentering'), 5, false);
},
invokeCentering : function() { // bug: if I center the text and size narrow columns: exceptions are thrown and a column breaks out
this.headerTextMorph.setAlignment('center');
this.footerTextMorph.setAlignment('center');
},
prepareSampleText : function() {
var result = '';
for (var i = 0; i < 2; i++) {
result = result + philmaker.foundation.sampleText + '\n\n';
}
return result;
}
});
philmaker.foundation.TextMorph.subclass('philmaker.playground.StructuredContentTextMorph', {
suppressHandles : true,
openForDragAndDrop : false,
styleClass : [],
initialize : function($super, rectangle, text, name) {
$super(rectangle, text);
this.myName = name;
this.setFillOpacity(0.0);
this.setBorderWidth(1);
this.setBorderColor(Color.hsb(0.0, 0.0, 0.95));
this.setTextColor(Color.hsb(0.0, 0.0, 0.4));
this.focusHaloBorderWidth = 0;
this.padding = Rectangle.inset(0, 0, 0, 0);
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
}
});
Morph.subclass('philmaker.playground.Shelf', { // using scaling for workspaces
// until this is written, we just use the selection tray scaling
initialize: function($super) { // workspaces are stacked horizontally or vertically and have scrolling buttons
// look into FishEye too
$super(new lively.scene.Rectangle(new Rectangle(0, 0, 100, 100)));
this.setPosition(pt(100, 100));
},
openForDragAndDrop : true
});
Morph.subclass('philmaker.playground.ShelfBox', { // fixme: should be resizale and possibly still scalable
// cool demo: animation runnning inside a toolbox
openForDragAndDrop : false, // omg what to do if put one box inside another?
suppressHandles : true,
initialize: function($super) {
$super(new lively.scene.Rectangle(new Rectangle(100, 100, 100, 100)));
if (false) philmaker.foundation.layoutBorders = true;
this.suppressHandles = true;
this.setFill(Color.white);
this.setFillOpacity(1.0);
this.setBorderColor(Color.hsb(0, 0.0, 0.9));
this.setBorderWidth(6);
this.shapeRoundEdgesBy(10);
var textMorph = new philmaker.foundation.TextMorph(Rectangle(0, 0, 100, 100), 'Toolbox');
textMorph.setFillOpacity(0.0);
textMorph.setTextColor(Color.hsb(0, 0.0, 0.90));
textMorph.beLabel();
textMorph.setFontFamily('Marker Felt');
textMorph.setFontSize(20);
textMorph.setPosition(pt(8, 34));
this.addMorph(textMorph);
var container = new philmaker.playground.ShelfBoxContainer();
this.addMorph(container);
},
addCover : function() {
var cover = new philmaker.playground.ShelfBoxCover(this.shape.bounds());
this.addMorph(cover);
},
getContainer : function() {
return philmaker.foundation.Utility.getSubmorphByClass(this, philmaker.playground.ShelfBoxContainer);
},
getCover : function() {
return philmaker.foundation.Utility.getSubmorphByClass(this, philmaker.playground.ShelfBoxCover);
},
onMouseUp : function(event) { // ShelfBoxContainer.onMouseDown enables this
event.hand.setMouseFocus(null);
}
});
Morph.subclass('philmaker.playground.ShelfBoxContainer', {
openForDragAndDrop : true,
suppressHandles : true,
handlesMouseDown : Functions.True,
initialize: function($super) {
$super(new lively.scene.Rectangle(new Rectangle(10, 10, 80, 80)));
this.suppressHandles = true;
this.setFillOpacity(0.0);
this.setBorderWidth(0);
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.restoreBounds();
},
initializeTransientState : function() {
this.openForDragAndDrop = true;
},
restoreBounds : function() {
this.restorePosition();
this.setExtent(pt(80, 80));
},
restorePosition : function() {
this.setPosition(pt(10, 10));
},
addMorph : function($super, morph) { // issue: I am not seeing that Lively will notify me of a drop action, it only calls addMorph on the receiver
// as a result I hack this to be able know the extent of the entire set of dropped morphs first
if (! (morph.owner instanceof HandMorph)) { // so know how much to scale to fit the size of the container
$super(morph);
} else {
if ((! this.union) && (this.hasSubmorphs())) { // fixme: need a real flag instead of using this.union as the in process flag
return;
}
this.setPosition(pt(0, 0));
var handMorph = morph.owner;
var dropDelta = handMorph.getPosition().subPt(this.worldPoint(this.getPosition()));
if (! this.union) {
this.union = new Rectangle(0, 0, 0, 0);
var self = this;
handMorph.carriedMorphsDo(function(m) {
var rect = new Rectangle(m.getPosition().x, m.getPosition().y, m.getExtent().x, m.getExtent().y);
self.union = self.union.union(rect);
});
handMorph.carriedMorphsDo(function(m) {
m.translateBy(pt(-self.union.x, -self.union.y));
m.translateBy(pt(-dropDelta.x, -dropDelta.y));
});
var max = Math.max(this.union.width, this.union.height);
var offset = this.getBorderWidth();
this.scaleReduction = (this.getExtent().y / max);
this.setExtent(pt(this.union.width, this.union.height));
}
var result = $super(morph);
var carryCount = 0;
handMorph.carriedMorphsDo(function(m) {
carryCount++;
});
if (carryCount == 0) {
this.restorePosition();
this.union = null;
this.setScale(this.scaleReduction); // fixme: must take into account existing scaling of dropped morphs
var shelfBox = this.owner;
shelfBox.addCover();
}
}
},
onMouseDown : function(event) {
if (this.mouseFocus != this.owner) {
event.hand.setMouseFocus(this.owner);
}
},
addAllDroppedMorphs : function(morphs) {
},
/*
pickMeUp : function(event) {
this.owner.pickMeUp(event);
},
dragMe : function(event) {
this.owner.dragMe(event);
},
*/
remove : function() {
this.owner.remove();
}
});
Morph.subclass('philmaker.playground.ShelfBoxCover', {
openForDragAndDrop : false,
suppressHandles : true,
initialize: function($super, rectangle) {
$super(new lively.scene.Rectangle(rectangle));
this.suppressHandles = true;
this.setFillOpacity(0.0);
this.setBorderWidth(0);
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.green);
}
this.handlesMouseDown = Functions.True;
},
initializeTransientState : function() {
this.openForDragAndDrop = false;
this.handlesMouseDown = Functions.True;
},
onMouseDown : function(event) {
this.beginGrab(event);
},
onMouseUp : function(event) {
event.hand.dropMorphsOn(this.world()); // or locate actual receiver?
this.owner.removeMorph(this);
},
beginGrab : function(event) { // reference material: PasteUpMorph onMouseDown & makeSelection
var shelfBox = this.owner;
var container = shelfBox.getContainer();
if (container.hasSubmorphs()) {
container.setScale(1.0);
var rectangle = event.point().asRectangle();
rectangle.width = container.getExtent().x;
rectangle.height = container.getExtent().y;
rectangle = rectangle.expandBy(5);
var grabMorph = null;
var dragDelta = event.hand.getPosition().subPt(this.worldPoint(container.getPosition()));
var world = this.world();
if (container.submorphs.length == 1) {
grabMorph = container.submorphs[0];
grabMorph.translateBy(pt(dragDelta.x, dragDelta.y));
world.addMorph(grabMorph);
} else {
var selectionMorph = new SelectionMorph(rectangle);
container.submorphs.clone().reverse().forEach(function(submorph) {
submorph.translateBy(pt(dragDelta.x, dragDelta.y));
world.addMorph(submorph);
selectionMorph.selectedMorphs.push(submorph);
});
grabMorph = selectionMorph;
this.world().currentSelection = grabMorph;
}
container.restoreBounds();
this.world().addMorph(grabMorph);
event.hand.grabMorph(grabMorph, event);
}
},
pickMeUp : function(event) {
this.owner.pickMeUp(event);
},
dragMe : function(event) {
this.owner.dragMe(event);
},
remove : function() {
this.owner.remove();
}
});
Morph.subclass('philmaker.playground.TagMorph', { // feedback: would be nice if I could pass points here
// but lively.scene may not depend on Base
openForDragAndDrop : false,
suppressHandles : true,
reshape : Functions.Null,
tagWidth : 80,
tagHeight : 20,
insetX : 6,
insetY : 6,
initialize : function($super) {
var shape = this.createShape();
$super(shape);
this.setFill(Color.hsb(217, 0.66, 0.93));
this.setBorderColor(Color.hsb(217, 0.66, 0.85));
this.setBorderWidth(1);
var rectangle = new Rectangle(0, 0, this.tagWidth, this.tagHeight);
var textMorph = new philmaker.playground.TagTextMorph(rectangle);
this.addMorph(textMorph);
textMorph.setPosition(pt(this.insetX + 6, 2));
if (true) {
this.rotateBy(-0.1);
}
},
createShape : function() {
var definition = this.createShapeDefinition();
if (false) {
return new lively.scene.Path(definition);
} else {
return new lively.scene.Polygon(definition);
}
},
createShapeDefinition : function() {
if (false) {
var p = pt(0, 0);
var elements = [];
elements.push(new lively.scene.MoveTo(p.x, p.y = p.y + this.insetY));
elements.push(new lively.scene.LineTo(p.x = p.x + this.insetX, p.y = p.y - this.insetY));
elements.push(new lively.scene.LineTo(p.x = (this.tagWidth - this.insetX), p.y));
elements.push(new lively.scene.LineTo(p.x, p.y = p.y + this.tagHeight));
elements.push(new lively.scene.LineTo(p.x = p.x - (this.tagWidth - (this.insetX * 2)), p.y));
elements.push(new lively.scene.LineTo(p.x = p.x - this.insetX, p.y = p.y - this.insetY));
elements.push(new lively.scene.LineTo(p.x, p.y = p.y - (this.tagHeight - (this.insetY * 2))));
//elements.push(new lively.scene.ClosePath()); // causes an exception when rendering
return elements;
} else {
var p = pt(0, 0);
var points = [];
points.push(p = p.copy().addXY(0, this.insetY));
points.push(p = p.copy().addXY(this.insetX, - this.insetY));
points.push(p = p.copy().addXY(this.tagWidth - (this.insetX * 2), 0));
points.push(p = p.copy().addXY(0, this.tagHeight));
points.push(p = p.copy().addXY(-(this.tagWidth - (this.insetX * 2)), 0));
points.push(p = p.copy().addXY(-this.insetX, -this.insetY));
points.push(p = p.copy().addXY(0, - (this.tagHeight - (this.insetY * 2))));
return points;
}
},
updateExtent : function() {
var textMorph = philmaker.foundation.Utility.getSubmorphByClass(this, TextMorph);
var length = textMorph.textString.length;
var charBounds = textMorph.getCharBounds(length - 1);
var width = charBounds.x + charBounds.width;
var extent = textMorph.getExtent();
extent.y = width;
textMorph.setExtent(extent);
this.tagWidth = width + 26;
var definition = this.createShapeDefinition();
if (false) {
this.shape.setElements(definition);
} else {
this.shape.setVertices(definition);
}
},
setValue : function(value) {
var textMorph = philmaker.foundation.Utility.getSubmorphByClass(this, TextMorph);
return textMorph.setTextString(value);
},
getValue : function() {
var textMorph = philmaker.foundation.Utility.getSubmorphByClass(this, TextMorph);
return textMorph.textString;
}
});
TextMorph.subclass('philmaker.playground.TagTextMorph', { // fixme: selection x extent does not work very well after resizing
openForDragAndDrop : false,
suppressHandles : true,
reshape : Functions.Null,
initialize : function($super, rectangle) {
$super(rectangle);
this.setFillOpacity(0);
this.setBorderWidth(0);
this.setFontFamily('Marker Felt');
this.setFontSize(16);
this.setTextColor(Color.white);
this.focusHaloBorderWidth = 0;
this.padding = new Rectangle(0, 0, 0, 0);
this.setTextString('Untitled');
this.setWrapStyle(lively.Text.WrapStyle.None);
if (false) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
this.setTextColor(Color.red);
}
},
setTextString : function($super, textString) {
$super(textString);
if (this.owner) {
this.owner.updateExtent();
}
},
onKeyDown : function($super, event) {
$super(event);
var owner = this.owner;
if (owner && (owner instanceof philmaker.playground.TagMorph)) {
var tagMorph = owner;
console.log('calling updateExtent');
tagMorph.updateExtent();
}
}
});
BoxMorph.subclass('philmaker.playground.RecordMorph', { // may need a way to expand and collapse records (triangle at right edge?)
// for the demo: use toolbox to house some runnable code notes
initialize : function($super, spec) {
var rectangle = new Rectangle(100, 100, 700, 34);
$super(rectangle);
this.setFill(Color.white);
this.setBorderColor(Color.hsb(217, .5, 1));
this.setBorderWidth(2);
this.shapeRoundEdgesBy(10);
if (! spec) {
spec = {
kind : 'Task',
title : 'Wash the Dog',
rating : 10,
tags : ['Chores', 'Complete']
};
}
var padding = 10;
var x = 10;
var morph;
morph = new philmaker.playground.TagMorph();
morph.setValue(spec.kind);
morph.setPosition(pt(x, 10));
this.addMorph(morph);
x = x + morph.getExtent().scaleByPt(morph.scalePoint).x + padding;
morph = new philmaker.playground.RecordTextMorph(new Rectangle(0, 0, 200, 20), spec.title, 'title');
morph.setPosition(pt(x, 9));
this.addMorph(morph);
x = x + morph.getExtent().scaleByPt(morph.scalePoint).x + padding;
var titleMorph = morph;
morph = new philmaker.playground.RatingMorph();
morph.name = 'rating';
morph.setFill(Color.hsb(217, .66, .93));
morph.setLitColor(Color.white);
morph.setUnlitColor(Color.hsb(217, 0.66, 0.93));
morph.setValue(spec.rating);
morph.setScale(0.8);
morph.setPosition(pt(x, 7));
this.addMorph(morph);
x = x + morph.getExtent().scaleByPt(morph.scalePoint).x + padding;
for (var i = 0; i < spec.tags.length; i++) {
var tagText = spec.tags[i];
morph = new philmaker.playground.TagMorph();
morph.setValue(tagText);
morph.setPosition(pt(x, 10));
this.addMorph(morph);
x = x + morph.getExtent().scaleByPt(morph.scalePoint).x + padding;
}
var y = this.getExtent().y;
if (spec.fields) {
var x2 = titleMorph.getPosition().x;
var y = titleMorph.getPosition().y + titleMorph.getExtent().scaleByPt(titleMorph.scalePoint).y + 0;
for (var i = 0; i < spec.fields.length; i++) {
var field = spec.fields[i];
morph = new philmaker.playground.RecordTextMorph(new Rectangle(0, 0, 200, 20), field.value, field.name);
morph.setPosition(pt(x2, y));
this.addMorph(morph);
y = y + morph.getExtent().scaleByPt(morph.scalePoint).y + 0;
}
}
this.setPosition(pt(100, 100));
var extent = this.getExtent();
extent.x = x + 4;
extent.y = y;
this.setExtent(extent);
}
});
philmaker.foundation.TextMorph.subclass('philmaker.playground.RecordTextMorph', {
initialize : function($super, rectangle, value, name) {
$super(rectangle, value);
this.setFillOpacity(0);
this.setBorderWidth(0);
this.setFontFamily('Marker Felt');
this.setFontSize(16);
this.setTextColor(Color.hsb(217, .66, .93));
this.focusHaloBorderWidth = 0;
this.padding = new Rectangle(0, 0, 0, 0);
this.setWrapStyle(lively.Text.WrapStyle.None);
this.name = name;
}
});
Object.subclass('philmaker.playground.RecordAssistant', {
initialize : function() {
}
});
philmaker.playground.RecordAssistant.findAllRecords = function() { // use Namespace.addMethods ???
var records = [];
WorldMorph.current().withAllSubmorphsDo(function() {
if (philmaker.playground.RecordAssistant.isRecord(this)) {
records.push(this);
}
});
return records;
};
philmaker.playground.RecordAssistant.findRecordsTagged = function(records, text) {
var results = [];
records.forEach(function() {
var record = this;
var tags = philmaker.foundation.Utility.getSubmorphsByClass(this, philmaker.playground.TagMorph);
tags.forEach(function() {
var value = this.getValue();
if (value == text) {
results.push(record);
}
});
});
return results;
};
philmaker.playground.RecordAssistant.getFieldValue = function(record, field) {
var value = null;
record.withAllSubmorphsDo(function() {
if (this.field && this.field == field) {
if (this.textString) {
value = this.textString;
} else if (this instanceof philmaker.foundation.RatingMorph) {
value = submorph.getValue();
}
}
});
return value;
};
philmaker.playground.RecordAssistant.isRecord = function(morph) {
var isRecord = false;
if ((morph.isRecord) && (morph.isRecord == true)) {
isRecord = true;
} else if (morph instanceof philmaker.playground.RecordMorph) {
isRecord = true;
}
return isRecord;
};
philmaker.foundation.TextMorph.subclass('philmaker.playground.BadgeMorph', {
initialize : function($super, text) {
$super(new Rectangle(0, 0, 200, 40), text);
this.setFillOpacity(1.0);
this.setBorderWidth(1.0);
this.setFontFamily('Optima');
this.setFontSize(18);
this.setTextColor(Color.hsb(0, 0.0, 0.15));
this.focusHaloBorderWidth = 0;
this.padding = new Rectangle(8, 8, 8, 8);
this.setWrapStyle(lively.Text.WrapStyle.None);
}
});
philmaker.foundation.ImageMorph.subclass('philmaker.playground.ImageMorph', { // todo: change the name and implementation of this to CaptionedImage
// image, title/caption, borders, (maybe photodate if the morph doesn't get too busy) (later even: rating)
initialize : function($super) { // look into ImageButtonMorph
var rectangle = new Rectangle(100, 100, 300, 250);
var imagePath = 'http://farm4.static.flickr.com/3228/2601103409_9b2817c6bf_o.png';
$super(rectangle, imagePath);
this.setOpacity(0.85);
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.ScrollableStickyNote', { // need to be able to detect system fonts or the system
// and also offer alternatives
initialize : function($super) {
$super(new Rectangle(200, 200, 300, 300));
this.setOrientation('vertical');
this.setFill(Color.hsb(59, .36, 1.0));
this.setFillOpacity(1.0);
this.setBorderColor(Color.rgb(255, 240, 146));
this.setBorderWidth(1);
this.setStrokeOpacity(1.0);
this.rotateBy(-0.05);
this.suppressHandles = false;
var textMorph = new philmaker.foundation.TextMorph(new Rectangle(0, 0, 300, 300), this.prepareSampleText());
textMorph.setTextColor(Color.hsb(29, 1.0, 0.5));
textMorph.setFontFamily('Marker Felt');
textMorph.setFontSize(18);
textMorph.setFill(Color.rgb(255, 254, 164));
textMorph.setFillOpacity(0.0);
textMorph.focusHaloBorderWidth = 0;
var scrollPane = new philmaker.playground.NoteScrollPane(textMorph, new Rectangle(0, 0, 300, 300));
this.addMorph(scrollPane, {
weight : 1.0,
margin : new philmaker.foundation.Insets(20, 1, 1, 1)
});
this.adjustForNewBounds(); // hack for now
},
prepareSampleText : function() {
var result = '';
for (var i = 0; i < 4; i++) {
result = result + philmaker.foundation.sampleText + '\n\n';
}
return result;
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.RunnableCodeNote', {
initialize : function($super) { // need to study TitleBarMorph to figure out how to make title bar draggable yet attached
$super(new Rectangle(200, 200, 600, 150));
this.setOrientation('vertical');
this.setFill(Color.hsb(0.0, 0.0, 0.98));
this.setFillOpacity(1.0);
this.setBorderColor(Color.hsb(0.0, 0.0, 0.93));
this.setBorderWidth(1);
this.setStrokeOpacity(1.0);
this.suppressHandles = false;
this.textMorph = new philmaker.foundation.TextMorph(new Rectangle(0, 0, 300, 300), this.prepareSampleText());
this.textMorph.setTextColor(Color.hsb(0.0, 0.0, 0.0));
if (true) {
this.textMorph.setFontFamily('Monaco');
this.textMorph.setFontSize(10);
} else {
this.textMorph.setFontFamily('Verdana');
this.textMorph.setFontSize(10);
this.textMorph.emphasizeBoldItalic({
style : 'bold'
});
}
this.textMorph.setFill(Color.hsb(0.0, 0.0, 0.98)); // fixme: investigate why this is necessary
this.textMorph.setFillOpacity(0.0); // would like for setFillOpacity(0.0) to just work
this.textMorph.focusHaloBorderWidth = 0;
this.textMorph.openForDragAndDrop = false;
var scrollPane = new philmaker.playground.NoteScrollPane(this.textMorph, new Rectangle(0, 0, 300, 300));
var controls = new philmaker.playground.RunnableCodeNoteControlMorph(this);
this.addMorph(scrollPane, {
weight : 1.0,
margin : new philmaker.foundation.Insets(20, 1, 1, 1)
});
this.addMorph(controls, {
weight : 26,
margin : new philmaker.foundation.Insets(3, 2, 0, 0)
});
this.adjustForNewBounds(); // hack for now
},
evaluate : function() {
var text = this.textMorph.textString;
try {
eval(text);
} catch (e) {
console.log('RunnableCodeNote evaluation failed.');
console.log(e);
}
},
prepareSampleText : function() {
var result = '';
for (var i = 0; i < 3; i++) {
result = result + 'console.log(\'Let\'s all go to the lobby...\');' + '\n';
}
return result;
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.RunnableCodeNoteControlMorph', {
initialize : function($super, codeNote) {
$super(new Rectangle(0, 0, 0, 0));
this.codeNote = codeNote;
this.setOrientation('horizontal');
this.setFillOpacity(0.0);
this.setStrokeOpacity(1.0);
var spacerMorph = new philmaker.foundation.BasicMorph(new lively.scene.Rectangle(new Rectangle(0, 0, 0, 0)));
var buttonMorph = new philmaker.playground.RunnableCodeNoteEvaluateButton(new Rectangle(0, 0, 300, 300), 'Evaluate', this.codeNote);
this.addMorph(buttonMorph, {
weight : 80, // this is an issue with my BoxLayoutMorph, if not wide enough then clips mouse event region
margin : new philmaker.foundation.Insets(0, 2, 0, 0)
});
this.addMorph(spacerMorph, {
weight : 1.0,
margin : new philmaker.foundation.Insets(0, 0, 0, 0)
});
this.adjustForNewBounds(); // hack for now
}
});
philmaker.foundation.TextMorph.subclass('philmaker.playground.RunnableCodeNoteEvaluateButton', { // fixme: slow down and try to use ButtonMorph instead
handlesMouseDown : Functions.True,
initialize : function($super, rectangle, text, codeNote) {
$super(rectangle, text);
this.codeNote = codeNote;
this.openForDragAndDrop = false;
this.suppressHandles = true;
this.initializeFills();
this.focusHaloBorderWidth = 0;
this.openForDragAndDrop = false;
this.beLabel();
this.applyStyle({ // without this after beLabel, setBorderColor below will not work
borderWidth : 1,
fontSize : 12,
});
if (false) {
buttonMorph.setBold(true);
}
this.setTextColor(Color.hsb(0, 0.0, 0.4));
this.setFill(Color.hsb(0, 0.0, 0.85));
this.setFill(this.normalFill);
this.setBorderColor(Color.hsb(0, 0.0, 0.75));
this.setStrokeOpacity(1.0);
this.setFillOpacity(1.0);
this.shapeRoundEdgesBy(5);
this.padding = Rectangle.inset(8, 3, 8, 3); // left, top, right, bottom (order?)
this.handlesMouseDown = Functions.True;
},
initializeTransientState : function() {
this.initializeFills();
},
initializeFills : function() {
var hue = 0;
var saturation = 0.0;
this.normalFill = new lively.paint.LinearGradient([
new lively.paint.Stop(0, Color.hsb(hue, saturation, 0.99)),
new lively.paint.Stop(1, Color.hsb(hue, saturation, 0.70))
], lively.paint.LinearGradient.NorthSouth);
this.pressedFill = new lively.paint.LinearGradient([
new lively.paint.Stop(0, Color.hsb(hue, saturation, 0.79)),
new lively.paint.Stop(1, Color.hsb(hue, saturation, 0.50))
], lively.paint.LinearGradient.NorthSouth);
},
ignoreEvents : function($super) { // because beLabel calls ignore events
;
},
onMouseDown : function($super, evt) {
this.setFill(this.pressedFill);
return true;
},
onMouseUp : function($super, evt) {
this.setFill(this.normalFill);
this.codeNote.evaluate(); // fixme: need to look into Lively's model mechanism
return true;
}
});
ScrollPane.subclass('philmaker.playground.NoteScrollPane', {
initialize : function($super, morphToClip, initialBounds) {
$super(morphToClip, initialBounds);
this.scrollBar.takesKeyboardFocus = Functions.False;
this.scrollBar.applyStyle({
borderWidth : 0,
borderColor : Color.red
});
this.scrollBar.setFillOpacity(0.0);
this.scrollBar.setBorderWidth(0); // this function is all a quick fix because Slider.adjustSliderParts
this.scrollBar.setBorderWidth = function($super, width) { // invokes this: this.setBorderWidth(this.slider.getBorderWidth());
$super(0);
};
this.scrollBar.slider.setFill(Color.hsb(0, 0.0, 0.0));
this.scrollBar.slider.setFillOpacity(0.03);
this.scrollBar.slider.setBorderWidth(1);
this.scrollBar.slider.setBorderColor(Color.hsb(29, 0.0, 0.0));
this.scrollBar.slider.setStrokeOpacity(0.06);
this.scrollBarWidth = 8;
if (true) {
this.scrollBar.slider.setFillOpacity(0.05);
this.scrollBar.slider.setStrokeOpacity(0.065);
}
}
});
philmaker.foundation.TextMorph.subclass('philmaker.playground.StickyNote', { // need to be able to detect system fonts or the system
// and also be able to plug in alternates
initialize : function($super) {
var rectangle = new Rectangle(200, 200, 300, 10);
$super(rectangle);
this.setFill(Color.rgb(255, 254, 164));
this.setBorderColor(Color.rgb(255, 240, 146));
this.setBorderWidth(1);
this.setFillOpacity(1.0);
this.setStrokeOpacity(1.0);
this.setTextColor(Color.rgb(127, 62, 0));
this.setFontFamily('Marker Felt');
this.setFontSize(18);
this.focusHaloBorderWidth = 0;
this.rotateBy(-0.05);
this.textString = philmaker.foundation.sampleText;
}
});
philmaker.foundation.TextMorph.subclass('philmaker.playground.CodeNote', { // need to be able to detect system fonts, or the users system
// and also offer font alternatives
initialize : function($super) { // add: run, preamble, postscript
var rectangle = new Rectangle(220, 220, 300, 10);
$super(rectangle);
this.setFill(Color.hsb(0, 0.0, 0.9));
this.setBorderColor(Color.hsb(0, 0.0, 0.8));
this.setBorderWidth(1);
this.setFillOpacity(1.0);
this.setStrokeOpacity(1.0);
this.setTextColor(Color.hsb(0, 0.0, 0.0));
if (true) {
this.setFontFamily('Monaco');
this.setFontSize(10);
this.emphasizeBoldItalic({
style : ''
});
} else {
this.setFontFamily('Verdana');
this.setFontSize(10);
this.emphasizeBoldItalic({
style : 'bold'
});
}
this.focusHaloBorderWidth = 0;
var text = '';
for (var i = 0; i < 3; i++) {
text = text + 'console.log(\'Let\'s all go to the lobby...\');' + '\n';
}
this.setTextString(text);
}
});
Morph.subclass('philmaker.playground.WormholeMorph', {
openForDragAndDrop: false,
suppressHandles : true,
styleClass: [],
initialize : function($super) {
$super(new lively.scene.Ellipse(pt(200, 200), 55));
this.setFillOpacity(1.0);
//this.setFill(Color.hsb(209, .9, .99));
this.setFill(Color.hsb(287, .9, .99));
this.setBorderWidth(0);
for (var i = 0; i < 8; i++) {
var leg = new philmaker.playground.WormholeLegMorph();
leg.setPosition(pt(-50, 0));
leg.rotateBy(0.78 * i);
this.addMorph(leg);
}
this.setScale(.4);
if (false) {
this.beClipMorph();
}
WorldMorph.current().scheduleForLater(new SchedulableAction(this, 'invokeSteppingScript'), 5, false);
},
invokeSteppingScript : function() {
this.startStepping(50, 'twirl');
},
twirl : function() {
this.rotateBy(0.015);
}
});
Morph.subclass('philmaker.playground.WormholeLegMorph', {
openForDragAndDrop : false,
suppressHandles : true,
initialize : function($super) {
var path = [];
path.push(new lively.scene.MoveTo(0, 0));
path.push(new lively.scene.QuadCurveTo(-50, 50, -35, 10));
path.push(new lively.scene.LineTo(-25, 50));
path.push(new lively.scene.QuadCurveTo(0, 0, -20, 10));
path.push(new lively.scene.ClosePath());
$super(new lively.scene.Path(path));
//this.setPosition(pt(100, 100));
//this.shape.translateBy(200, 200);
//this.moveOriginBy(pt(50, 50));
//this.setScalePoint(pt(3, 3));
//this.setFill(Color.hsb(209, .39, .99));
this.setFill(Color.hsb(287, .39, .99));
this.setBorderWidth(0);
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.BoxLayoutMorph', { // philmaker.foundation.BoxLayoutMorph test morph
margin : new Rectangle(8, 8, 8, 8),
initialize : function($super) {
$super(new Rectangle(100, 100, 300, 300));
this.setOrientation('horizontal');
this.setFill(Color.white);
this.setFillOpacity(1.0);
this.setBorderColor(Color.red);
this.setBorderWidth(1);
this.shapeRoundEdgesBy(0);
this.padding = Rectangle.inset(10, 10, 10, 10);
this.suppressHandles = false;
var rectangle = new Rectangle(0, 0, 150, 500);
this.leftTextMorph = new TextMorph(rectangle, this.prepareSidebarText(), 'left');
this.leftTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.centerTextMorph = new philmaker.playground.BoxLayoutMorph2();
this.centerTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.rightTextMorph = new TextMorph(rectangle, this.prepareSidebarText(), 'right');
this.rightTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.addMorph(this.leftTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(5, 5, 5, 5)
});
this.addMorph(this.centerTextMorph, {
weight : 0.6,
margin : new philmaker.foundation.Insets(5, 5, 5, 5)
});
this.addMorph(this.rightTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(5, 5, 5, 5)
});
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.adjustForNewBounds(); // hack for now
},
prepareSidebarText : function() {
var result = '';
for (var i = 0; i < 20; i++) {
result = result + 'sidebar link' + '\n';
}
return result;
}
});
philmaker.foundation.BoxLayoutMorph.subclass('philmaker.playground.BoxLayoutMorph2', { // philmaker.foundation.BoxLayoutMorph test morph
initialize : function($super) {
$super(new Rectangle(0, 0, 100, 300));
this.setOrientation('vertical');
this.setFill(Color.white);
this.setFillOpacity(1.0);
this.setBorderWidth(1);
this.shapeRoundEdgesBy(0);
this.padding = Rectangle.inset(10, 10, 10, 10);
var rectangle = new Rectangle(0, 0, 150, 500);
this.headerTextMorph = new TextMorph(rectangle, 'Lively: The Web Done Right', 'header');
this.headerTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.bodyTextMorph = new TextMorph(rectangle, this.prepareSidebarText(), 'body');
this.bodyTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.footerTextMorph = new TextMorph(rectangle, 'Copyright Bullwikle J. Moose', 'footer');
this.footerTextMorph.padding = Rectangle.inset(5, 5, 5, 5);
this.addMorph(this.headerTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(0, 5, 5, 5)
});
this.addMorph(this.bodyTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(5, 5, 5, 5)
});
this.addMorph(this.footerTextMorph, {
weight : 0.2,
margin : new philmaker.foundation.Insets(5, 5, 0, 5)
});
if (philmaker.foundation.layoutBorders) {
this.setBorderWidth(1);
this.setBorderColor(Color.red);
}
this.adjustForNewBounds(); // hack for now
},
prepareSidebarText : function() {
var result = '';
for (var i = 0; i < 20; i++) {
result = result + 'sidebar link' + '\n';
}
return result;
}
});
PanelMorph.subclass('philmaker.playground.PanelMorph', { // was previously a simple isolated test case to study PanelMorph and padding
// underlying issue: PanelMorph does not appear to account for gaps between submorphs (review)
initialize : function($super) { // and GridLayoutMorph does not appear to support adjustForNewBounds
},
adjustForNewBounds : function ($super) {
$super();
var extent = this.getExtent();
var padding = this.padding;
this.submorphs.forEach(function(submorph) {
submorph.setPosition(pt(padding.left, padding.top));
submorph.setExtent(pt(extent.x - (padding.left + padding.right), extent.y - (padding.top + padding.bottom)));
});
}
});
Object.subclass('MetamorphosisDemo', {
initialize : function() {
console.log('Hello world');
var morph = Morph.makeRectangle(pt(100, 100), pt(60, 30));
morph.suppressHandles = true;
morph.openForDragAndDrop = false;
morph.handlesMouseDown = Functions.True;
var self = morph;
WorldMorph.current().addMorph(morph);
this.metamorphObject(morph, philmaker.playground.TickleMorph);
},
metamorphObject : function(object, clazz) {
if (true) {
object.__proto__ = clazz.prototype;
} else {
for (var i in clazz.prototype) {
if (clazz.prototype.hasOwnProperty(i)) {
object[i] = clazz.prototype[i];
}
}
}
}
});
Morph.subclass('philmaker.playground.TickleMorph', {
handlesMouseDown : Functions.True,
initialize : function($super, shape) {
$super(shape);
},
initializeTransientState : function() {
this.handlesMouseDown = Functions.True;
this.suppressHandles = true;
this.openForDragAndDrop = false;
},
onMouseDown : function(event) {
window.alert('Please do not tickle me.');
if (this instanceof philmaker.playground.TickleMorph) {
console.log('instanceof philmaker.playground.TickleMorph');
} else {
console.log('not instanceof philmaker.playground.TickleMorph');
}
}
});
try {
var worldInitializer = new philmaker.playground.WorldInitializer();
if (true) {
worldInitializer.initializePreamble();
} else {
worldInitializer.initializePostscript();
}
} catch (e) {
console.log('Exception in philmaker.playground.WorldInitializer: ' + JSON.serialize(e));
}
try {
new philmaker.playground.WorldInitializer();
} catch (e) {
console.log('Exception creating philmaker.playground.WorldInitializer');
console.log(e);
}
null
ServerPreparation:InstallingApache&Lively
20
27
false
null
8
null
null
Toolbox
20
null
null
PreparingApacheforLivelyThesestepswereperformedforLinuxunderUbuntu8.04HardyHeronrunningatslicehost.com.ConnectingtothemachineasrootusingsshfromMacOSX10.5.6Caveats:TheversionofApachewashavingtroublewithdigestauthenticationsothissetupexampleisusingbasicauthenticationonly.Therecommendationistousesomethingbetterthanbasicauthentication.Apachemodulesmaybeconfiguredpermanently(a2enmod)oratruntimeinhttpd.conf(LoadModule).WhenIrehearsedthesestepsforthiswriteup,IdidnotgetLoadModuleworkingreliablyquicklyforWebDavsoIstopped.RunningasrootIthinkisabadideabutIdiditforthiswriteup.#connect,updatethesystem,andinstalltheApachewebserverssh<username-or-root>@<host>sudoapt-getupdatesudoapt-getinstallapache2a2enmoddava2enmoddav_fsa2enmodauth_digesta2enmodproxya2enmodproxy_httpa2enmodrewriteapt-getinstallsubversioncd/varmkdirlively-kernelcdlively-kernelsvncheckouthttp://livelykernel.sunlabs.com/repository/lively-kernel/trunk/#copythekernelclientfilestowebdocumentroot-thiswillforceoverwritetheexistingApacheindex.htmlpage(warning!)cp-rftrunk/source/kernel/*/var/www#thesecommandsensurethatWebDavhaspermissionsforApache'sdocumentrootcd/varchmod-R755wwwchown-Rwww-datawwwchgrp-Rwww-datawww#importantcaveat:ifyoulatermanuallyuploadfiles,forexampleusingftpandnotWebDav,youlikelyneedtoissuetheseagain#createusernameandpasswordforWebDavaccesshtpasswd-c/etc/apache2/access<webdav-username>#otherwiseauthdigestwouldbelike:htdigest-c/etc/apache2/accessglobal<webdav-username>#editthewebserverconfigurationwithhttpd.confsource#ifyouarenotfamilarwiththevieditoritwilllikelybeeasierjusttouploadhttpd.confusinganftpclientvi/etc/apache2/httpd.conf#runorreloadthewebserversudo/etc/init.d/apache2restart#sudo/etc/init.d/apache2force-reload#nowconfiguretheLivelyinstall#pending
@\rsudo apt-get update\r\rsudo apt-get install apache2\ra2enmod dav\ra2enmod dav_fs\ra2enmod auth_digest\ra2enmod proxy\ra2enmod proxy_http\ra2enmod rewrite\r\rapt-get install subversion\rcd /var\rmkdir lively-kernel\rcd lively-kernel\rsvn checkout http://livelykernel.sunlabs.com/repository/lively-kernel/trunk/\r# copy the kernel client files to web document root - this will force overwrite the existing Apache index.html page (warning!)\rcp -rf trunk/source/kernel/* /var/www\r\r# these commands ensure that WebDav has permissions for Apache's document root\rcd /var\rchmod -R 755 www\rchown -R www-data www\rchgrp -R www-data www\r# important caveat: if you later manually upload files, for example using ftp and not WebDav, you likely need to issue these again\r\r# create username and password for WebDav access\rhtpasswd -c /etc/apache2/access \r# otherwise auth digest would be like: htdigest -c /etc/apache2/access global \r\r# edit the web server configuration with httpd.conf source\r# if you are not familar with the vi editor it will likely be easier just to upload httpd.conf using an ftp client\rvi /etc/apache2/httpd.conf\r\r# run or reload the web server\rsudo /etc/init.d/apache2 restart\r# sudo /etc/init.d/apache2 force-reload\r\r# now configure the Lively install\r# pending"]]>
0
true
2069
false
595
@\rsudo apt-get update\r\rsudo apt-get install apache2\ra2enmod dav\ra2enmod dav_fs\ra2enmod auth_digest\ra2enmod proxy\ra2enmod proxy_http\ra2enmod rewrite\r\rapt-get install subversion\rcd /var\rmkdir lively-kernel\rcd lively-kernel\rsvn checkout http://livelykernel.sunlabs.com/repository/lively-kernel/trunk/\r# copy the kernel client files to web document root - this will force overwrite the existing Apache index.html page (warning!)\rcp -rf trunk/source/kernel/* /var/www\r\r# these commands ensure that WebDav has permissions for Apache's document root\rcd /var\rchmod -R 755 www\rchown -R www-data www\rchgrp -R www-data www\r# important caveat: if you later manually upload files, for example using ftp and not WebDav, you likely need to issue these again\r\r# create username and password for WebDav access\rhtpasswd -c /etc/apache2/access \r# otherwise auth digest would be like: htdigest -c /etc/apache2/access global \r\r# edit the web server configuration with httpd.conf source\r# if you are not familar with the vi editor it will likely be easier just to upload httpd.conf using an ftp client\rvi /etc/apache2/httpd.conf\r\r# run or reload the web server\rsudo /etc/init.d/apache2 restart\r# sudo /etc/init.d/apache2 force-reload\r\r# now configure the Lively install\r# pending"]]>
null
52
true
null
null
1
true
null
true
8
false
null
0.09720534629404617
null
Toolbox
20
null
null
null
<VirtualHost*>ServerAdminyou@yourdomain.comServerNameyourdomain.comServerAliaswww.yourdomain.comDocumentRoot/var/www<Directory/var/www>OptionsIndexesMultiViewsAllowOverrideNoneOrderallow,denyallowfromall</Directory><Location/>DAVOnAuthTypeBasicAuthName"RestrictedFiles"AuthUserFile/etc/apache2/access<LimitExceptGETOPTIONSPROPFIND>Requirevalid-user</LimitExcept></Location><Proxy*>Orderdeny,allowAllowfromall</Proxy>#seealso:trunk/source/kernel/example.htaccess&example.htpasswd#considertheimplicationsofalloftheseproxiesbeforehostingapublicsiteRewriteEngineOnRewriteRule^/proxy/news.com.com(.*)$http://news.com.com$1[P]RewriteRule^/proxy/news.cnet.com(.*)$http://news.cnet.com$1[P]RewriteRule^/proxy/weatherforecastmap.com(.*)$http://weatherforecastmap.com$1[P]RewriteRule^/proxy/feeds.bbc.co.uk(.*)$http://feeds.bbc.co.uk$1[P]RewriteRule^/proxy/finance.google.com(.*)$http://finance.google.com$1[P]RewriteRule^/proxy/download.finance.yahoo.com(.*)$http://download.finance.yahoo.com$1[P]RewriteRule^/proxy/feeds.feedburner.com(.*)$http://feeds.feedburner.com$1[P]RewriteRule^/proxy/blogs.sun.com(.*)$http://blogs.sun.com$1[P]RewriteRule^/proxy/feeds.tuaw.com(.*)$http://feeds.tuaw.com$1[P]RewriteRule^/proxy/api.flickr.com/services/rest/http://api.flickr.com/services/rest/?api_key=YOUR_KEY[QSA,P]</VirtualHost>
\n\tServerAdmin you@yourdomain.com\n\tServerName yourdomain.com\n\tServerAlias www.yourdomain.com\n\t\n\tDocumentRoot /var/www\n\t\n\t\tOptions Indexes MultiViews\n\t\tAllowOverride None\n\t\tOrder allow,deny\n\t\tallow from all\n\t\n\t\n\t\n\t\tDAV On\n\t\tAuthType Basic\n\t\tAuthName \"Restricted Files\"\n\t\tAuthUserFile /etc/apache2/access\n\t\t\n\t\t\tRequire valid-user\n\t\t\n\t\n\t\n\t\n\t\tOrder deny,allow\n\t\tAllow from all\n\t \n\n\t# see also: trunk/source/kernel/example.htaccess & example.htpasswd\r\t# consider the implications of all of these proxies before hosting a public site\n\tRewriteEngine On\r\tRewriteRule ^/proxy/news.com.com(.*)$ http://news.com.com$1 [P]\r\tRewriteRule ^/proxy/news.cnet.com(.*)$ http://news.cnet.com$1 [P]\r\tRewriteRule ^/proxy/weatherforecastmap.com(.*)$ http://weatherforecastmap.com$1 [P]\r\tRewriteRule ^/proxy/feeds.bbc.co.uk(.*)$ http://feeds.bbc.co.uk$1 [P]\r\tRewriteRule ^/proxy/finance.google.com(.*)$ http://finance.google.com$1 [P]\r\tRewriteRule ^/proxy/download.finance.yahoo.com(.*)$ http://download.finance.yahoo.com$1 [P]\r\tRewriteRule ^/proxy/feeds.feedburner.com(.*)$ http://feeds.feedburner.com$1 [P]\r\tRewriteRule ^/proxy/blogs.sun.com(.*)$ http://blogs.sun.com$1 [P]\r\tRewriteRule ^/proxy/feeds.tuaw.com(.*)$ http://feeds.tuaw.com$1 [P]\r\tRewriteRule ^/proxy/api.flickr.com/services/rest/ http://api.flickr.com/services/rest/?api_key=YOUR_KEY [QSA,P]\r\n"]]>
41
0
true
55
false
\n\t\r\t# see also"]]>
523
\n\tServerAdmin you@yourdomain.com\n\tServerName yourdomain.com\n\tServerAlias www.yourdomain.com\n\t\n\tDocumentRoot /var/www\n\t\n\t\tOptions Indexes MultiViews\n\t\tAllowOverride None\n\t\tOrder allow,deny\n\t\tallow from all\n\t\n\t\n\t\n\t\tDAV On\n\t\tAuthType Basic\n\t\tAuthName \"Restricted Files\"\n\t\tAuthUserFile /etc/apache2/access\n\t\t\n\t\t\tRequire valid-user\n\t\t\n\t\n\t\r\t# see also: trunk/source/kernel/example.htaccess & example.htpasswd\r\t# consider the implications of all of these proxies before hosting a public site\n\tRewriteEngine On\r\tRewriteRule ^/proxy/news.com.com(.*)$ http://news.com.com$1 [P]\r\tRewriteRule ^/proxy/news.cnet.com(.*)$ http://news.cnet.com$1 [P]\r\tRewriteRule ^/proxy/weatherforecastmap.com(.*)$ http://weatherforecastmap.com$1 [P]\r\tRewriteRule ^/proxy/feeds.bbc.co.uk(.*)$ http://feeds.bbc.co.uk$1 [P]\r\tRewriteRule ^/proxy/finance.google.com(.*)$ http://finance.google.com$1 [P]\r\tRewriteRule ^/proxy/download.finance.yahoo.com(.*)$ http://download.finance.yahoo.com$1 [P]\r\tRewriteRule ^/proxy/feeds.feedburner.com(.*)$ http://feeds.feedburner.com$1 [P]\r\tRewriteRule ^/proxy/blogs.sun.com(.*)$ http://blogs.sun.com$1 [P]\r\tRewriteRule ^/proxy/feeds.tuaw.com(.*)$ http://feeds.tuaw.com$1 [P]\r\tRewriteRule ^/proxy/api.flickr.com/services/rest/ http://api.flickr.com/services/rest/?api_key=YOUR_KEY [QSA,P]\r\n"]]>
\n\t\n\t\n\t\tOrder deny,allow\n\t\tAllow from all\n\t \n\n\t# see also"]]>
null
true
1
true
null
true
8
false
null
0.1188707280832095
null
Instructions
20
10
false
null
1
null
0
null
AboveareinstructionsforpreparingApachetobeabletosaveworldsusingWebDavandalsotobeablesetupproxiesformakingNetRequestsinLively.TheseareprovidedbyaLivelyuserandmaynotbeideal.Atthistimetheyareintendedjusttogetupandrunningandthesecurityneedstoberevisitedbyyourself.
18
0
true
202
true
203
null
8
true
1
true
true
8
-0.049999999200753306
false
null
httpd.conf
20
4
true
10
null
0
null
1239816913730
1021
1
NaN
null
1239816913
null