aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfriendica <info@friendica.com>2015-01-01 22:33:28 -0800
committerfriendica <info@friendica.com>2015-01-01 22:33:28 -0800
commit82d0a4af452015e870bdcea56f1008ea22d066b3 (patch)
tree3ad1db1aeb0dfdeb10a70b99da353fe3094f1d69
parent9a34e18319301e0a952f674899aeb58b424637a4 (diff)
parent68c612c597471404201099ecbc8b4082d152e18a (diff)
downloadvolse-hubzilla-82d0a4af452015e870bdcea56f1008ea22d066b3.tar.gz
volse-hubzilla-82d0a4af452015e870bdcea56f1008ea22d066b3.tar.bz2
volse-hubzilla-82d0a4af452015e870bdcea56f1008ea22d066b3.zip
Merge branch 'master' into trinidad
-rw-r--r--assets/home.html79
-rw-r--r--include/datetime.php47
-rw-r--r--include/permissions.php38
-rw-r--r--library/HTMLPurifier.autoload.php8
-rw-r--r--library/HTMLPurifier.composer.php4
-rw-r--r--library/HTMLPurifier.func.php8
-rw-r--r--library/HTMLPurifier.includes.php21
-rw-r--r--library/HTMLPurifier.kses.php4
-rw-r--r--library/HTMLPurifier.php137
-rw-r--r--library/HTMLPurifier.safe-includes.php19
-rw-r--r--library/HTMLPurifier/Arborize.php71
-rw-r--r--library/HTMLPurifier/AttrCollections.php53
-rw-r--r--library/HTMLPurifier/AttrDef.php53
-rw-r--r--library/HTMLPurifier/AttrDef/CSS.php39
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/AlphaValue.php27
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Background.php60
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php54
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Border.php21
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Color.php67
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Composite.php22
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php28
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Filter.php49
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Font.php89
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/FontFamily.php185
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Ident.php32
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php28
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Length.php60
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/ListStyle.php78
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Multiple.php31
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Number.php45
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/Percentage.php36
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/TextDecoration.php20
-rw-r--r--library/HTMLPurifier/AttrDef/CSS/URI.php38
-rw-r--r--library/HTMLPurifier/AttrDef/Clone.php44
-rw-r--r--library/HTMLPurifier/AttrDef/Enum.php28
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/Bool.php35
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/Class.php22
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/Color.php45
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/FrameTarget.php25
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/ID.php71
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/Length.php41
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/LinkTypes.php43
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/MultiLength.php51
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/Nmtokens.php40
-rw-r--r--library/HTMLPurifier/AttrDef/HTML/Pixels.php60
-rw-r--r--library/HTMLPurifier/AttrDef/Integer.php56
-rw-r--r--library/HTMLPurifier/AttrDef/Lang.php39
-rw-r--r--library/HTMLPurifier/AttrDef/Switch.php27
-rw-r--r--library/HTMLPurifier/AttrDef/Text.php10
-rw-r--r--library/HTMLPurifier/AttrDef/URI.php72
-rw-r--r--library/HTMLPurifier/AttrDef/URI/Email.php5
-rw-r--r--library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php14
-rw-r--r--library/HTMLPurifier/AttrDef/URI/Host.php104
-rw-r--r--library/HTMLPurifier/AttrDef/URI/IPv4.php28
-rw-r--r--library/HTMLPurifier/AttrDef/URI/IPv6.php106
-rw-r--r--library/HTMLPurifier/AttrTransform.php28
-rw-r--r--library/HTMLPurifier/AttrTransform/Background.php21
-rw-r--r--library/HTMLPurifier/AttrTransform/BdoDir.php14
-rw-r--r--library/HTMLPurifier/AttrTransform/BgColor.php21
-rw-r--r--library/HTMLPurifier/AttrTransform/BoolToCSS.php33
-rw-r--r--library/HTMLPurifier/AttrTransform/Border.php18
-rw-r--r--library/HTMLPurifier/AttrTransform/EnumToCSS.php46
-rw-r--r--library/HTMLPurifier/AttrTransform/ImgRequired.php19
-rw-r--r--library/HTMLPurifier/AttrTransform/ImgSpace.php39
-rw-r--r--library/HTMLPurifier/AttrTransform/Input.php34
-rw-r--r--library/HTMLPurifier/AttrTransform/Lang.php15
-rw-r--r--library/HTMLPurifier/AttrTransform/Length.php28
-rw-r--r--library/HTMLPurifier/AttrTransform/Name.php22
-rw-r--r--library/HTMLPurifier/AttrTransform/NameSync.php28
-rw-r--r--library/HTMLPurifier/AttrTransform/Nofollow.php52
-rw-r--r--library/HTMLPurifier/AttrTransform/SafeEmbed.php12
-rw-r--r--library/HTMLPurifier/AttrTransform/SafeObject.php16
-rw-r--r--library/HTMLPurifier/AttrTransform/SafeParam.php29
-rw-r--r--library/HTMLPurifier/AttrTransform/ScriptRequired.php9
-rw-r--r--library/HTMLPurifier/AttrTransform/TargetBlank.php45
-rw-r--r--library/HTMLPurifier/AttrTransform/Textarea.php19
-rw-r--r--library/HTMLPurifier/AttrTypes.php45
-rw-r--r--library/HTMLPurifier/AttrValidator.php66
-rw-r--r--library/HTMLPurifier/Bootstrap.php90
-rw-r--r--library/HTMLPurifier/CSSDefinition.php452
-rw-r--r--library/HTMLPurifier/ChildDef.php26
-rw-r--r--library/HTMLPurifier/ChildDef/Chameleon.php33
-rw-r--r--library/HTMLPurifier/ChildDef/Custom.php56
-rw-r--r--library/HTMLPurifier/ChildDef/Empty.php22
-rw-r--r--library/HTMLPurifier/ChildDef/List.php86
-rw-r--r--library/HTMLPurifier/ChildDef/Optional.php31
-rw-r--r--library/HTMLPurifier/ChildDef/Required.php103
-rw-r--r--library/HTMLPurifier/ChildDef/StrictBlockquote.php96
-rw-r--r--library/HTMLPurifier/ChildDef/Table.php302
-rw-r--r--library/HTMLPurifier/Config.php681
-rw-r--r--library/HTMLPurifier/ConfigSchema.php78
-rw-r--r--library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php8
-rw-r--r--library/HTMLPurifier/ConfigSchema/Builder/Xml.php94
-rw-r--r--library/HTMLPurifier/ConfigSchema/Interchange.php11
-rw-r--r--library/HTMLPurifier/ConfigSchema/Interchange/Directive.php28
-rw-r--r--library/HTMLPurifier/ConfigSchema/Interchange/Id.php33
-rw-r--r--library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php90
-rw-r--r--library/HTMLPurifier/ConfigSchema/Validator.php90
-rw-r--r--library/HTMLPurifier/ConfigSchema/ValidatorAtom.php108
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema.serbin13244 -> 15000 bytes
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt12
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt13
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt9
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt11
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt16
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt3
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt14
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt9
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt6
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt11
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt11
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt5
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt11
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt10
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt15
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt17
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt11
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt7
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt13
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt10
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt8
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt1
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt15
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt4
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt7
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt2
-rw-r--r--library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt22
-rw-r--r--library/HTMLPurifier/ContentSets.php55
-rw-r--r--library/HTMLPurifier/Context.php61
-rw-r--r--library/HTMLPurifier/Definition.php26
-rw-r--r--library/HTMLPurifier/DefinitionCache.php57
-rw-r--r--library/HTMLPurifier/DefinitionCache/Decorator.php76
-rw-r--r--library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php61
-rw-r--r--library/HTMLPurifier/DefinitionCache/Decorator/Memory.php65
-rw-r--r--library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in59
-rw-r--r--library/HTMLPurifier/DefinitionCache/Null.php53
-rw-r--r--library/HTMLPurifier/DefinitionCache/Serializer.php235
-rwxr-xr-x[-rw-r--r--]library/HTMLPurifier/DefinitionCache/Serializer/README0
-rw-r--r--library/HTMLPurifier/DefinitionCacheFactory.php47
-rw-r--r--library/HTMLPurifier/Doctype.php17
-rw-r--r--library/HTMLPurifier/DoctypeRegistry.php87
-rw-r--r--library/HTMLPurifier/ElementDef.php85
-rw-r--r--library/HTMLPurifier/Encoder.php301
-rw-r--r--library/HTMLPurifier/EntityLookup.php16
-rw-r--r--library/HTMLPurifier/EntityLookup/entities.ser2
-rw-r--r--library/HTMLPurifier/EntityParser.php53
-rw-r--r--library/HTMLPurifier/ErrorCollector.php87
-rw-r--r--library/HTMLPurifier/ErrorStruct.php20
-rw-r--r--library/HTMLPurifier/Filter.php18
-rw-r--r--library/HTMLPurifier/Filter/ExtractStyleBlocks.php257
-rw-r--r--library/HTMLPurifier/Filter/YouTube.php56
-rw-r--r--library/HTMLPurifier/Generator.php164
-rw-r--r--library/HTMLPurifier/HTMLDefinition.php211
-rw-r--r--library/HTMLPurifier/HTMLModule.php122
-rw-r--r--library/HTMLPurifier/HTMLModule/Bdo.php21
-rw-r--r--library/HTMLPurifier/HTMLModule/CommonAttributes.php7
-rw-r--r--library/HTMLPurifier/HTMLModule/Edit.php25
-rw-r--r--library/HTMLPurifier/HTMLModule/Forms.php216
-rw-r--r--library/HTMLPurifier/HTMLModule/Hypertext.php15
-rw-r--r--library/HTMLPurifier/HTMLModule/Iframe.php51
-rw-r--r--library/HTMLPurifier/HTMLModule/Image.php17
-rw-r--r--library/HTMLPurifier/HTMLModule/Legacy.php89
-rw-r--r--library/HTMLPurifier/HTMLModule/List.php28
-rw-r--r--library/HTMLPurifier/HTMLModule/Name.php13
-rw-r--r--library/HTMLPurifier/HTMLModule/Nofollow.php25
-rw-r--r--library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php6
-rw-r--r--library/HTMLPurifier/HTMLModule/Object.php31
-rw-r--r--library/HTMLPurifier/HTMLModule/Presentation.php26
-rw-r--r--library/HTMLPurifier/HTMLModule/Proprietary.php19
-rw-r--r--library/HTMLPurifier/HTMLModule/Ruby.php17
-rw-r--r--library/HTMLPurifier/HTMLModule/SafeEmbed.php20
-rw-r--r--library/HTMLPurifier/HTMLModule/SafeObject.php33
-rw-r--r--library/HTMLPurifier/HTMLModule/SafeScripting.php40
-rw-r--r--library/HTMLPurifier/HTMLModule/Scripting.php31
-rw-r--r--library/HTMLPurifier/HTMLModule/StyleAttribute.php15
-rw-r--r--library/HTMLPurifier/HTMLModule/Tables.php29
-rw-r--r--library/HTMLPurifier/HTMLModule/Target.php11
-rw-r--r--library/HTMLPurifier/HTMLModule/TargetBlank.php24
-rw-r--r--library/HTMLPurifier/HTMLModule/Text.php56
-rw-r--r--library/HTMLPurifier/HTMLModule/Tidy.php85
-rw-r--r--library/HTMLPurifier/HTMLModule/Tidy/Name.php15
-rw-r--r--library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php14
-rw-r--r--library/HTMLPurifier/HTMLModule/Tidy/Strict.php28
-rw-r--r--library/HTMLPurifier/HTMLModule/Tidy/Transitional.php7
-rw-r--r--library/HTMLPurifier/HTMLModule/Tidy/XHTML.php15
-rw-r--r--library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php146
-rw-r--r--library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php6
-rw-r--r--library/HTMLPurifier/HTMLModuleManager.php166
-rw-r--r--library/HTMLPurifier/IDAccumulator.php24
-rw-r--r--library/HTMLPurifier/Injector.php198
-rw-r--r--library/HTMLPurifier/Injector/AutoParagraph.php99
-rw-r--r--library/HTMLPurifier/Injector/DisplayLinkURI.php22
-rw-r--r--library/HTMLPurifier/Injector/Linkify.php27
-rw-r--r--library/HTMLPurifier/Injector/PurifierLinkify.php46
-rw-r--r--library/HTMLPurifier/Injector/RemoveEmpty.php82
-rw-r--r--library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php36
-rw-r--r--library/HTMLPurifier/Injector/SafeObject.php53
-rw-r--r--library/HTMLPurifier/Language.php97
-rw-r--r--library/HTMLPurifier/Language/classes/en-x-test.php3
-rw-r--r--library/HTMLPurifier/Language/messages/en.php90
-rw-r--r--library/HTMLPurifier/LanguageFactory.php81
-rw-r--r--library/HTMLPurifier/Length.php91
-rw-r--r--library/HTMLPurifier/Lexer.php191
-rw-r--r--library/HTMLPurifier/Lexer/DOMLex.php161
-rw-r--r--library/HTMLPurifier/Lexer/DirectLex.php217
-rw-r--r--library/HTMLPurifier/Lexer/PEARSax3.php139
-rw-r--r--library/HTMLPurifier/Lexer/PH5P.php4324
-rw-r--r--library/HTMLPurifier/Node.php49
-rw-r--r--library/HTMLPurifier/Node/Comment.php36
-rw-r--r--library/HTMLPurifier/Node/Element.php59
-rw-r--r--library/HTMLPurifier/Node/Text.php54
-rw-r--r--library/HTMLPurifier/PercentEncoder.php37
-rw-r--r--library/HTMLPurifier/Printer.php134
-rw-r--r--library/HTMLPurifier/Printer/CSSDefinition.php12
-rw-r--r--library/HTMLPurifier/Printer/ConfigForm.php257
-rw-r--r--library/HTMLPurifier/Printer/HTMLDefinition.php214
-rw-r--r--library/HTMLPurifier/PropertyList.php68
-rw-r--r--library/HTMLPurifier/PropertyListIterator.php22
-rw-r--r--library/HTMLPurifier/Queue.php56
-rw-r--r--library/HTMLPurifier/Strategy.php8
-rw-r--r--library/HTMLPurifier/Strategy/Composite.php13
-rw-r--r--library/HTMLPurifier/Strategy/Core.php5
-rw-r--r--library/HTMLPurifier/Strategy/FixNesting.php349
-rw-r--r--library/HTMLPurifier/Strategy/MakeWellFormed.php379
-rw-r--r--library/HTMLPurifier/Strategy/RemoveForeignElements.php94
-rw-r--r--library/HTMLPurifier/Strategy/ValidateAttributes.php22
-rw-r--r--library/HTMLPurifier/StringHash.php16
-rw-r--r--library/HTMLPurifier/StringHashParser.php52
-rw-r--r--library/HTMLPurifier/TagTransform.php15
-rw-r--r--library/HTMLPurifier/TagTransform/Font.php42
-rw-r--r--library/HTMLPurifier/TagTransform/Simple.php21
-rw-r--r--library/HTMLPurifier/Token.php81
-rw-r--r--library/HTMLPurifier/Token/Comment.php24
-rw-r--r--library/HTMLPurifier/Token/Empty.php6
-rw-r--r--library/HTMLPurifier/Token/End.php9
-rw-r--r--library/HTMLPurifier/Token/Start.php1
-rw-r--r--library/HTMLPurifier/Token/Tag.php22
-rw-r--r--library/HTMLPurifier/Token/Text.php34
-rw-r--r--library/HTMLPurifier/TokenFactory.php80
-rw-r--r--library/HTMLPurifier/URI.php257
-rw-r--r--library/HTMLPurifier/URIDefinition.php39
-rw-r--r--library/HTMLPurifier/URIFilter.php45
-rw-r--r--library/HTMLPurifier/URIFilter/DisableExternal.php45
-rw-r--r--library/HTMLPurifier/URIFilter/DisableExternalResources.php17
-rw-r--r--library/HTMLPurifier/URIFilter/DisableResources.php22
-rw-r--r--library/HTMLPurifier/URIFilter/HostBlacklist.php31
-rw-r--r--library/HTMLPurifier/URIFilter/MakeAbsolute.php74
-rw-r--r--library/HTMLPurifier/URIFilter/Munge.php91
-rw-r--r--library/HTMLPurifier/URIFilter/SafeIframe.php68
-rw-r--r--library/HTMLPurifier/URIParser.php9
-rw-r--r--library/HTMLPurifier/URIScheme.php88
-rw-r--r--library/HTMLPurifier/URIScheme/data.php58
-rw-r--r--library/HTMLPurifier/URIScheme/file.php44
-rw-r--r--library/HTMLPurifier/URIScheme/ftp.php29
-rw-r--r--library/HTMLPurifier/URIScheme/http.php26
-rw-r--r--library/HTMLPurifier/URIScheme/https.php12
-rw-r--r--library/HTMLPurifier/URIScheme/mailto.php23
-rw-r--r--library/HTMLPurifier/URIScheme/news.php29
-rw-r--r--library/HTMLPurifier/URIScheme/nntp.php24
-rw-r--r--library/HTMLPurifier/URISchemeRegistry.php41
-rw-r--r--library/HTMLPurifier/UnitConverter.php117
-rw-r--r--library/HTMLPurifier/VarParser.php152
-rw-r--r--library/HTMLPurifier/VarParser/Flexible.php88
-rw-r--r--library/HTMLPurifier/VarParser/Native.php18
-rw-r--r--library/HTMLPurifier/Zipper.php157
-rw-r--r--library/jquery.AreYouSure/.gitignore166
-rw-r--r--library/jquery.AreYouSure/Gruntfile.js26
-rw-r--r--library/jquery.AreYouSure/README.md297
-rw-r--r--library/jquery.AreYouSure/are-you-sure.jquery.json39
-rw-r--r--library/jquery.AreYouSure/ays-beforeunload-shim.js31
-rw-r--r--library/jquery.AreYouSure/bower.json30
-rw-r--r--library/jquery.AreYouSure/demo/are-you-sure-demo.html576
-rw-r--r--library/jquery.AreYouSure/jquery.are-you-sure.js192
-rw-r--r--library/jquery.AreYouSure/package.json45
-rw-r--r--library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html4
-rw-r--r--library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js28
-rw-r--r--mod/item.php8
-rw-r--r--mod/new_channel.php7
-rw-r--r--mod/profiles.php13
-rw-r--r--mod/settings.php28
-rwxr-xr-xmod/setup.php2
-rw-r--r--view/css/bootstrap-red.css4
-rw-r--r--view/css/mod_connect.css6
-rw-r--r--view/css/mod_group.css4
-rw-r--r--view/css/mod_settings.css10
-rw-r--r--view/css/mod_thing.css7
-rw-r--r--view/js/mod_admin.js3
-rw-r--r--view/js/mod_new_channel.js2
-rw-r--r--view/js/mod_profiles.js3
-rw-r--r--view/js/mod_settings.js5
-rw-r--r--view/php/theme_init.php1
-rw-r--r--view/sv/messages.po8016
-rw-r--r--view/sv/strings.php1922
-rw-r--r--view/theme/redbasic/css/style.css86
-rwxr-xr-xview/tpl/event_head.tpl5
-rwxr-xr-xview/tpl/field_acheckbox.tpl2
-rwxr-xr-xview/tpl/field_checkbox.tpl5
-rw-r--r--view/tpl/field_colorinput.tpl2
-rwxr-xr-xview/tpl/field_combobox.tpl2
-rwxr-xr-xview/tpl/field_custom.tpl2
-rwxr-xr-xview/tpl/field_input.tpl2
-rwxr-xr-xview/tpl/field_intcheckbox.tpl5
-rwxr-xr-xview/tpl/field_password.tpl2
-rwxr-xr-xview/tpl/field_radio.tpl2
-rwxr-xr-xview/tpl/field_richtext.tpl2
-rwxr-xr-xview/tpl/field_select.tpl2
-rw-r--r--view/tpl/field_select_disabled.tpl2
-rw-r--r--view/tpl/field_select_grouped.tpl12
-rwxr-xr-xview/tpl/field_select_raw.tpl2
-rwxr-xr-xview/tpl/field_textarea.tpl2
-rwxr-xr-xview/tpl/field_themeselect.tpl2
-rwxr-xr-xview/tpl/field_yesno.tpl2
-rwxr-xr-xview/tpl/install_settings.tpl2
-rwxr-xr-xview/tpl/new_channel.tpl5
-rw-r--r--view/tpl/profile_hide_friends.tpl5
-rw-r--r--view/tpl/select_timezone.tpl11
-rwxr-xr-xview/tpl/settings.tpl9
-rwxr-xr-xview/tpl/settings_features.tpl2
318 files changed, 20068 insertions, 11043 deletions
diff --git a/assets/home.html b/assets/home.html
index cad2045d0..16baab838 100644
--- a/assets/home.html
+++ b/assets/home.html
@@ -139,7 +139,8 @@ $(document).ready(function() {
var known = {
en: true, // ENGLISH
fr: true, // FRENCH
- nl: true // NETHERLANDS
+ nl: true, // NETHERLANDS
+ sv: true // SWEDISH
// ADD YOUR LANGUAGE HERE.
};
// Figure out the language, default to English because that's
@@ -196,6 +197,55 @@ $(document).ready(function() {
"Code Source Ouvert",
"Gratuit",
null);
+ else if (lang == "sv") // SWEDISH TRANSLATIONS
+ terms = new Array("Sekretess skalad för Internet",
+ "Socialt nätverkande",
+ "Single Sign-On",
+ "Fotoalbum",
+ "Decentraliserat",
+ "Molnlagring",
+ "Ditt eget innehåll",
+ "Blogg",
+ "End-to-end-kryptering",
+ "Chattrum",
+ "Delbara tilläggsprogram",
+ "Kontrollera behörighet mellan webbplatser",
+ "Ångra privata meddelanden",
+ "Skapa webbsidor",
+ "Innehållshantering",
+ "Tidsbegränsade meddelanden",
+ "Spel och verktyg",
+ "Inte styrt av företag",
+ "Forum",
+ "Gilla + Ogilla",
+ "Dela allt som är digitalt",
+ "Kommunikation",
+ "Identitsmedvetet innehåll",
+ "Pseudonymer",
+ "Multipla identiteter",
+ "Reklamfritt",
+ "Rich Text-inlägg/-kommentarer",
+ "Händelsekalender",
+ "Bokmärken",
+ "Gemensam taggning",
+ "Speglad katalog",
+ "Nomadisk identitet",
+ "Avknoppade kanaler",
+ "Anpassad kryptering",
+ "Multipla profiler",
+ "Sekretessgrupper",
+ "Fildelning",
+ "MIT-licens",
+ "Självständighet",
+ "Samhörighetsfiltrering",
+ "Vänförslag",
+ "Fjärrinloggning",
+ "Teman",
+ "Tillägg",
+ "Externt API",
+ "Tredjepartsappar",
+ "Öppen källkod",
+ null);
// Find all <div>s with a class of "wrapper" and lang attribute equal
// to `lang` and make them visibile.
@@ -315,6 +365,33 @@ De RedMatrix is ideaal voor groepen mensen van welke omvang dan ook, van kleine
</div>
<div style="margin-top: 15px; margin-bottom: 15px;"><a href="pubsites">Andere openbare hubs</a> | <a href="https://redmatrix.me">Projectwebsite</a> | <a href="https://github.com/friendica/red">Broncode</a> | <a href="https://zothub.com/channel/one">Ontwikkelaars</a></div>
</div>
+
+<!-- SWEDISH FRONTPAGE TRANSLATION STARTS HERE -->
+
+<div lang="sv" class="wrapper" style="display: none;">
+<div class="tr" style="font-size: 1.4em; color: #666; margin-left: 75px; margin-right: 75px;">
+Ett av de vanliga problemen med oberoende publicering p&aring; n&auml;tet har alltid varit det faktum att oberoende f&ouml;rfattare ofta &auml;r isolerade fr&aring;n varandra p&aring; sin egen webbplats och l&auml;gger det mesta av energin p&aring; att locka och attrahera bes&ouml;kare. Uppkomsten av vinstdrivande tj&auml;nster och s&aring; kallade sociala n&auml;tverk erbj&ouml;d en l&ouml;sning till m&aring;nga av dessa problem. Centraliseringen som p&aring;g&aring;tt har dock lett till att ditt inneh&aring;ll inte l&auml;ngre &auml;r under din direkta kontroll. Det &auml;r delat fullt ut med vinstdrivande annons&ouml;rer och myndigheter, men ironiskt nog uppmanas du ofta att betala pengar f&ouml;r att s&auml;kerst&auml;lla att dina v&auml;nner kan se ditt inneh&aring;ll. F&ouml;rest&auml;ll dig en situation d&auml;r du har f&ouml;rdelarna av den skalbarhet, kontakt och spridning som centraliseringen typiskt erbjuder, samtidigt som du inte ger avkall p&aring; kontroll &ouml;ver din egen n&auml;rvaro p&aring; Internet.
+</div>
+<br />
+<div class="tr" style="font-size: 1.4em; color: #666; margin-left: 75px; margin-right: 75px;">
+RedMatrix &auml;r ett n&auml;tverk sammansatt av ett stort antal mindre, oberoende och sj&auml;lvst&auml;ndiga webbplatser, sammankopplade till en samverkande publicerings- och kommunikationsplattform. Mjukvaran best&aring;r av en webbapplikation sl&auml;ppt som &ouml;ppen k&auml;llkod, som tillhandah&aring;ller ett <strong>decentraliserat</strong> fleranv&auml;ndarsystem f&ouml;r kommunikation, publicering och delning, och n&auml;r den k&ouml;rs utg&ouml;r en nod i n&auml;tverket. Varje nod erbjuder s&aring;v&auml;l kommunikationsverktyg (privata meddelanden, chatt, blogg, forum och traditionellt socialt n&auml;tverkande) som filhantering (foton, kalenderh&auml;ndelser, filer, webbsidor, delbara till&auml;ggsprogram) f&ouml;r alla medlemmar; alltihop i en sammanknuten plattform. Dessa noder tar automatiskt kontakt med varandra och resten av n&auml;tverket. Sekretess och inneh&aring;llsstyrning &auml;r alltid under din direkta personliga kontroll, och beh&ouml;righet till inl&auml;gg eller filer kan ges eller nekas vem som helst i n&auml;tverket.
+</div>
+<br />
+<div class="tr" style="font-size: 1.4em; color: #666; margin-left: 75px; margin-right: 75px;">
+Det som g&ouml;r RedMatrix unikt &auml;r vad vi kallar "magisk fj&auml;rrinloggning" - som &auml;r baserad p&aring; v&aring;rt banbrytande arbete med en decentraliserad identitetshantering. Ingen annan plattform vi k&auml;nner till erbjuder i dagsl&auml;get n&aring;got liknande. Inom n&auml;tverket &auml;r gr&auml;nserna mellan de olika noderna utsuddade eller till synes icke-existerande. En identitet i n&auml;tverket kan vara &ouml;verg&aring;ende och potentiellt nomadisk. "Vem du &auml;r" har inget att g&ouml;ra med "vilken dator du ansluter till inom n&auml;tverket" och webbsidornas inneh&aring;ll kan skapas s&aring; att det anpassar sig utifr&aring;n vem som tittar p&aring; det. Du har m&ouml;jlighet att "klona" din identitet till andra noder, vilket l&aring;ter dig forts&auml;tta att kommunicera med dina v&auml;nner utan avbrott om din prim&auml;ra nod skulle bli otillg&auml;nglig (tillf&auml;lligt eller permanent).
+</div>
+<br />
+<div class="tr" style="font-size: 1.4em; color: #666; margin-left: 75px; margin-right: 75px;">
+RedMatrix passar f&ouml;r grupper av vilken storlek som helst - alltifr&aring;n privatpersoner och familjer till n&auml;tforum, f&ouml;retagswebbplatser och organisationer. Det kan anv&auml;ndas av alla som har inneh&aring;ll de &ouml;nskar dela med sig av och samtidigt ha full kontroll &ouml;ver vem de delar det med.
+</div>
+<br />
+<div style="margin-bottom: 15px; color: #808080; font-size: 1.8em;"><strong>RedMatrix - "N&auml;tverket"</strong></div>
+<div style="font-size: 1.4em;">
+<a href="register" style="color: white; padding:10px; background-color: #c60032; border-radius: 10px;">Registrera dig nu!</a>
+<a href="donate" style="color: white; padding:10px; background-color: #c60032; border-radius: 10px;">Ge ett bidrag / Sponsra</a>
+</div>
+<div style="margin-top: 15px; margin-bottom: 15px;"><a href="pubsites">Offentliga noder</a> | <a href="https://redmatrix.me">Projektets hemsida</a> | <a href="https://github.com/friendica/red">Kod</a> | <a href="https://zothub.com/channel/one">Utvecklare</a></div>
+</div>
<!-- INSERT NEW TRANSLATIONS HERE -->
<!-- DO NOT REMOVE THE 2 LINES BELOW -->
diff --git a/include/datetime.php b/include/datetime.php
index 59dad2045..346d03bd4 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -14,25 +14,17 @@ function timezone_cmp($a, $b) {
return ( t($a) < t($b)) ? -1 : 1;
}
-// emit a timezone selector grouped (primarily) by continent
-
-function select_timezone($current = 'America/Los_Angeles') {
-
+// Return timezones grouped (primarily) by continent
+function get_timezones( ){
$timezone_identifiers = DateTimeZone::listIdentifiers();
-
- $o ='<select id="timezone_select" name="timezone">';
usort($timezone_identifiers, 'timezone_cmp');
$continent = '';
+ $continents = array();
foreach($timezone_identifiers as $value) {
$ex = explode("/", $value);
if(count($ex) > 1) {
- if($ex[0] != $continent) {
- if($continent != '')
- $o .= '</optgroup>';
- $continent = $ex[0];
- $o .= '<optgroup label="' . t($continent) . '">';
- }
+ $continent = t($ex[0]);
if(count($ex) > 2)
$city = substr($value,strpos($value,'/')+1);
else
@@ -40,35 +32,14 @@ function select_timezone($current = 'America/Los_Angeles') {
}
else {
$city = $ex[0];
- if($continent != t('Miscellaneous')) {
- $o .= '</optgroup>';
- $continent = t('Miscellaneous');
- $o .= '<optgroup label="' . t($continent) . '">';
- }
+ $continent = t('Miscellaneous');
}
$city = str_replace('_', ' ', t($city));
- $selected = (($value == $current) ? " selected=\"selected\" " : "");
- $o .= "<option value=\"$value\" $selected >$city</option>";
- }
- $o .= '</optgroup></select>';
- return $o;
-}
-
-// return a select using 'field_select_raw' template, with timezones
-// groupped (primarily) by continent
-// arguments follow convetion as other field_* template array:
-// 'name', 'label', $value, 'help'
-function field_timezone($name='timezone', $label='', $current = 'America/Los_Angeles', $help){
- $options = select_timezone($current);
- $options = str_replace('<select id="timezone_select" name="timezone">','', $options);
- $options = str_replace('</select>','', $options);
-
- $tpl = get_markup_template('field_select_raw.tpl');
- return replace_macros($tpl, array(
- '$field' => array($name, $label, $current, $help, $options),
- ));
-
+ if(!x($continents,$ex[0])) $continents[$ex[0]] = array();
+ $continents[$continent][$value] = $city;
+ }
+ return $continents;
}
// General purpose date parse/convert function.
diff --git a/include/permissions.php b/include/permissions.php
index 9e60223fb..ccbde1a7c 100644
--- a/include/permissions.php
+++ b/include/permissions.php
@@ -800,38 +800,18 @@ function get_role_perms($role) {
}
/**
- * @brief Creates a HTML select field with all available roles.
+ * @brief Returns a list or roles, grouped by type
*
* @param string $current The current role
- * @return string Returns the complete HTML code for this privacy-role-select field.
+ * @return string Returns an array of roles, grouped by type
*/
-function role_selector($current) {
-
- if(! $current)
- $current = 'custom';
-
+function get_roles() {
$roles = array(
- 'social' => array( t('Social Networking'),
- array('social' => t('Mostly Public'), 'social_restricted' => t('Restricted'), 'social_private' => t('Private'))),
- 'forum' => array( t('Community Forum'),
- array('forum' => t('Mostly Public'), 'forum_restricted' => t('Restricted'), 'forum_private' => t('Private'))),
- 'feed' => array( t('Feed Republish'),
- array('feed' => t('Mostly Public'), 'feed_restricted' => t('Restricted'))),
- 'special' => array( t('Special Purpose'),
- array('soapbox' => t('Celebrity/Soapbox'), 'repository' => t('Group Repository'))),
- 'other' => array( t('Other'),
- array('custom' => t('Custom/Expert Mode'))));
-
- $o = '<select name="permissions_role" id="privacy-role-select">';
- foreach($roles as $k => $v) {
- $o .= '<optgroup label="'. htmlspecialchars($v[0]) . '">';
- foreach($v[1] as $kk => $vv) {
- $selected = (($kk === $current) ? ' selected="selected"' : '');
- $o .= '<option value="' . $kk . '"' . $selected . '>' . htmlspecialchars($vv) . '</option>';
- }
- $o .= '</optgroup>';
- }
- $o .= '</select>';
+ t('Social Networking') => array('social' => t('Mostly Public'), 'social_restricted' => t('Restricted'), 'social_private' => t('Private')),
+ t('Community Forum') => array('forum' => t('Mostly Public'), 'forum_restricted' => t('Restricted'), 'forum_private' => t('Private')),
+ t('Feed Republish') => array('feed' => t('Mostly Public'), 'feed_restricted' => t('Restricted')),
+ t('Special Purpose') => array('soapbox' => t('Celebrity/Soapbox'), 'repository' => t('Group Repository')),
+ t('Other') => array('custom' => t('Custom/Expert Mode')));
- return $o;
+ return $roles;
}
diff --git a/library/HTMLPurifier.autoload.php b/library/HTMLPurifier.autoload.php
index 8d4017640..c3ea67e81 100644
--- a/library/HTMLPurifier.autoload.php
+++ b/library/HTMLPurifier.autoload.php
@@ -3,6 +3,7 @@
/**
* @file
* Convenience file that registers autoload handler for HTML Purifier.
+ * It also does some sanity checks.
*/
if (function_exists('spl_autoload_register') && function_exists('spl_autoload_unregister')) {
@@ -13,9 +14,14 @@ if (function_exists('spl_autoload_register') && function_exists('spl_autoload_un
spl_autoload_register('__autoload');
}
} elseif (!function_exists('__autoload')) {
- function __autoload($class) {
+ function __autoload($class)
+ {
return HTMLPurifier_Bootstrap::autoload($class);
}
}
+if (ini_get('zend.ze1_compatibility_mode')) {
+ trigger_error("HTML Purifier is not compatible with zend.ze1_compatibility_mode; please turn it off", E_USER_ERROR);
+}
+
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier.composer.php b/library/HTMLPurifier.composer.php
new file mode 100644
index 000000000..6706f4e39
--- /dev/null
+++ b/library/HTMLPurifier.composer.php
@@ -0,0 +1,4 @@
+<?php
+if (!defined('HTMLPURIFIER_PREFIX')) {
+ define('HTMLPURIFIER_PREFIX', __DIR__);
+}
diff --git a/library/HTMLPurifier.func.php b/library/HTMLPurifier.func.php
index 56a55b2fe..64b140bec 100644
--- a/library/HTMLPurifier.func.php
+++ b/library/HTMLPurifier.func.php
@@ -8,11 +8,13 @@
/**
* Purify HTML.
- * @param $html String HTML to purify
- * @param $config Configuration to use, can be any value accepted by
+ * @param string $html String HTML to purify
+ * @param mixed $config Configuration to use, can be any value accepted by
* HTMLPurifier_Config::create()
+ * @return string
*/
-function HTMLPurifier($html, $config = null) {
+function HTMLPurifier($html, $config = null)
+{
static $purifier = false;
if (!$purifier) {
$purifier = new HTMLPurifier();
diff --git a/library/HTMLPurifier.includes.php b/library/HTMLPurifier.includes.php
index 2ed0f0c17..9b7b88a87 100644
--- a/library/HTMLPurifier.includes.php
+++ b/library/HTMLPurifier.includes.php
@@ -7,7 +7,7 @@
* primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
* FILE, changes will be overwritten the next time the script is run.
*
- * @version 4.1.1
+ * @version 4.6.0
*
* @warning
* You must *not* include any other HTML Purifier files before this file,
@@ -19,6 +19,7 @@
*/
require 'HTMLPurifier.php';
+require 'HTMLPurifier/Arborize.php';
require 'HTMLPurifier/AttrCollections.php';
require 'HTMLPurifier/AttrDef.php';
require 'HTMLPurifier/AttrTransform.php';
@@ -54,9 +55,11 @@ require 'HTMLPurifier/Language.php';
require 'HTMLPurifier/LanguageFactory.php';
require 'HTMLPurifier/Length.php';
require 'HTMLPurifier/Lexer.php';
+require 'HTMLPurifier/Node.php';
require 'HTMLPurifier/PercentEncoder.php';
require 'HTMLPurifier/PropertyList.php';
require 'HTMLPurifier/PropertyListIterator.php';
+require 'HTMLPurifier/Queue.php';
require 'HTMLPurifier/Strategy.php';
require 'HTMLPurifier/StringHash.php';
require 'HTMLPurifier/StringHashParser.php';
@@ -72,7 +75,9 @@ require 'HTMLPurifier/URISchemeRegistry.php';
require 'HTMLPurifier/UnitConverter.php';
require 'HTMLPurifier/VarParser.php';
require 'HTMLPurifier/VarParserException.php';
+require 'HTMLPurifier/Zipper.php';
require 'HTMLPurifier/AttrDef/CSS.php';
+require 'HTMLPurifier/AttrDef/Clone.php';
require 'HTMLPurifier/AttrDef/Enum.php';
require 'HTMLPurifier/AttrDef/Integer.php';
require 'HTMLPurifier/AttrDef/Lang.php';
@@ -90,6 +95,7 @@ require 'HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php';
require 'HTMLPurifier/AttrDef/CSS/Filter.php';
require 'HTMLPurifier/AttrDef/CSS/Font.php';
require 'HTMLPurifier/AttrDef/CSS/FontFamily.php';
+require 'HTMLPurifier/AttrDef/CSS/Ident.php';
require 'HTMLPurifier/AttrDef/CSS/ImportantDecorator.php';
require 'HTMLPurifier/AttrDef/CSS/Length.php';
require 'HTMLPurifier/AttrDef/CSS/ListStyle.php';
@@ -125,14 +131,17 @@ require 'HTMLPurifier/AttrTransform/Lang.php';
require 'HTMLPurifier/AttrTransform/Length.php';
require 'HTMLPurifier/AttrTransform/Name.php';
require 'HTMLPurifier/AttrTransform/NameSync.php';
+require 'HTMLPurifier/AttrTransform/Nofollow.php';
require 'HTMLPurifier/AttrTransform/SafeEmbed.php';
require 'HTMLPurifier/AttrTransform/SafeObject.php';
require 'HTMLPurifier/AttrTransform/SafeParam.php';
require 'HTMLPurifier/AttrTransform/ScriptRequired.php';
+require 'HTMLPurifier/AttrTransform/TargetBlank.php';
require 'HTMLPurifier/AttrTransform/Textarea.php';
require 'HTMLPurifier/ChildDef/Chameleon.php';
require 'HTMLPurifier/ChildDef/Custom.php';
require 'HTMLPurifier/ChildDef/Empty.php';
+require 'HTMLPurifier/ChildDef/List.php';
require 'HTMLPurifier/ChildDef/Required.php';
require 'HTMLPurifier/ChildDef/Optional.php';
require 'HTMLPurifier/ChildDef/StrictBlockquote.php';
@@ -147,10 +156,12 @@ require 'HTMLPurifier/HTMLModule/CommonAttributes.php';
require 'HTMLPurifier/HTMLModule/Edit.php';
require 'HTMLPurifier/HTMLModule/Forms.php';
require 'HTMLPurifier/HTMLModule/Hypertext.php';
+require 'HTMLPurifier/HTMLModule/Iframe.php';
require 'HTMLPurifier/HTMLModule/Image.php';
require 'HTMLPurifier/HTMLModule/Legacy.php';
require 'HTMLPurifier/HTMLModule/List.php';
require 'HTMLPurifier/HTMLModule/Name.php';
+require 'HTMLPurifier/HTMLModule/Nofollow.php';
require 'HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
require 'HTMLPurifier/HTMLModule/Object.php';
require 'HTMLPurifier/HTMLModule/Presentation.php';
@@ -158,10 +169,12 @@ require 'HTMLPurifier/HTMLModule/Proprietary.php';
require 'HTMLPurifier/HTMLModule/Ruby.php';
require 'HTMLPurifier/HTMLModule/SafeEmbed.php';
require 'HTMLPurifier/HTMLModule/SafeObject.php';
+require 'HTMLPurifier/HTMLModule/SafeScripting.php';
require 'HTMLPurifier/HTMLModule/Scripting.php';
require 'HTMLPurifier/HTMLModule/StyleAttribute.php';
require 'HTMLPurifier/HTMLModule/Tables.php';
require 'HTMLPurifier/HTMLModule/Target.php';
+require 'HTMLPurifier/HTMLModule/TargetBlank.php';
require 'HTMLPurifier/HTMLModule/Text.php';
require 'HTMLPurifier/HTMLModule/Tidy.php';
require 'HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
@@ -180,6 +193,9 @@ require 'HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php';
require 'HTMLPurifier/Injector/SafeObject.php';
require 'HTMLPurifier/Lexer/DOMLex.php';
require 'HTMLPurifier/Lexer/DirectLex.php';
+require 'HTMLPurifier/Node/Comment.php';
+require 'HTMLPurifier/Node/Element.php';
+require 'HTMLPurifier/Node/Text.php';
require 'HTMLPurifier/Strategy/Composite.php';
require 'HTMLPurifier/Strategy/Core.php';
require 'HTMLPurifier/Strategy/FixNesting.php';
@@ -196,10 +212,13 @@ require 'HTMLPurifier/Token/Start.php';
require 'HTMLPurifier/Token/Text.php';
require 'HTMLPurifier/URIFilter/DisableExternal.php';
require 'HTMLPurifier/URIFilter/DisableExternalResources.php';
+require 'HTMLPurifier/URIFilter/DisableResources.php';
require 'HTMLPurifier/URIFilter/HostBlacklist.php';
require 'HTMLPurifier/URIFilter/MakeAbsolute.php';
require 'HTMLPurifier/URIFilter/Munge.php';
+require 'HTMLPurifier/URIFilter/SafeIframe.php';
require 'HTMLPurifier/URIScheme/data.php';
+require 'HTMLPurifier/URIScheme/file.php';
require 'HTMLPurifier/URIScheme/ftp.php';
require 'HTMLPurifier/URIScheme/http.php';
require 'HTMLPurifier/URIScheme/https.php';
diff --git a/library/HTMLPurifier.kses.php b/library/HTMLPurifier.kses.php
index 3143feb17..752290077 100644
--- a/library/HTMLPurifier.kses.php
+++ b/library/HTMLPurifier.kses.php
@@ -7,7 +7,8 @@
require_once dirname(__FILE__) . '/HTMLPurifier.auto.php';
-function kses($string, $allowed_html, $allowed_protocols = null) {
+function kses($string, $allowed_html, $allowed_protocols = null)
+{
$config = HTMLPurifier_Config::createDefault();
$allowed_elements = array();
$allowed_attributes = array();
@@ -19,7 +20,6 @@ function kses($string, $allowed_html, $allowed_protocols = null) {
}
$config->set('HTML.AllowedElements', $allowed_elements);
$config->set('HTML.AllowedAttributes', $allowed_attributes);
- $allowed_schemes = array();
if ($allowed_protocols !== null) {
$config->set('URI.AllowedSchemes', $allowed_protocols);
}
diff --git a/library/HTMLPurifier.php b/library/HTMLPurifier.php
index ba2c7b306..6f654fde5 100644
--- a/library/HTMLPurifier.php
+++ b/library/HTMLPurifier.php
@@ -19,7 +19,7 @@
*/
/*
- HTML Purifier 4.1.1 - Standards Compliant HTML Filtering
+ HTML Purifier 4.6.0 - Standards Compliant HTML Filtering
Copyright (C) 2006-2008 Edward Z. Yang
This library is free software; you can redistribute it and/or
@@ -54,66 +54,97 @@
class HTMLPurifier
{
- /** Version of HTML Purifier */
- public $version = '4.1.1';
+ /**
+ * Version of HTML Purifier.
+ * @type string
+ */
+ public $version = '4.6.0';
- /** Constant with version of HTML Purifier */
- const VERSION = '4.1.1';
+ /**
+ * Constant with version of HTML Purifier.
+ */
+ const VERSION = '4.6.0';
- /** Global configuration object */
+ /**
+ * Global configuration object.
+ * @type HTMLPurifier_Config
+ */
public $config;
- /** Array of extra HTMLPurifier_Filter objects to run on HTML, for backwards compatibility */
+ /**
+ * Array of extra filter objects to run on HTML,
+ * for backwards compatibility.
+ * @type HTMLPurifier_Filter[]
+ */
private $filters = array();
- /** Single instance of HTML Purifier */
+ /**
+ * Single instance of HTML Purifier.
+ * @type HTMLPurifier
+ */
private static $instance;
- protected $strategy, $generator;
+ /**
+ * @type HTMLPurifier_Strategy_Core
+ */
+ protected $strategy;
+
+ /**
+ * @type HTMLPurifier_Generator
+ */
+ protected $generator;
/**
- * Resultant HTMLPurifier_Context of last run purification. Is an array
- * of contexts if the last called method was purifyArray().
+ * Resultant context of last run purification.
+ * Is an array of contexts if the last called method was purifyArray().
+ * @type HTMLPurifier_Context
*/
public $context;
/**
* Initializes the purifier.
- * @param $config Optional HTMLPurifier_Config object for all instances of
- * the purifier, if omitted, a default configuration is
- * supplied (which can be overridden on a per-use basis).
+ *
+ * @param HTMLPurifier_Config $config Optional HTMLPurifier_Config object
+ * for all instances of the purifier, if omitted, a default
+ * configuration is supplied (which can be overridden on a
+ * per-use basis).
* The parameter can also be any type that
* HTMLPurifier_Config::create() supports.
*/
- public function __construct($config = null) {
-
+ public function __construct($config = null)
+ {
$this->config = HTMLPurifier_Config::create($config);
-
- $this->strategy = new HTMLPurifier_Strategy_Core();
-
+ $this->strategy = new HTMLPurifier_Strategy_Core();
}
/**
* Adds a filter to process the output. First come first serve
- * @param $filter HTMLPurifier_Filter object
+ *
+ * @param HTMLPurifier_Filter $filter HTMLPurifier_Filter object
*/
- public function addFilter($filter) {
- trigger_error('HTMLPurifier->addFilter() is deprecated, use configuration directives in the Filter namespace or Filter.Custom', E_USER_WARNING);
+ public function addFilter($filter)
+ {
+ trigger_error(
+ 'HTMLPurifier->addFilter() is deprecated, use configuration directives' .
+ ' in the Filter namespace or Filter.Custom',
+ E_USER_WARNING
+ );
$this->filters[] = $filter;
}
/**
* Filters an HTML snippet/document to be XSS-free and standards-compliant.
*
- * @param $html String of HTML to purify
- * @param $config HTMLPurifier_Config object for this operation, if omitted,
- * defaults to the config object specified during this
+ * @param string $html String of HTML to purify
+ * @param HTMLPurifier_Config $config Config object for this operation,
+ * if omitted, defaults to the config object specified during this
* object's construction. The parameter can also be any type
* that HTMLPurifier_Config::create() supports.
- * @return Purified HTML
+ *
+ * @return string Purified HTML
*/
- public function purify($html, $config = null) {
-
+ public function purify($html, $config = null)
+ {
// :TODO: make the config merge in, instead of replace
$config = $config ? HTMLPurifier_Config::create($config) : $this->config;
@@ -151,8 +182,12 @@ class HTMLPurifier
unset($filter_flags['Custom']);
$filters = array();
foreach ($filter_flags as $filter => $flag) {
- if (!$flag) continue;
- if (strpos($filter, '.') !== false) continue;
+ if (!$flag) {
+ continue;
+ }
+ if (strpos($filter, '.') !== false) {
+ continue;
+ }
$class = "HTMLPurifier_Filter_$filter";
$filters[] = new $class;
}
@@ -175,9 +210,12 @@ class HTMLPurifier
// list of un-purified tokens
$lexer->tokenizeHTML(
// un-purified HTML
- $html, $config, $context
+ $html,
+ $config,
+ $context
),
- $config, $context
+ $config,
+ $context
)
);
@@ -192,11 +230,15 @@ class HTMLPurifier
/**
* Filters an array of HTML snippets
- * @param $config Optional HTMLPurifier_Config object for this operation.
+ *
+ * @param string[] $array_of_html Array of html snippets
+ * @param HTMLPurifier_Config $config Optional config object for this operation.
* See HTMLPurifier::purify() for more details.
- * @return Array of purified HTML
+ *
+ * @return string[] Array of purified HTML
*/
- public function purifyArray($array_of_html, $config = null) {
+ public function purifyArray($array_of_html, $config = null)
+ {
$context_array = array();
foreach ($array_of_html as $key => $html) {
$array_of_html[$key] = $this->purify($html, $config);
@@ -208,11 +250,16 @@ class HTMLPurifier
/**
* Singleton for enforcing just one HTML Purifier in your system
- * @param $prototype Optional prototype HTMLPurifier instance to
- * overload singleton with, or HTMLPurifier_Config
- * instance to configure the generated version with.
+ *
+ * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype
+ * HTMLPurifier instance to overload singleton with,
+ * or HTMLPurifier_Config instance to configure the
+ * generated version with.
+ *
+ * @return HTMLPurifier
*/
- public static function instance($prototype = null) {
+ public static function instance($prototype = null)
+ {
if (!self::$instance || $prototype) {
if ($prototype instanceof HTMLPurifier) {
self::$instance = $prototype;
@@ -226,12 +273,20 @@ class HTMLPurifier
}
/**
+ * Singleton for enforcing just one HTML Purifier in your system
+ *
+ * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype
+ * HTMLPurifier instance to overload singleton with,
+ * or HTMLPurifier_Config instance to configure the
+ * generated version with.
+ *
+ * @return HTMLPurifier
* @note Backwards compatibility, see instance()
*/
- public static function getInstance($prototype = null) {
+ public static function getInstance($prototype = null)
+ {
return HTMLPurifier::instance($prototype);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier.safe-includes.php b/library/HTMLPurifier.safe-includes.php
index 6402de045..9dea6d1ed 100644
--- a/library/HTMLPurifier.safe-includes.php
+++ b/library/HTMLPurifier.safe-includes.php
@@ -13,6 +13,7 @@
$__dir = dirname(__FILE__);
require_once $__dir . '/HTMLPurifier.php';
+require_once $__dir . '/HTMLPurifier/Arborize.php';
require_once $__dir . '/HTMLPurifier/AttrCollections.php';
require_once $__dir . '/HTMLPurifier/AttrDef.php';
require_once $__dir . '/HTMLPurifier/AttrTransform.php';
@@ -48,9 +49,11 @@ require_once $__dir . '/HTMLPurifier/Language.php';
require_once $__dir . '/HTMLPurifier/LanguageFactory.php';
require_once $__dir . '/HTMLPurifier/Length.php';
require_once $__dir . '/HTMLPurifier/Lexer.php';
+require_once $__dir . '/HTMLPurifier/Node.php';
require_once $__dir . '/HTMLPurifier/PercentEncoder.php';
require_once $__dir . '/HTMLPurifier/PropertyList.php';
require_once $__dir . '/HTMLPurifier/PropertyListIterator.php';
+require_once $__dir . '/HTMLPurifier/Queue.php';
require_once $__dir . '/HTMLPurifier/Strategy.php';
require_once $__dir . '/HTMLPurifier/StringHash.php';
require_once $__dir . '/HTMLPurifier/StringHashParser.php';
@@ -66,7 +69,9 @@ require_once $__dir . '/HTMLPurifier/URISchemeRegistry.php';
require_once $__dir . '/HTMLPurifier/UnitConverter.php';
require_once $__dir . '/HTMLPurifier/VarParser.php';
require_once $__dir . '/HTMLPurifier/VarParserException.php';
+require_once $__dir . '/HTMLPurifier/Zipper.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/Clone.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Integer.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Lang.php';
@@ -84,6 +89,7 @@ require_once $__dir . '/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Filter.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Font.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/FontFamily.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Ident.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Length.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ListStyle.php';
@@ -119,14 +125,17 @@ require_once $__dir . '/HTMLPurifier/AttrTransform/Lang.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Length.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/NameSync.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Nofollow.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeEmbed.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/TargetBlank.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Textarea.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Empty.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/List.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Required.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Optional.php';
require_once $__dir . '/HTMLPurifier/ChildDef/StrictBlockquote.php';
@@ -141,10 +150,12 @@ require_once $__dir . '/HTMLPurifier/HTMLModule/CommonAttributes.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Edit.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Forms.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Hypertext.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Iframe.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Image.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Legacy.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/List.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Name.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Nofollow.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Object.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Presentation.php';
@@ -152,10 +163,12 @@ require_once $__dir . '/HTMLPurifier/HTMLModule/Proprietary.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Ruby.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeEmbed.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeObject.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/SafeScripting.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Scripting.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/StyleAttribute.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tables.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Target.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/TargetBlank.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Text.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
@@ -174,6 +187,9 @@ require_once $__dir . '/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php';
require_once $__dir . '/HTMLPurifier/Injector/SafeObject.php';
require_once $__dir . '/HTMLPurifier/Lexer/DOMLex.php';
require_once $__dir . '/HTMLPurifier/Lexer/DirectLex.php';
+require_once $__dir . '/HTMLPurifier/Node/Comment.php';
+require_once $__dir . '/HTMLPurifier/Node/Element.php';
+require_once $__dir . '/HTMLPurifier/Node/Text.php';
require_once $__dir . '/HTMLPurifier/Strategy/Composite.php';
require_once $__dir . '/HTMLPurifier/Strategy/Core.php';
require_once $__dir . '/HTMLPurifier/Strategy/FixNesting.php';
@@ -190,10 +206,13 @@ require_once $__dir . '/HTMLPurifier/Token/Start.php';
require_once $__dir . '/HTMLPurifier/Token/Text.php';
require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternal.php';
require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternalResources.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/DisableResources.php';
require_once $__dir . '/HTMLPurifier/URIFilter/HostBlacklist.php';
require_once $__dir . '/HTMLPurifier/URIFilter/MakeAbsolute.php';
require_once $__dir . '/HTMLPurifier/URIFilter/Munge.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/SafeIframe.php';
require_once $__dir . '/HTMLPurifier/URIScheme/data.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/file.php';
require_once $__dir . '/HTMLPurifier/URIScheme/ftp.php';
require_once $__dir . '/HTMLPurifier/URIScheme/http.php';
require_once $__dir . '/HTMLPurifier/URIScheme/https.php';
diff --git a/library/HTMLPurifier/Arborize.php b/library/HTMLPurifier/Arborize.php
new file mode 100644
index 000000000..9e6617be5
--- /dev/null
+++ b/library/HTMLPurifier/Arborize.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * Converts a stream of HTMLPurifier_Token into an HTMLPurifier_Node,
+ * and back again.
+ *
+ * @note This transformation is not an equivalence. We mutate the input
+ * token stream to make it so; see all [MUT] markers in code.
+ */
+class HTMLPurifier_Arborize
+{
+ public static function arborize($tokens, $config, $context) {
+ $definition = $config->getHTMLDefinition();
+ $parent = new HTMLPurifier_Token_Start($definition->info_parent);
+ $stack = array($parent->toNode());
+ foreach ($tokens as $token) {
+ $token->skip = null; // [MUT]
+ $token->carryover = null; // [MUT]
+ if ($token instanceof HTMLPurifier_Token_End) {
+ $token->start = null; // [MUT]
+ $r = array_pop($stack);
+ assert($r->name === $token->name);
+ assert(empty($token->attr));
+ $r->endCol = $token->col;
+ $r->endLine = $token->line;
+ $r->endArmor = $token->armor;
+ continue;
+ }
+ $node = $token->toNode();
+ $stack[count($stack)-1]->children[] = $node;
+ if ($token instanceof HTMLPurifier_Token_Start) {
+ $stack[] = $node;
+ }
+ }
+ assert(count($stack) == 1);
+ return $stack[0];
+ }
+
+ public static function flatten($node, $config, $context) {
+ $level = 0;
+ $nodes = array($level => new HTMLPurifier_Queue(array($node)));
+ $closingTokens = array();
+ $tokens = array();
+ do {
+ while (!$nodes[$level]->isEmpty()) {
+ $node = $nodes[$level]->shift(); // FIFO
+ list($start, $end) = $node->toTokenPair();
+ if ($level > 0) {
+ $tokens[] = $start;
+ }
+ if ($end !== NULL) {
+ $closingTokens[$level][] = $end;
+ }
+ if ($node instanceof HTMLPurifier_Node_Element) {
+ $level++;
+ $nodes[$level] = new HTMLPurifier_Queue();
+ foreach ($node->children as $childNode) {
+ $nodes[$level]->push($childNode);
+ }
+ }
+ }
+ $level--;
+ if ($level && isset($closingTokens[$level])) {
+ while ($token = array_pop($closingTokens[$level])) {
+ $tokens[] = $token;
+ }
+ }
+ } while ($level > 0);
+ return $tokens;
+ }
+}
diff --git a/library/HTMLPurifier/AttrCollections.php b/library/HTMLPurifier/AttrCollections.php
index 555b86d04..4f6c2e39a 100644
--- a/library/HTMLPurifier/AttrCollections.php
+++ b/library/HTMLPurifier/AttrCollections.php
@@ -8,7 +8,8 @@ class HTMLPurifier_AttrCollections
{
/**
- * Associative array of attribute collections, indexed by name
+ * Associative array of attribute collections, indexed by name.
+ * @type array
*/
public $info = array();
@@ -16,10 +17,11 @@ class HTMLPurifier_AttrCollections
* Performs all expansions on internal data for use by other inclusions
* It also collects all attribute collection extensions from
* modules
- * @param $attr_types HTMLPurifier_AttrTypes instance
- * @param $modules Hash array of HTMLPurifier_HTMLModule members
+ * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
+ * @param HTMLPurifier_HTMLModule[] $modules Hash array of HTMLPurifier_HTMLModule members
*/
- public function __construct($attr_types, $modules) {
+ public function __construct($attr_types, $modules)
+ {
// load extensions from the modules
foreach ($modules as $module) {
foreach ($module->attr_collections as $coll_i => $coll) {
@@ -30,7 +32,9 @@ class HTMLPurifier_AttrCollections
if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
// merge in includes
$this->info[$coll_i][$attr_i] = array_merge(
- $this->info[$coll_i][$attr_i], $attr);
+ $this->info[$coll_i][$attr_i],
+ $attr
+ );
continue;
}
$this->info[$coll_i][$attr_i] = $attr;
@@ -49,20 +53,29 @@ class HTMLPurifier_AttrCollections
/**
* Takes a reference to an attribute associative array and performs
* all inclusions specified by the zero index.
- * @param &$attr Reference to attribute array
+ * @param array &$attr Reference to attribute array
*/
- public function performInclusions(&$attr) {
- if (!isset($attr[0])) return;
+ public function performInclusions(&$attr)
+ {
+ if (!isset($attr[0])) {
+ return;
+ }
$merge = $attr[0];
$seen = array(); // recursion guard
// loop through all the inclusions
for ($i = 0; isset($merge[$i]); $i++) {
- if (isset($seen[$merge[$i]])) continue;
+ if (isset($seen[$merge[$i]])) {
+ continue;
+ }
$seen[$merge[$i]] = true;
// foreach attribute of the inclusion, copy it over
- if (!isset($this->info[$merge[$i]])) continue;
+ if (!isset($this->info[$merge[$i]])) {
+ continue;
+ }
foreach ($this->info[$merge[$i]] as $key => $value) {
- if (isset($attr[$key])) continue; // also catches more inclusions
+ if (isset($attr[$key])) {
+ continue;
+ } // also catches more inclusions
$attr[$key] = $value;
}
if (isset($this->info[$merge[$i]][0])) {
@@ -76,20 +89,24 @@ class HTMLPurifier_AttrCollections
/**
* Expands all string identifiers in an attribute array by replacing
* them with the appropriate values inside HTMLPurifier_AttrTypes
- * @param &$attr Reference to attribute array
- * @param $attr_types HTMLPurifier_AttrTypes instance
+ * @param array &$attr Reference to attribute array
+ * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
*/
- public function expandIdentifiers(&$attr, $attr_types) {
-
+ public function expandIdentifiers(&$attr, $attr_types)
+ {
// because foreach will process new elements we add, make sure we
// skip duplicates
$processed = array();
foreach ($attr as $def_i => $def) {
// skip inclusions
- if ($def_i === 0) continue;
+ if ($def_i === 0) {
+ continue;
+ }
- if (isset($processed[$def_i])) continue;
+ if (isset($processed[$def_i])) {
+ continue;
+ }
// determine whether or not attribute is required
if ($required = (strpos($def_i, '*') !== false)) {
@@ -120,9 +137,7 @@ class HTMLPurifier_AttrCollections
unset($attr[$def_i]);
}
}
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef.php b/library/HTMLPurifier/AttrDef.php
index b2e4f36c5..5ac06522b 100644
--- a/library/HTMLPurifier/AttrDef.php
+++ b/library/HTMLPurifier/AttrDef.php
@@ -14,23 +14,25 @@ abstract class HTMLPurifier_AttrDef
{
/**
- * Tells us whether or not an HTML attribute is minimized. Has no
- * meaning in other contexts.
+ * Tells us whether or not an HTML attribute is minimized.
+ * Has no meaning in other contexts.
+ * @type bool
*/
public $minimized = false;
/**
- * Tells us whether or not an HTML attribute is required. Has no
- * meaning in other contexts
+ * Tells us whether or not an HTML attribute is required.
+ * Has no meaning in other contexts
+ * @type bool
*/
public $required = false;
/**
* Validates and cleans passed string according to a definition.
*
- * @param $string String to be validated and cleaned.
- * @param $config Mandatory HTMLPurifier_Config object.
- * @param $context Mandatory HTMLPurifier_AttrContext object.
+ * @param string $string String to be validated and cleaned.
+ * @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object.
+ * @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object.
*/
abstract public function validate($string, $config, $context);
@@ -55,7 +57,8 @@ abstract class HTMLPurifier_AttrDef
* parsing XML, thus, this behavior may still be correct. We
* assume that newlines have been normalized.
*/
- public function parseCDATA($string) {
+ public function parseCDATA($string)
+ {
$string = trim($string);
$string = str_replace(array("\n", "\t", "\r"), ' ', $string);
return $string;
@@ -63,10 +66,11 @@ abstract class HTMLPurifier_AttrDef
/**
* Factory method for creating this class from a string.
- * @param $string String construction info
- * @return Created AttrDef object corresponding to $string
+ * @param string $string String construction info
+ * @return HTMLPurifier_AttrDef Created AttrDef object corresponding to $string
*/
- public function make($string) {
+ public function make($string)
+ {
// default implementation, return a flyweight of this object.
// If $string has an effect on the returned object (i.e. you
// need to overload this method), it is best
@@ -77,16 +81,20 @@ abstract class HTMLPurifier_AttrDef
/**
* Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work
* properly. THIS IS A HACK!
+ * @param string $string a CSS colour definition
+ * @return string
*/
- protected function mungeRgb($string) {
+ protected function mungeRgb($string)
+ {
return preg_replace('/rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)/', 'rgb(\1,\2,\3)', $string);
}
/**
- * Parses a possibly escaped CSS string and returns the "pure"
+ * Parses a possibly escaped CSS string and returns the "pure"
* version of it.
*/
- protected function expandCSSEscape($string) {
+ protected function expandCSSEscape($string)
+ {
// flexibly parse it
$ret = '';
for ($i = 0, $c = strlen($string); $i < $c; $i++) {
@@ -99,25 +107,32 @@ abstract class HTMLPurifier_AttrDef
if (ctype_xdigit($string[$i])) {
$code = $string[$i];
for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) {
- if (!ctype_xdigit($string[$i])) break;
+ if (!ctype_xdigit($string[$i])) {
+ break;
+ }
$code .= $string[$i];
}
// We have to be extremely careful when adding
// new characters, to make sure we're not breaking
// the encoding.
$char = HTMLPurifier_Encoder::unichr(hexdec($code));
- if (HTMLPurifier_Encoder::cleanUTF8($char) === '') continue;
+ if (HTMLPurifier_Encoder::cleanUTF8($char) === '') {
+ continue;
+ }
$ret .= $char;
- if ($i < $c && trim($string[$i]) !== '') $i--;
+ if ($i < $c && trim($string[$i]) !== '') {
+ $i--;
+ }
+ continue;
+ }
+ if ($string[$i] === "\n") {
continue;
}
- if ($string[$i] === "\n") continue;
}
$ret .= $string[$i];
}
return $ret;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS.php b/library/HTMLPurifier/AttrDef/CSS.php
index 953e70675..02c1641fb 100644
--- a/library/HTMLPurifier/AttrDef/CSS.php
+++ b/library/HTMLPurifier/AttrDef/CSS.php
@@ -14,8 +14,14 @@
class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
{
- public function validate($css, $config, $context) {
-
+ /**
+ * @param string $css
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($css, $config, $context)
+ {
$css = $this->parseCDATA($css);
$definition = $config->getCSSDefinition();
@@ -36,34 +42,47 @@ class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
$context->register('CurrentCSSProperty', $property);
foreach ($declarations as $declaration) {
- if (!$declaration) continue;
- if (!strpos($declaration, ':')) continue;
+ if (!$declaration) {
+ continue;
+ }
+ if (!strpos($declaration, ':')) {
+ continue;
+ }
list($property, $value) = explode(':', $declaration, 2);
$property = trim($property);
- $value = trim($value);
+ $value = trim($value);
$ok = false;
do {
if (isset($definition->info[$property])) {
$ok = true;
break;
}
- if (ctype_lower($property)) break;
+ if (ctype_lower($property)) {
+ break;
+ }
$property = strtolower($property);
if (isset($definition->info[$property])) {
$ok = true;
break;
}
- } while(0);
- if (!$ok) continue;
+ } while (0);
+ if (!$ok) {
+ continue;
+ }
// inefficient call, since the validator will do this again
if (strtolower(trim($value)) !== 'inherit') {
// inherit works for everything (but only on the base property)
$result = $definition->info[$property]->validate(
- $value, $config, $context );
+ $value,
+ $config,
+ $context
+ );
} else {
$result = 'inherit';
}
- if ($result === false) continue;
+ if ($result === false) {
+ continue;
+ }
$propvalues[$property] = $result;
}
diff --git a/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php
index 292c040d4..af2b83dff 100644
--- a/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php
+++ b/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php
@@ -3,19 +3,32 @@
class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number
{
- public function __construct() {
+ public function __construct()
+ {
parent::__construct(false); // opacity is non-negative, but we will clamp it
}
- public function validate($number, $config, $context) {
+ /**
+ * @param string $number
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
+ */
+ public function validate($number, $config, $context)
+ {
$result = parent::validate($number, $config, $context);
- if ($result === false) return $result;
- $float = (float) $result;
- if ($float < 0.0) $result = '0';
- if ($float > 1.0) $result = '1';
+ if ($result === false) {
+ return $result;
+ }
+ $float = (float)$result;
+ if ($float < 0.0) {
+ $result = '0';
+ }
+ if ($float > 1.0) {
+ $result = '1';
+ }
return $result;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/Background.php b/library/HTMLPurifier/AttrDef/CSS/Background.php
index 3a3d20cd6..7f1ea3b0f 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Background.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Background.php
@@ -9,11 +9,16 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
/**
* Local copy of component validators.
+ * @type HTMLPurifier_AttrDef[]
* @note See HTMLPurifier_AttrDef_Font::$info for a similar impl.
*/
protected $info;
- public function __construct($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function __construct($config)
+ {
$def = $config->getCSSDefinition();
$this->info['background-color'] = $def->info['background-color'];
$this->info['background-image'] = $def->info['background-image'];
@@ -22,40 +27,55 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
$this->info['background-position'] = $def->info['background-position'];
}
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
// regular pre-processing
$string = $this->parseCDATA($string);
- if ($string === '') return false;
+ if ($string === '') {
+ return false;
+ }
// munge rgb() decl if necessary
$string = $this->mungeRgb($string);
// assumes URI doesn't have spaces in it
- $bits = explode(' ', strtolower($string)); // bits to process
+ $bits = explode(' ', $string); // bits to process
$caught = array();
- $caught['color'] = false;
- $caught['image'] = false;
- $caught['repeat'] = false;
+ $caught['color'] = false;
+ $caught['image'] = false;
+ $caught['repeat'] = false;
$caught['attachment'] = false;
$caught['position'] = false;
$i = 0; // number of catches
- $none = false;
foreach ($bits as $bit) {
- if ($bit === '') continue;
+ if ($bit === '') {
+ continue;
+ }
foreach ($caught as $key => $status) {
if ($key != 'position') {
- if ($status !== false) continue;
+ if ($status !== false) {
+ continue;
+ }
$r = $this->info['background-' . $key]->validate($bit, $config, $context);
} else {
$r = $bit;
}
- if ($r === false) continue;
+ if ($r === false) {
+ continue;
+ }
if ($key == 'position') {
- if ($caught[$key] === false) $caught[$key] = '';
+ if ($caught[$key] === false) {
+ $caught[$key] = '';
+ }
$caught[$key] .= $r . ' ';
} else {
$caught[$key] = $r;
@@ -65,7 +85,9 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
}
}
- if (!$i) return false;
+ if (!$i) {
+ return false;
+ }
if ($caught['position'] !== false) {
$caught['position'] = $this->info['background-position']->
validate($caught['position'], $config, $context);
@@ -73,15 +95,17 @@ class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
$ret = array();
foreach ($caught as $value) {
- if ($value === false) continue;
+ if ($value === false) {
+ continue;
+ }
$ret[] = $value;
}
- if (empty($ret)) return false;
+ if (empty($ret)) {
+ return false;
+ }
return implode(' ', $ret);
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php
index fae82eaec..4580ef5a9 100644
--- a/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php
+++ b/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php
@@ -44,15 +44,30 @@
class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
{
+ /**
+ * @type HTMLPurifier_AttrDef_CSS_Length
+ */
protected $length;
+
+ /**
+ * @type HTMLPurifier_AttrDef_CSS_Percentage
+ */
protected $percentage;
- public function __construct() {
- $this->length = new HTMLPurifier_AttrDef_CSS_Length();
+ public function __construct()
+ {
+ $this->length = new HTMLPurifier_AttrDef_CSS_Length();
$this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage();
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = $this->parseCDATA($string);
$bits = explode(' ', $string);
@@ -74,7 +89,9 @@ class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
);
foreach ($bits as $bit) {
- if ($bit === '') continue;
+ if ($bit === '') {
+ continue;
+ }
// test for keyword
$lbit = ctype_lower($bit) ? $bit : strtolower($bit);
@@ -104,30 +121,37 @@ class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
$measures[] = $r;
$i++;
}
-
}
- if (!$i) return false; // no valid values were caught
+ if (!$i) {
+ return false;
+ } // no valid values were caught
$ret = array();
// first keyword
- if ($keywords['h']) $ret[] = $keywords['h'];
- elseif ($keywords['ch']) {
+ if ($keywords['h']) {
+ $ret[] = $keywords['h'];
+ } elseif ($keywords['ch']) {
$ret[] = $keywords['ch'];
$keywords['cv'] = false; // prevent re-use: center = center center
+ } elseif (count($measures)) {
+ $ret[] = array_shift($measures);
}
- elseif (count($measures)) $ret[] = array_shift($measures);
- if ($keywords['v']) $ret[] = $keywords['v'];
- elseif ($keywords['cv']) $ret[] = $keywords['cv'];
- elseif (count($measures)) $ret[] = array_shift($measures);
+ if ($keywords['v']) {
+ $ret[] = $keywords['v'];
+ } elseif ($keywords['cv']) {
+ $ret[] = $keywords['cv'];
+ } elseif (count($measures)) {
+ $ret[] = array_shift($measures);
+ }
- if (empty($ret)) return false;
+ if (empty($ret)) {
+ return false;
+ }
return implode(' ', $ret);
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/Border.php b/library/HTMLPurifier/AttrDef/CSS/Border.php
index 42a1d1b4a..16243ba1e 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Border.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Border.php
@@ -8,17 +8,29 @@ class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
/**
* Local copy of properties this property is shorthand for.
+ * @type HTMLPurifier_AttrDef[]
*/
protected $info = array();
- public function __construct($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function __construct($config)
+ {
$def = $config->getCSSDefinition();
$this->info['border-width'] = $def->info['border-width'];
$this->info['border-style'] = $def->info['border-style'];
$this->info['border-top-color'] = $def->info['border-top-color'];
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = $this->parseCDATA($string);
$string = $this->mungeRgb($string);
$bits = explode(' ', $string);
@@ -26,7 +38,9 @@ class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
$ret = ''; // return value
foreach ($bits as $bit) {
foreach ($this->info as $propname => $validator) {
- if (isset($done[$propname])) continue;
+ if (isset($done[$propname])) {
+ continue;
+ }
$r = $validator->validate($bit, $config, $context);
if ($r !== false) {
$ret .= $r . ' ';
@@ -37,7 +51,6 @@ class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
}
return rtrim($ret);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/Color.php b/library/HTMLPurifier/AttrDef/CSS/Color.php
index 07f95a671..16d2a6b98 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Color.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Color.php
@@ -6,29 +6,47 @@
class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
{
- public function validate($color, $config, $context) {
-
+ /**
+ * @param string $color
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($color, $config, $context)
+ {
static $colors = null;
- if ($colors === null) $colors = $config->get('Core.ColorKeywords');
+ if ($colors === null) {
+ $colors = $config->get('Core.ColorKeywords');
+ }
$color = trim($color);
- if ($color === '') return false;
+ if ($color === '') {
+ return false;
+ }
$lower = strtolower($color);
- if (isset($colors[$lower])) return $colors[$lower];
+ if (isset($colors[$lower])) {
+ return $colors[$lower];
+ }
if (strpos($color, 'rgb(') !== false) {
// rgb literal handling
$length = strlen($color);
- if (strpos($color, ')') !== $length - 1) return false;
+ if (strpos($color, ')') !== $length - 1) {
+ return false;
+ }
$triad = substr($color, 4, $length - 4 - 1);
$parts = explode(',', $triad);
- if (count($parts) !== 3) return false;
+ if (count($parts) !== 3) {
+ return false;
+ }
$type = false; // to ensure that they're all the same type
$new_parts = array();
foreach ($parts as $part) {
$part = trim($part);
- if ($part === '') return false;
+ if ($part === '') {
+ return false;
+ }
$length = strlen($part);
if ($part[$length - 1] === '%') {
// handle percents
@@ -37,9 +55,13 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
} elseif ($type !== 'percentage') {
return false;
}
- $num = (float) substr($part, 0, $length - 1);
- if ($num < 0) $num = 0;
- if ($num > 100) $num = 100;
+ $num = (float)substr($part, 0, $length - 1);
+ if ($num < 0) {
+ $num = 0;
+ }
+ if ($num > 100) {
+ $num = 100;
+ }
$new_parts[] = "$num%";
} else {
// handle integers
@@ -48,10 +70,14 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
} elseif ($type !== 'integer') {
return false;
}
- $num = (int) $part;
- if ($num < 0) $num = 0;
- if ($num > 255) $num = 255;
- $new_parts[] = (string) $num;
+ $num = (int)$part;
+ if ($num < 0) {
+ $num = 0;
+ }
+ if ($num > 255) {
+ $num = 255;
+ }
+ $new_parts[] = (string)$num;
}
}
$new_triad = implode(',', $new_parts);
@@ -65,14 +91,15 @@ class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
$color = '#' . $color;
}
$length = strlen($hex);
- if ($length !== 3 && $length !== 6) return false;
- if (!ctype_xdigit($hex)) return false;
+ if ($length !== 3 && $length !== 6) {
+ return false;
+ }
+ if (!ctype_xdigit($hex)) {
+ return false;
+ }
}
-
return $color;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/Composite.php b/library/HTMLPurifier/AttrDef/CSS/Composite.php
index de1289cba..9c1750554 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Composite.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Composite.php
@@ -13,26 +13,36 @@ class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef
{
/**
- * List of HTMLPurifier_AttrDef objects that may process strings
+ * List of objects that may process strings.
+ * @type HTMLPurifier_AttrDef[]
* @todo Make protected
*/
public $defs;
/**
- * @param $defs List of HTMLPurifier_AttrDef objects
+ * @param HTMLPurifier_AttrDef[] $defs List of HTMLPurifier_AttrDef objects
*/
- public function __construct($defs) {
+ public function __construct($defs)
+ {
$this->defs = $defs;
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
foreach ($this->defs as $i => $def) {
$result = $this->defs[$i]->validate($string, $config, $context);
- if ($result !== false) return $result;
+ if ($result !== false) {
+ return $result;
+ }
}
return false;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php
index 6599c5b2d..9d77cc9aa 100644
--- a/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php
+++ b/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php
@@ -5,22 +5,38 @@
*/
class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef
{
- public $def, $element;
+ /**
+ * @type HTMLPurifier_AttrDef
+ */
+ public $def;
+ /**
+ * @type string
+ */
+ public $element;
/**
- * @param $def Definition to wrap
- * @param $element Element to deny
+ * @param HTMLPurifier_AttrDef $def Definition to wrap
+ * @param string $element Element to deny
*/
- public function __construct($def, $element) {
+ public function __construct($def, $element)
+ {
$this->def = $def;
$this->element = $element;
}
+
/**
* Checks if CurrentToken is set and equal to $this->element
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
*/
- public function validate($string, $config, $context) {
+ public function validate($string, $config, $context)
+ {
$token = $context->get('CurrentToken', true);
- if ($token && $token->name == $this->element) return false;
+ if ($token && $token->name == $this->element) {
+ return false;
+ }
return $this->def->validate($string, $config, $context);
}
}
diff --git a/library/HTMLPurifier/AttrDef/CSS/Filter.php b/library/HTMLPurifier/AttrDef/CSS/Filter.php
index 147894b86..bde4c3301 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Filter.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Filter.php
@@ -7,23 +7,37 @@
*/
class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
{
-
+ /**
+ * @type HTMLPurifier_AttrDef_Integer
+ */
protected $intValidator;
- public function __construct() {
+ public function __construct()
+ {
$this->intValidator = new HTMLPurifier_AttrDef_Integer();
}
- public function validate($value, $config, $context) {
+ /**
+ * @param string $value
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($value, $config, $context)
+ {
$value = $this->parseCDATA($value);
- if ($value === 'none') return $value;
+ if ($value === 'none') {
+ return $value;
+ }
// if we looped this we could support multiple filters
$function_length = strcspn($value, '(');
$function = trim(substr($value, 0, $function_length));
if ($function !== 'alpha' &&
$function !== 'Alpha' &&
$function !== 'progid:DXImageTransform.Microsoft.Alpha'
- ) return false;
+ ) {
+ return false;
+ }
$cursor = $function_length + 1;
$parameters_length = strcspn($value, ')', $cursor);
$parameters = substr($value, $cursor, $parameters_length);
@@ -32,15 +46,25 @@ class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
$lookup = array();
foreach ($params as $param) {
list($key, $value) = explode('=', $param);
- $key = trim($key);
+ $key = trim($key);
$value = trim($value);
- if (isset($lookup[$key])) continue;
- if ($key !== 'opacity') continue;
+ if (isset($lookup[$key])) {
+ continue;
+ }
+ if ($key !== 'opacity') {
+ continue;
+ }
$value = $this->intValidator->validate($value, $config, $context);
- if ($value === false) continue;
- $int = (int) $value;
- if ($int > 100) $value = '100';
- if ($int < 0) $value = '0';
+ if ($value === false) {
+ continue;
+ }
+ $int = (int)$value;
+ if ($int > 100) {
+ $value = '100';
+ }
+ if ($int < 0) {
+ $value = '0';
+ }
$ret_params[] = "$key=$value";
$lookup[$key] = true;
}
@@ -48,7 +72,6 @@ class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
$ret_function = "$function($ret_parameters)";
return $ret_function;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/Font.php b/library/HTMLPurifier/AttrDef/CSS/Font.php
index 699ee0b70..579b97ef1 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Font.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Font.php
@@ -7,8 +7,8 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
{
/**
- * Local copy of component validators.
- *
+ * Local copy of validators
+ * @type HTMLPurifier_AttrDef[]
* @note If we moved specific CSS property definitions to their own
* classes instead of having them be assembled at run time by
* CSSDefinition, this wouldn't be necessary. We'd instantiate
@@ -16,18 +16,28 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
*/
protected $info = array();
- public function __construct($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function __construct($config)
+ {
$def = $config->getCSSDefinition();
- $this->info['font-style'] = $def->info['font-style'];
+ $this->info['font-style'] = $def->info['font-style'];
$this->info['font-variant'] = $def->info['font-variant'];
- $this->info['font-weight'] = $def->info['font-weight'];
- $this->info['font-size'] = $def->info['font-size'];
- $this->info['line-height'] = $def->info['line-height'];
- $this->info['font-family'] = $def->info['font-family'];
+ $this->info['font-weight'] = $def->info['font-weight'];
+ $this->info['font-size'] = $def->info['font-size'];
+ $this->info['line-height'] = $def->info['line-height'];
+ $this->info['font-family'] = $def->info['font-family'];
}
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
static $system_fonts = array(
'caption' => true,
'icon' => true,
@@ -39,7 +49,9 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
// regular pre-processing
$string = $this->parseCDATA($string);
- if ($string === '') return false;
+ if ($string === '') {
+ return false;
+ }
// check if it's one of the keywords
$lowercase_string = strtolower($string);
@@ -54,15 +66,20 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
$final = ''; // output
for ($i = 0, $size = count($bits); $i < $size; $i++) {
- if ($bits[$i] === '') continue;
+ if ($bits[$i] === '') {
+ continue;
+ }
switch ($stage) {
-
- // attempting to catch font-style, font-variant or font-weight
- case 0:
+ case 0: // attempting to catch font-style, font-variant or font-weight
foreach ($stage_1 as $validator_name) {
- if (isset($caught[$validator_name])) continue;
+ if (isset($caught[$validator_name])) {
+ continue;
+ }
$r = $this->info[$validator_name]->validate(
- $bits[$i], $config, $context);
+ $bits[$i],
+ $config,
+ $context
+ );
if ($r !== false) {
$final .= $r . ' ';
$caught[$validator_name] = true;
@@ -70,15 +87,17 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
}
}
// all three caught, continue on
- if (count($caught) >= 3) $stage = 1;
- if ($r !== false) break;
-
- // attempting to catch font-size and perhaps line-height
- case 1:
+ if (count($caught) >= 3) {
+ $stage = 1;
+ }
+ if ($r !== false) {
+ break;
+ }
+ case 1: // attempting to catch font-size and perhaps line-height
$found_slash = false;
if (strpos($bits[$i], '/') !== false) {
list($font_size, $line_height) =
- explode('/', $bits[$i]);
+ explode('/', $bits[$i]);
if ($line_height === '') {
// ooh, there's a space after the slash!
$line_height = false;
@@ -89,14 +108,19 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
$line_height = false;
}
$r = $this->info['font-size']->validate(
- $font_size, $config, $context);
+ $font_size,
+ $config,
+ $context
+ );
if ($r !== false) {
$final .= $r;
// attempt to catch line-height
if ($line_height === false) {
// we need to scroll forward
for ($j = $i + 1; $j < $size; $j++) {
- if ($bits[$j] === '') continue;
+ if ($bits[$j] === '') {
+ continue;
+ }
if ($bits[$j] === '/') {
if ($found_slash) {
return false;
@@ -116,7 +140,10 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
if ($found_slash) {
$i = $j;
$r = $this->info['line-height']->validate(
- $line_height, $config, $context);
+ $line_height,
+ $config,
+ $context
+ );
if ($r !== false) {
$final .= '/' . $r;
}
@@ -126,13 +153,14 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
break;
}
return false;
-
- // attempting to catch font-family
- case 2:
+ case 2: // attempting to catch font-family
$font_family =
implode(' ', array_slice($bits, $i, $size - $i));
$r = $this->info['font-family']->validate(
- $font_family, $config, $context);
+ $font_family,
+ $config,
+ $context
+ );
if ($r !== false) {
$final .= $r . ' ';
// processing completed successfully
@@ -143,7 +171,6 @@ class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
}
return false;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/FontFamily.php b/library/HTMLPurifier/AttrDef/CSS/FontFamily.php
index 42c2054c2..74e24c881 100644
--- a/library/HTMLPurifier/AttrDef/CSS/FontFamily.php
+++ b/library/HTMLPurifier/AttrDef/CSS/FontFamily.php
@@ -2,12 +2,58 @@
/**
* Validates a font family list according to CSS spec
- * @todo whitelisting allowed fonts would be nice
*/
class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
{
- public function validate($string, $config, $context) {
+ protected $mask = null;
+
+ public function __construct()
+ {
+ $this->mask = '_- ';
+ for ($c = 'a'; $c <= 'z'; $c++) {
+ $this->mask .= $c;
+ }
+ for ($c = 'A'; $c <= 'Z'; $c++) {
+ $this->mask .= $c;
+ }
+ for ($c = '0'; $c <= '9'; $c++) {
+ $this->mask .= $c;
+ } // cast-y, but should be fine
+ // special bytes used by UTF-8
+ for ($i = 0x80; $i <= 0xFF; $i++) {
+ // We don't bother excluding invalid bytes in this range,
+ // because the our restriction of well-formed UTF-8 will
+ // prevent these from ever occurring.
+ $this->mask .= chr($i);
+ }
+
+ /*
+ PHP's internal strcspn implementation is
+ O(length of string * length of mask), making it inefficient
+ for large masks. However, it's still faster than
+ preg_match 8)
+ for (p = s1;;) {
+ spanp = s2;
+ do {
+ if (*spanp == c || p == s1_end) {
+ return p - s1;
+ }
+ } while (spanp++ < (s2_end - 1));
+ c = *++p;
+ }
+ */
+ // possible optimization: invert the mask.
+ }
+
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
static $generic_names = array(
'serif' => true,
'sans-serif' => true,
@@ -15,24 +61,33 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
'fantasy' => true,
'cursive' => true
);
+ $allowed_fonts = $config->get('CSS.AllowedFonts');
// assume that no font names contain commas in them
$fonts = explode(',', $string);
$final = '';
- foreach($fonts as $font) {
+ foreach ($fonts as $font) {
$font = trim($font);
- if ($font === '') continue;
+ if ($font === '') {
+ continue;
+ }
// match a generic name
if (isset($generic_names[$font])) {
- $final .= $font . ', ';
+ if ($allowed_fonts === null || isset($allowed_fonts[$font])) {
+ $final .= $font . ', ';
+ }
continue;
}
// match a quoted name
if ($font[0] === '"' || $font[0] === "'") {
$length = strlen($font);
- if ($length <= 2) continue;
+ if ($length <= 2) {
+ continue;
+ }
$quote = $font[0];
- if ($font[$length - 1] !== $quote) continue;
+ if ($font[$length - 1] !== $quote) {
+ continue;
+ }
$font = substr($font, 1, $length - 2);
}
@@ -40,6 +95,10 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
// $font is a pure representation of the font name
+ if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) {
+ continue;
+ }
+
if (ctype_alnum($font) && $font !== '') {
// very simple font, allow it in unharmed
$final .= $font . ', ';
@@ -50,20 +109,108 @@ class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
// shouldn't show up regardless
$font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font);
- // These ugly transforms don't pose a security
- // risk (as \\ and \" might). We could try to be clever and
- // use single-quote wrapping when there is a double quote
- // present, but I have choosen not to implement that.
- // (warning: this code relies on the selection of quotation
- // mark below)
- $font = str_replace('\\', '\\5C ', $font);
- $font = str_replace('"', '\\22 ', $font);
-
- // complicated font, requires quoting
- $final .= "\"$font\", "; // note that this will later get turned into &quot;
+ // Here, there are various classes of characters which need
+ // to be treated differently:
+ // - Alphanumeric characters are essentially safe. We
+ // handled these above.
+ // - Spaces require quoting, though most parsers will do
+ // the right thing if there aren't any characters that
+ // can be misinterpreted
+ // - Dashes rarely occur, but they fairly unproblematic
+ // for parsing/rendering purposes.
+ // The above characters cover the majority of Western font
+ // names.
+ // - Arbitrary Unicode characters not in ASCII. Because
+ // most parsers give little thought to Unicode, treatment
+ // of these codepoints is basically uniform, even for
+ // punctuation-like codepoints. These characters can
+ // show up in non-Western pages and are supported by most
+ // major browsers, for example: "MS 明朝" is a
+ // legitimate font-name
+ // <http://ja.wikipedia.org/wiki/MS_明朝>. See
+ // the CSS3 spec for more examples:
+ // <http://www.w3.org/TR/2011/WD-css3-fonts-20110324/localizedfamilynames.png>
+ // You can see live samples of these on the Internet:
+ // <http://www.google.co.jp/search?q=font-family+MS+明朝|ゴシック>
+ // However, most of these fonts have ASCII equivalents:
+ // for example, 'MS Mincho', and it's considered
+ // professional to use ASCII font names instead of
+ // Unicode font names. Thanks Takeshi Terada for
+ // providing this information.
+ // The following characters, to my knowledge, have not been
+ // used to name font names.
+ // - Single quote. While theoretically you might find a
+ // font name that has a single quote in its name (serving
+ // as an apostrophe, e.g. Dave's Scribble), I haven't
+ // been able to find any actual examples of this.
+ // Internet Explorer's cssText translation (which I
+ // believe is invoked by innerHTML) normalizes any
+ // quoting to single quotes, and fails to escape single
+ // quotes. (Note that this is not IE's behavior for all
+ // CSS properties, just some sort of special casing for
+ // font-family). So a single quote *cannot* be used
+ // safely in the font-family context if there will be an
+ // innerHTML/cssText translation. Note that Firefox 3.x
+ // does this too.
+ // - Double quote. In IE, these get normalized to
+ // single-quotes, no matter what the encoding. (Fun
+ // fact, in IE8, the 'content' CSS property gained
+ // support, where they special cased to preserve encoded
+ // double quotes, but still translate unadorned double
+ // quotes into single quotes.) So, because their
+ // fixpoint behavior is identical to single quotes, they
+ // cannot be allowed either. Firefox 3.x displays
+ // single-quote style behavior.
+ // - Backslashes are reduced by one (so \\ -> \) every
+ // iteration, so they cannot be used safely. This shows
+ // up in IE7, IE8 and FF3
+ // - Semicolons, commas and backticks are handled properly.
+ // - The rest of the ASCII punctuation is handled properly.
+ // We haven't checked what browsers do to unadorned
+ // versions, but this is not important as long as the
+ // browser doesn't /remove/ surrounding quotes (as IE does
+ // for HTML).
+ //
+ // With these results in hand, we conclude that there are
+ // various levels of safety:
+ // - Paranoid: alphanumeric, spaces and dashes(?)
+ // - International: Paranoid + non-ASCII Unicode
+ // - Edgy: Everything except quotes, backslashes
+ // - NoJS: Standards compliance, e.g. sod IE. Note that
+ // with some judicious character escaping (since certain
+ // types of escaping doesn't work) this is theoretically
+ // OK as long as innerHTML/cssText is not called.
+ // We believe that international is a reasonable default
+ // (that we will implement now), and once we do more
+ // extensive research, we may feel comfortable with dropping
+ // it down to edgy.
+
+ // Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of
+ // str(c)spn assumes that the string was already well formed
+ // Unicode (which of course it is).
+ if (strspn($font, $this->mask) !== strlen($font)) {
+ continue;
+ }
+
+ // Historical:
+ // In the absence of innerHTML/cssText, these ugly
+ // transforms don't pose a security risk (as \\ and \"
+ // might--these escapes are not supported by most browsers).
+ // We could try to be clever and use single-quote wrapping
+ // when there is a double quote present, but I have choosen
+ // not to implement that. (NOTE: you can reduce the amount
+ // of escapes by one depending on what quoting style you use)
+ // $font = str_replace('\\', '\\5C ', $font);
+ // $font = str_replace('"', '\\22 ', $font);
+ // $font = str_replace("'", '\\27 ', $font);
+
+ // font possibly with spaces, requires quoting
+ $final .= "'$font', ";
}
$final = rtrim($final, ', ');
- if ($final === '') return false;
+ if ($final === '') {
+ return false;
+ }
return $final;
}
diff --git a/library/HTMLPurifier/AttrDef/CSS/Ident.php b/library/HTMLPurifier/AttrDef/CSS/Ident.php
new file mode 100644
index 000000000..973002c17
--- /dev/null
+++ b/library/HTMLPurifier/AttrDef/CSS/Ident.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Validates based on {ident} CSS grammar production
+ */
+class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef
+{
+
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
+ $string = trim($string);
+
+ // early abort: '' and '0' (strings that convert to false) are invalid
+ if (!$string) {
+ return false;
+ }
+
+ $pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/';
+ if (!preg_match($pattern, $string)) {
+ return false;
+ }
+ return $string;
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php b/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php
index 4e6b35e5a..ffc989fe8 100644
--- a/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php
+++ b/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php
@@ -5,20 +5,34 @@
*/
class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
{
- public $def, $allow;
+ /**
+ * @type HTMLPurifier_AttrDef
+ */
+ public $def;
+ /**
+ * @type bool
+ */
+ public $allow;
/**
- * @param $def Definition to wrap
- * @param $allow Whether or not to allow !important
+ * @param HTMLPurifier_AttrDef $def Definition to wrap
+ * @param bool $allow Whether or not to allow !important
*/
- public function __construct($def, $allow = false) {
+ public function __construct($def, $allow = false)
+ {
$this->def = $def;
$this->allow = $allow;
}
+
/**
* Intercepts and removes !important if necessary
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
*/
- public function validate($string, $config, $context) {
+ public function validate($string, $config, $context)
+ {
// test for ! and important tokens
$string = trim($string);
$is_important = false;
@@ -32,7 +46,9 @@ class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
}
}
$string = $this->def->validate($string, $config, $context);
- if ($this->allow && $is_important) $string .= ' !important';
+ if ($this->allow && $is_important) {
+ $string .= ' !important';
+ }
return $string;
}
}
diff --git a/library/HTMLPurifier/AttrDef/CSS/Length.php b/library/HTMLPurifier/AttrDef/CSS/Length.php
index a07ec5813..f12453a04 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Length.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Length.php
@@ -6,42 +6,72 @@
class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef
{
- protected $min, $max;
+ /**
+ * @type HTMLPurifier_Length|string
+ */
+ protected $min;
/**
- * @param HTMLPurifier_Length $max Minimum length, or null for no bound. String is also acceptable.
- * @param HTMLPurifier_Length $max Maximum length, or null for no bound. String is also acceptable.
+ * @type HTMLPurifier_Length|string
*/
- public function __construct($min = null, $max = null) {
+ protected $max;
+
+ /**
+ * @param HTMLPurifier_Length|string $min Minimum length, or null for no bound. String is also acceptable.
+ * @param HTMLPurifier_Length|string $max Maximum length, or null for no bound. String is also acceptable.
+ */
+ public function __construct($min = null, $max = null)
+ {
$this->min = $min !== null ? HTMLPurifier_Length::make($min) : null;
$this->max = $max !== null ? HTMLPurifier_Length::make($max) : null;
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = $this->parseCDATA($string);
// Optimizations
- if ($string === '') return false;
- if ($string === '0') return '0';
- if (strlen($string) === 1) return false;
+ if ($string === '') {
+ return false;
+ }
+ if ($string === '0') {
+ return '0';
+ }
+ if (strlen($string) === 1) {
+ return false;
+ }
$length = HTMLPurifier_Length::make($string);
- if (!$length->isValid()) return false;
+ if (!$length->isValid()) {
+ return false;
+ }
if ($this->min) {
$c = $length->compareTo($this->min);
- if ($c === false) return false;
- if ($c < 0) return false;
+ if ($c === false) {
+ return false;
+ }
+ if ($c < 0) {
+ return false;
+ }
}
if ($this->max) {
$c = $length->compareTo($this->max);
- if ($c === false) return false;
- if ($c > 0) return false;
+ if ($c === false) {
+ return false;
+ }
+ if ($c > 0) {
+ return false;
+ }
}
-
return $length->toString();
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/ListStyle.php b/library/HTMLPurifier/AttrDef/CSS/ListStyle.php
index 4406868c0..e74d42654 100644
--- a/library/HTMLPurifier/AttrDef/CSS/ListStyle.php
+++ b/library/HTMLPurifier/AttrDef/CSS/ListStyle.php
@@ -8,46 +8,72 @@ class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
{
/**
- * Local copy of component validators.
+ * Local copy of validators.
+ * @type HTMLPurifier_AttrDef[]
* @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl.
*/
protected $info;
- public function __construct($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function __construct($config)
+ {
$def = $config->getCSSDefinition();
- $this->info['list-style-type'] = $def->info['list-style-type'];
+ $this->info['list-style-type'] = $def->info['list-style-type'];
$this->info['list-style-position'] = $def->info['list-style-position'];
$this->info['list-style-image'] = $def->info['list-style-image'];
}
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
// regular pre-processing
$string = $this->parseCDATA($string);
- if ($string === '') return false;
+ if ($string === '') {
+ return false;
+ }
// assumes URI doesn't have spaces in it
$bits = explode(' ', strtolower($string)); // bits to process
$caught = array();
- $caught['type'] = false;
+ $caught['type'] = false;
$caught['position'] = false;
- $caught['image'] = false;
+ $caught['image'] = false;
$i = 0; // number of catches
$none = false;
foreach ($bits as $bit) {
- if ($i >= 3) return; // optimization bit
- if ($bit === '') continue;
+ if ($i >= 3) {
+ return;
+ } // optimization bit
+ if ($bit === '') {
+ continue;
+ }
foreach ($caught as $key => $status) {
- if ($status !== false) continue;
+ if ($status !== false) {
+ continue;
+ }
$r = $this->info['list-style-' . $key]->validate($bit, $config, $context);
- if ($r === false) continue;
+ if ($r === false) {
+ continue;
+ }
if ($r === 'none') {
- if ($none) continue;
- else $none = true;
- if ($key == 'image') continue;
+ if ($none) {
+ continue;
+ } else {
+ $none = true;
+ }
+ if ($key == 'image') {
+ continue;
+ }
}
$caught[$key] = $r;
$i++;
@@ -55,24 +81,32 @@ class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
}
}
- if (!$i) return false;
+ if (!$i) {
+ return false;
+ }
$ret = array();
// construct type
- if ($caught['type']) $ret[] = $caught['type'];
+ if ($caught['type']) {
+ $ret[] = $caught['type'];
+ }
// construct image
- if ($caught['image']) $ret[] = $caught['image'];
+ if ($caught['image']) {
+ $ret[] = $caught['image'];
+ }
// construct position
- if ($caught['position']) $ret[] = $caught['position'];
+ if ($caught['position']) {
+ $ret[] = $caught['position'];
+ }
- if (empty($ret)) return false;
+ if (empty($ret)) {
+ return false;
+ }
return implode(' ', $ret);
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/Multiple.php b/library/HTMLPurifier/AttrDef/CSS/Multiple.php
index 4d62a40d7..9f266cdd1 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Multiple.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Multiple.php
@@ -13,9 +13,9 @@
*/
class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
{
-
/**
* Instance of component definition to defer validation to.
+ * @type HTMLPurifier_AttrDef
* @todo Make protected
*/
public $single;
@@ -27,32 +27,45 @@ class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
public $max;
/**
- * @param $single HTMLPurifier_AttrDef to multiply
- * @param $max Max number of values allowed (usually four)
+ * @param HTMLPurifier_AttrDef $single HTMLPurifier_AttrDef to multiply
+ * @param int $max Max number of values allowed (usually four)
*/
- public function __construct($single, $max = 4) {
+ public function __construct($single, $max = 4)
+ {
$this->single = $single;
$this->max = $max;
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = $this->parseCDATA($string);
- if ($string === '') return false;
+ if ($string === '') {
+ return false;
+ }
$parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n
$length = count($parts);
$final = '';
for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) {
- if (ctype_space($parts[$i])) continue;
+ if (ctype_space($parts[$i])) {
+ continue;
+ }
$result = $this->single->validate($parts[$i], $config, $context);
if ($result !== false) {
$final .= $result . ' ';
$num++;
}
}
- if ($final === '') return false;
+ if ($final === '') {
+ return false;
+ }
return rtrim($final);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/Number.php b/library/HTMLPurifier/AttrDef/CSS/Number.php
index 3f99e12ec..8edc159e7 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Number.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Number.php
@@ -7,32 +7,44 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
{
/**
- * Bool indicating whether or not only positive values allowed.
+ * Indicates whether or not only positive values are allowed.
+ * @type bool
*/
protected $non_negative = false;
/**
- * @param $non_negative Bool indicating whether negatives are forbidden
+ * @param bool $non_negative indicates whether negatives are forbidden
*/
- public function __construct($non_negative = false) {
+ public function __construct($non_negative = false)
+ {
$this->non_negative = $non_negative;
}
/**
+ * @param string $number
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string|bool
* @warning Some contexts do not pass $config, $context. These
* variables should not be used without checking HTMLPurifier_Length
*/
- public function validate($number, $config, $context) {
-
+ public function validate($number, $config, $context)
+ {
$number = $this->parseCDATA($number);
- if ($number === '') return false;
- if ($number === '0') return '0';
+ if ($number === '') {
+ return false;
+ }
+ if ($number === '0') {
+ return '0';
+ }
$sign = '';
switch ($number[0]) {
case '-':
- if ($this->non_negative) return false;
+ if ($this->non_negative) {
+ return false;
+ }
$sign = '-';
case '+':
$number = substr($number, 1);
@@ -44,14 +56,20 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
}
// Period is the only non-numeric character allowed
- if (strpos($number, '.') === false) return false;
+ if (strpos($number, '.') === false) {
+ return false;
+ }
list($left, $right) = explode('.', $number, 2);
- if ($left === '' && $right === '') return false;
- if ($left !== '' && !ctype_digit($left)) return false;
+ if ($left === '' && $right === '') {
+ return false;
+ }
+ if ($left !== '' && !ctype_digit($left)) {
+ return false;
+ }
- $left = ltrim($left, '0');
+ $left = ltrim($left, '0');
$right = rtrim($right, '0');
if ($right === '') {
@@ -59,11 +77,8 @@ class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
} elseif (!ctype_digit($right)) {
return false;
}
-
return $sign . $left . '.' . $right;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/Percentage.php b/library/HTMLPurifier/AttrDef/CSS/Percentage.php
index c34b8fc3c..f0f25c50a 100644
--- a/library/HTMLPurifier/AttrDef/CSS/Percentage.php
+++ b/library/HTMLPurifier/AttrDef/CSS/Percentage.php
@@ -7,34 +7,48 @@ class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef
{
/**
- * Instance of HTMLPurifier_AttrDef_CSS_Number to defer number validation
+ * Instance to defer number validation to.
+ * @type HTMLPurifier_AttrDef_CSS_Number
*/
protected $number_def;
/**
- * @param Bool indicating whether to forbid negative values
+ * @param bool $non_negative Whether to forbid negative values
*/
- public function __construct($non_negative = false) {
+ public function __construct($non_negative = false)
+ {
$this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative);
}
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = $this->parseCDATA($string);
- if ($string === '') return false;
+ if ($string === '') {
+ return false;
+ }
$length = strlen($string);
- if ($length === 1) return false;
- if ($string[$length - 1] !== '%') return false;
+ if ($length === 1) {
+ return false;
+ }
+ if ($string[$length - 1] !== '%') {
+ return false;
+ }
$number = substr($string, 0, $length - 1);
$number = $this->number_def->validate($number, $config, $context);
- if ($number === false) return false;
+ if ($number === false) {
+ return false;
+ }
return "$number%";
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php
index 772c922d8..5fd4b7f7b 100644
--- a/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php
+++ b/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php
@@ -8,8 +8,14 @@
class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
{
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
static $allowed_values = array(
'line-through' => true,
'overline' => true,
@@ -18,7 +24,9 @@ class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
$string = strtolower($this->parseCDATA($string));
- if ($string === 'none') return $string;
+ if ($string === 'none') {
+ return $string;
+ }
$parts = explode(' ', $string);
$final = '';
@@ -28,11 +36,11 @@ class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
}
}
$final = rtrim($final);
- if ($final === '') return false;
+ if ($final === '') {
+ return false;
+ }
return $final;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/CSS/URI.php b/library/HTMLPurifier/AttrDef/CSS/URI.php
index 1df17dc25..f9434230e 100644
--- a/library/HTMLPurifier/AttrDef/CSS/URI.php
+++ b/library/HTMLPurifier/AttrDef/CSS/URI.php
@@ -12,25 +12,39 @@
class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
{
- public function __construct() {
+ public function __construct()
+ {
parent::__construct(true); // always embedded
}
- public function validate($uri_string, $config, $context) {
+ /**
+ * @param string $uri_string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($uri_string, $config, $context)
+ {
// parse the URI out of the string and then pass it onto
// the parent object
$uri_string = $this->parseCDATA($uri_string);
- if (strpos($uri_string, 'url(') !== 0) return false;
+ if (strpos($uri_string, 'url(') !== 0) {
+ return false;
+ }
$uri_string = substr($uri_string, 4);
$new_length = strlen($uri_string) - 1;
- if ($uri_string[$new_length] != ')') return false;
+ if ($uri_string[$new_length] != ')') {
+ return false;
+ }
$uri = trim(substr($uri_string, 0, $new_length));
if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) {
$quote = $uri[0];
$new_length = strlen($uri) - 1;
- if ($uri[$new_length] !== $quote) return false;
+ if ($uri[$new_length] !== $quote) {
+ return false;
+ }
$uri = substr($uri, 1, $new_length - 1);
}
@@ -38,15 +52,23 @@ class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
$result = parent::validate($uri, $config, $context);
- if ($result === false) return false;
+ if ($result === false) {
+ return false;
+ }
// extra sanity check; should have been done by URI
$result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result);
- return "url(\"$result\")";
+ // suspicious characters are ()'; we're going to percent encode
+ // them for safety.
+ $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result);
+ // there's an extra bug where ampersands lose their escaping on
+ // an innerHTML cycle, so a very unlucky query parameter could
+ // then change the meaning of the URL. Unfortunately, there's
+ // not much we can do about that...
+ return "url(\"$result\")";
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/Clone.php b/library/HTMLPurifier/AttrDef/Clone.php
new file mode 100644
index 000000000..6698a00c0
--- /dev/null
+++ b/library/HTMLPurifier/AttrDef/Clone.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * Dummy AttrDef that mimics another AttrDef, BUT it generates clones
+ * with make.
+ */
+class HTMLPurifier_AttrDef_Clone extends HTMLPurifier_AttrDef
+{
+ /**
+ * What we're cloning.
+ * @type HTMLPurifier_AttrDef
+ */
+ protected $clone;
+
+ /**
+ * @param HTMLPurifier_AttrDef $clone
+ */
+ public function __construct($clone)
+ {
+ $this->clone = $clone;
+ }
+
+ /**
+ * @param string $v
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($v, $config, $context)
+ {
+ return $this->clone->validate($v, $config, $context);
+ }
+
+ /**
+ * @param string $string
+ * @return HTMLPurifier_AttrDef
+ */
+ public function make($string)
+ {
+ return clone $this->clone;
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/Enum.php b/library/HTMLPurifier/AttrDef/Enum.php
index 5d603ebcc..8abda7f6e 100644
--- a/library/HTMLPurifier/AttrDef/Enum.php
+++ b/library/HTMLPurifier/AttrDef/Enum.php
@@ -12,9 +12,10 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
/**
* Lookup table of valid values.
+ * @type array
* @todo Make protected
*/
- public $valid_values = array();
+ public $valid_values = array();
/**
* Bool indicating whether or not enumeration is case sensitive.
@@ -23,17 +24,23 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
protected $case_sensitive = false; // values according to W3C spec
/**
- * @param $valid_values List of valid values
- * @param $case_sensitive Bool indicating whether or not case sensitive
+ * @param array $valid_values List of valid values
+ * @param bool $case_sensitive Whether or not case sensitive
*/
- public function __construct(
- $valid_values = array(), $case_sensitive = false
- ) {
+ public function __construct($valid_values = array(), $case_sensitive = false)
+ {
$this->valid_values = array_flip($valid_values);
$this->case_sensitive = $case_sensitive;
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = trim($string);
if (!$this->case_sensitive) {
// we may want to do full case-insensitive libraries
@@ -45,11 +52,13 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
}
/**
- * @param $string In form of comma-delimited list of case-insensitive
+ * @param string $string In form of comma-delimited list of case-insensitive
* valid values. Example: "foo,bar,baz". Prepend "s:" to make
* case sensitive
+ * @return HTMLPurifier_AttrDef_Enum
*/
- public function make($string) {
+ public function make($string)
+ {
if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') {
$string = substr($string, 2);
$sensitive = true;
@@ -59,7 +68,6 @@ class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
$values = explode(',', $string);
return new HTMLPurifier_AttrDef_Enum($values, $sensitive);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/Bool.php b/library/HTMLPurifier/AttrDef/HTML/Bool.php
index e06987eb8..036a240e1 100644
--- a/library/HTMLPurifier/AttrDef/HTML/Bool.php
+++ b/library/HTMLPurifier/AttrDef/HTML/Bool.php
@@ -6,23 +6,46 @@
class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef
{
+ /**
+ * @type bool
+ */
protected $name;
+
+ /**
+ * @type bool
+ */
public $minimized = true;
- public function __construct($name = false) {$this->name = $name;}
+ /**
+ * @param bool $name
+ */
+ public function __construct($name = false)
+ {
+ $this->name = $name;
+ }
- public function validate($string, $config, $context) {
- if (empty($string)) return false;
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
+ if (empty($string)) {
+ return false;
+ }
return $this->name;
}
/**
- * @param $string Name of attribute
+ * @param string $string Name of attribute
+ * @return HTMLPurifier_AttrDef_HTML_Bool
*/
- public function make($string) {
+ public function make($string)
+ {
return new HTMLPurifier_AttrDef_HTML_Bool($string);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/Class.php b/library/HTMLPurifier/AttrDef/HTML/Class.php
index 370068d97..d5013488f 100644
--- a/library/HTMLPurifier/AttrDef/HTML/Class.php
+++ b/library/HTMLPurifier/AttrDef/HTML/Class.php
@@ -5,7 +5,14 @@
*/
class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens
{
- protected function split($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ protected function split($string, $config, $context)
+ {
// really, this twiddle should be lazy loaded
$name = $config->getDefinition('HTML')->doctype->name;
if ($name == "XHTML 1.1" || $name == "XHTML 2.0") {
@@ -14,13 +21,20 @@ class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens
return preg_split('/\s+/', $string);
}
}
- protected function filter($tokens, $config, $context) {
+
+ /**
+ * @param array $tokens
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ protected function filter($tokens, $config, $context)
+ {
$allowed = $config->get('Attr.AllowedClasses');
$forbidden = $config->get('Attr.ForbiddenClasses');
$ret = array();
foreach ($tokens as $token) {
- if (
- ($allowed === null || isset($allowed[$token])) &&
+ if (($allowed === null || isset($allowed[$token])) &&
!isset($forbidden[$token]) &&
// We need this O(n) check because of PHP's array
// implementation that casts -0 to 0.
diff --git a/library/HTMLPurifier/AttrDef/HTML/Color.php b/library/HTMLPurifier/AttrDef/HTML/Color.php
index d01e20454..946ebb782 100644
--- a/library/HTMLPurifier/AttrDef/HTML/Color.php
+++ b/library/HTMLPurifier/AttrDef/HTML/Color.php
@@ -6,27 +6,46 @@
class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef
{
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
static $colors = null;
- if ($colors === null) $colors = $config->get('Core.ColorKeywords');
+ if ($colors === null) {
+ $colors = $config->get('Core.ColorKeywords');
+ }
$string = trim($string);
- if (empty($string)) return false;
- if (isset($colors[$string])) return $colors[$string];
- if ($string[0] === '#') $hex = substr($string, 1);
- else $hex = $string;
+ if (empty($string)) {
+ return false;
+ }
+ $lower = strtolower($string);
+ if (isset($colors[$lower])) {
+ return $colors[$lower];
+ }
+ if ($string[0] === '#') {
+ $hex = substr($string, 1);
+ } else {
+ $hex = $string;
+ }
$length = strlen($hex);
- if ($length !== 3 && $length !== 6) return false;
- if (!ctype_xdigit($hex)) return false;
- if ($length === 3) $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
-
+ if ($length !== 3 && $length !== 6) {
+ return false;
+ }
+ if (!ctype_xdigit($hex)) {
+ return false;
+ }
+ if ($length === 3) {
+ $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
+ }
return "#$hex";
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php
index ae6ea7c01..d79ba12b3 100644
--- a/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php
+++ b/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php
@@ -6,16 +6,33 @@
class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum
{
+ /**
+ * @type array
+ */
public $valid_values = false; // uninitialized value
+
+ /**
+ * @type bool
+ */
protected $case_sensitive = false;
- public function __construct() {}
+ public function __construct()
+ {
+ }
- public function validate($string, $config, $context) {
- if ($this->valid_values === false) $this->valid_values = $config->get('Attr.AllowedFrameTargets');
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
+ if ($this->valid_values === false) {
+ $this->valid_values = $config->get('Attr.AllowedFrameTargets');
+ }
return parent::validate($string, $config, $context);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/ID.php b/library/HTMLPurifier/AttrDef/HTML/ID.php
index 81d03762d..3d86efb44 100644
--- a/library/HTMLPurifier/AttrDef/HTML/ID.php
+++ b/library/HTMLPurifier/AttrDef/HTML/ID.php
@@ -12,42 +12,77 @@
class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
{
- // ref functionality disabled, since we also have to verify
- // whether or not the ID it refers to exists
-
- public function validate($id, $config, $context) {
+ // selector is NOT a valid thing to use for IDREFs, because IDREFs
+ // *must* target IDs that exist, whereas selector #ids do not.
+
+ /**
+ * Determines whether or not we're validating an ID in a CSS
+ * selector context.
+ * @type bool
+ */
+ protected $selector;
+
+ /**
+ * @param bool $selector
+ */
+ public function __construct($selector = false)
+ {
+ $this->selector = $selector;
+ }
- if (!$config->get('Attr.EnableID')) return false;
+ /**
+ * @param string $id
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($id, $config, $context)
+ {
+ if (!$this->selector && !$config->get('Attr.EnableID')) {
+ return false;
+ }
$id = trim($id); // trim it first
- if ($id === '') return false;
+ if ($id === '') {
+ return false;
+ }
$prefix = $config->get('Attr.IDPrefix');
if ($prefix !== '') {
$prefix .= $config->get('Attr.IDPrefixLocal');
// prevent re-appending the prefix
- if (strpos($id, $prefix) !== 0) $id = $prefix . $id;
+ if (strpos($id, $prefix) !== 0) {
+ $id = $prefix . $id;
+ }
} elseif ($config->get('Attr.IDPrefixLocal') !== '') {
- trigger_error('%Attr.IDPrefixLocal cannot be used unless '.
- '%Attr.IDPrefix is set', E_USER_WARNING);
+ trigger_error(
+ '%Attr.IDPrefixLocal cannot be used unless ' .
+ '%Attr.IDPrefix is set',
+ E_USER_WARNING
+ );
}
- //if (!$this->ref) {
+ if (!$this->selector) {
$id_accumulator =& $context->get('IDAccumulator');
- if (isset($id_accumulator->ids[$id])) return false;
- //}
+ if (isset($id_accumulator->ids[$id])) {
+ return false;
+ }
+ }
// we purposely avoid using regex, hopefully this is faster
if (ctype_alpha($id)) {
$result = true;
} else {
- if (!ctype_alpha(@$id[0])) return false;
- $trim = trim( // primitive style of regexps, I suppose
+ if (!ctype_alpha(@$id[0])) {
+ return false;
+ }
+ // primitive style of regexps, I suppose
+ $trim = trim(
$id,
'A..Za..z0..9:-._'
- );
+ );
$result = ($trim === '');
}
@@ -56,15 +91,15 @@ class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
return false;
}
- if (/*!$this->ref && */$result) $id_accumulator->add($id);
+ if (!$this->selector && $result) {
+ $id_accumulator->add($id);
+ }
// if no change was made to the ID, return the result
// else, return the new id if stripping whitespace made it
// valid, or return false.
return $result ? $id : false;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/Length.php b/library/HTMLPurifier/AttrDef/HTML/Length.php
index a242f9c23..1c4006fbb 100644
--- a/library/HTMLPurifier/AttrDef/HTML/Length.php
+++ b/library/HTMLPurifier/AttrDef/HTML/Length.php
@@ -10,32 +10,47 @@
class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels
{
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = trim($string);
- if ($string === '') return false;
+ if ($string === '') {
+ return false;
+ }
$parent_result = parent::validate($string, $config, $context);
- if ($parent_result !== false) return $parent_result;
+ if ($parent_result !== false) {
+ return $parent_result;
+ }
$length = strlen($string);
$last_char = $string[$length - 1];
- if ($last_char !== '%') return false;
+ if ($last_char !== '%') {
+ return false;
+ }
$points = substr($string, 0, $length - 1);
- if (!is_numeric($points)) return false;
-
- $points = (int) $points;
+ if (!is_numeric($points)) {
+ return false;
+ }
- if ($points < 0) return '0%';
- if ($points > 100) return '100%';
-
- return ((string) $points) . '%';
+ $points = (int)$points;
+ if ($points < 0) {
+ return '0%';
+ }
+ if ($points > 100) {
+ return '100%';
+ }
+ return ((string)$points) . '%';
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php
index 76d25ed08..63fa04c15 100644
--- a/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php
+++ b/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php
@@ -9,26 +9,44 @@
class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
{
- /** Name config attribute to pull. */
+ /**
+ * Name config attribute to pull.
+ * @type string
+ */
protected $name;
- public function __construct($name) {
+ /**
+ * @param string $name
+ */
+ public function __construct($name)
+ {
$configLookup = array(
'rel' => 'AllowedRel',
'rev' => 'AllowedRev'
);
if (!isset($configLookup[$name])) {
- trigger_error('Unrecognized attribute name for link '.
- 'relationship.', E_USER_ERROR);
+ trigger_error(
+ 'Unrecognized attribute name for link ' .
+ 'relationship.',
+ E_USER_ERROR
+ );
return;
}
$this->name = $configLookup[$name];
}
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$allowed = $config->get('Attr.' . $this->name);
- if (empty($allowed)) return false;
+ if (empty($allowed)) {
+ return false;
+ }
$string = $this->parseCDATA($string);
$parts = explode(' ', $string);
@@ -37,17 +55,18 @@ class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
$ret_lookup = array();
foreach ($parts as $part) {
$part = strtolower(trim($part));
- if (!isset($allowed[$part])) continue;
+ if (!isset($allowed[$part])) {
+ continue;
+ }
$ret_lookup[$part] = true;
}
- if (empty($ret_lookup)) return false;
+ if (empty($ret_lookup)) {
+ return false;
+ }
$string = implode(' ', array_keys($ret_lookup));
-
return $string;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/MultiLength.php b/library/HTMLPurifier/AttrDef/HTML/MultiLength.php
index c72fc76e4..bbb20f2f8 100644
--- a/library/HTMLPurifier/AttrDef/HTML/MultiLength.php
+++ b/library/HTMLPurifier/AttrDef/HTML/MultiLength.php
@@ -9,33 +9,52 @@
class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Length
{
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = trim($string);
- if ($string === '') return false;
+ if ($string === '') {
+ return false;
+ }
$parent_result = parent::validate($string, $config, $context);
- if ($parent_result !== false) return $parent_result;
+ if ($parent_result !== false) {
+ return $parent_result;
+ }
$length = strlen($string);
$last_char = $string[$length - 1];
- if ($last_char !== '*') return false;
+ if ($last_char !== '*') {
+ return false;
+ }
$int = substr($string, 0, $length - 1);
- if ($int == '') return '*';
- if (!is_numeric($int)) return false;
-
- $int = (int) $int;
-
- if ($int < 0) return false;
- if ($int == 0) return '0';
- if ($int == 1) return '*';
- return ((string) $int) . '*';
-
+ if ($int == '') {
+ return '*';
+ }
+ if (!is_numeric($int)) {
+ return false;
+ }
+
+ $int = (int)$int;
+ if ($int < 0) {
+ return false;
+ }
+ if ($int == 0) {
+ return '0';
+ }
+ if ($int == 1) {
+ return '*';
+ }
+ return ((string)$int) . '*';
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php b/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php
index aa34120bd..f79683b4f 100644
--- a/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php
+++ b/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php
@@ -6,24 +6,38 @@
class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
{
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = trim($string);
// early abort: '' and '0' (strings that convert to false) are invalid
- if (!$string) return false;
+ if (!$string) {
+ return false;
+ }
$tokens = $this->split($string, $config, $context);
$tokens = $this->filter($tokens, $config, $context);
- if (empty($tokens)) return false;
+ if (empty($tokens)) {
+ return false;
+ }
return implode(' ', $tokens);
-
}
/**
* Splits a space separated list of tokens into its constituent parts.
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
*/
- protected function split($string, $config, $context) {
+ protected function split($string, $config, $context)
+ {
// OPTIMIZABLE!
// do the preg_match, capture all subpatterns for reformulation
@@ -31,9 +45,9 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
// escaping because I don't know how to do that with regexps
// and plus it would complicate optimization efforts (you never
// see that anyway).
- $pattern = '/(?:(?<=\s)|\A)'. // look behind for space or string start
- '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)'.
- '(?:(?=\s)|\z)/'; // look ahead for space or string end
+ $pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start
+ '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' .
+ '(?:(?=\s)|\z)/'; // look ahead for space or string end
preg_match_all($pattern, $string, $matches);
return $matches[1];
}
@@ -42,11 +56,15 @@ class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
* Template method for removing certain tokens based on arbitrary criteria.
* @note If we wanted to be really functional, we'd do an array_filter
* with a callback. But... we're not.
+ * @param array $tokens
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
*/
- protected function filter($tokens, $config, $context) {
+ protected function filter($tokens, $config, $context)
+ {
return $tokens;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/HTML/Pixels.php b/library/HTMLPurifier/AttrDef/HTML/Pixels.php
index 4cb2c1b85..a1d019e09 100644
--- a/library/HTMLPurifier/AttrDef/HTML/Pixels.php
+++ b/library/HTMLPurifier/AttrDef/HTML/Pixels.php
@@ -6,43 +6,71 @@
class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef
{
+ /**
+ * @type int
+ */
protected $max;
- public function __construct($max = null) {
+ /**
+ * @param int $max
+ */
+ public function __construct($max = null)
+ {
$this->max = $max;
}
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = trim($string);
- if ($string === '0') return $string;
- if ($string === '') return false;
+ if ($string === '0') {
+ return $string;
+ }
+ if ($string === '') {
+ return false;
+ }
$length = strlen($string);
if (substr($string, $length - 2) == 'px') {
$string = substr($string, 0, $length - 2);
}
- if (!is_numeric($string)) return false;
- $int = (int) $string;
+ if (!is_numeric($string)) {
+ return false;
+ }
+ $int = (int)$string;
- if ($int < 0) return '0';
+ if ($int < 0) {
+ return '0';
+ }
// upper-bound value, extremely high values can
// crash operating systems, see <http://ha.ckers.org/imagecrash.html>
// WARNING, above link WILL crash you if you're using Windows
- if ($this->max !== null && $int > $this->max) return (string) $this->max;
-
- return (string) $int;
-
+ if ($this->max !== null && $int > $this->max) {
+ return (string)$this->max;
+ }
+ return (string)$int;
}
- public function make($string) {
- if ($string === '') $max = null;
- else $max = (int) $string;
+ /**
+ * @param string $string
+ * @return HTMLPurifier_AttrDef
+ */
+ public function make($string)
+ {
+ if ($string === '') {
+ $max = null;
+ } else {
+ $max = (int)$string;
+ }
$class = get_class($this);
return new $class($max);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/Integer.php b/library/HTMLPurifier/AttrDef/Integer.php
index d59738d2a..400e707d2 100644
--- a/library/HTMLPurifier/AttrDef/Integer.php
+++ b/library/HTMLPurifier/AttrDef/Integer.php
@@ -11,17 +11,20 @@ class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef
{
/**
- * Bool indicating whether or not negative values are allowed
+ * Whether or not negative values are allowed.
+ * @type bool
*/
protected $negative = true;
/**
- * Bool indicating whether or not zero is allowed
+ * Whether or not zero is allowed.
+ * @type bool
*/
protected $zero = true;
/**
- * Bool indicating whether or not positive values are allowed
+ * Whether or not positive values are allowed.
+ * @type bool
*/
protected $positive = true;
@@ -30,44 +33,59 @@ class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef
* @param $zero Bool indicating whether or not zero is allowed
* @param $positive Bool indicating whether or not positive values are allowed
*/
- public function __construct(
- $negative = true, $zero = true, $positive = true
- ) {
+ public function __construct($negative = true, $zero = true, $positive = true)
+ {
$this->negative = $negative;
- $this->zero = $zero;
+ $this->zero = $zero;
$this->positive = $positive;
}
- public function validate($integer, $config, $context) {
-
+ /**
+ * @param string $integer
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($integer, $config, $context)
+ {
$integer = $this->parseCDATA($integer);
- if ($integer === '') return false;
+ if ($integer === '') {
+ return false;
+ }
// we could possibly simply typecast it to integer, but there are
// certain fringe cases that must not return an integer.
// clip leading sign
- if ( $this->negative && $integer[0] === '-' ) {
+ if ($this->negative && $integer[0] === '-') {
$digits = substr($integer, 1);
- if ($digits === '0') $integer = '0'; // rm minus sign for zero
- } elseif( $this->positive && $integer[0] === '+' ) {
+ if ($digits === '0') {
+ $integer = '0';
+ } // rm minus sign for zero
+ } elseif ($this->positive && $integer[0] === '+') {
$digits = $integer = substr($integer, 1); // rm unnecessary plus
} else {
$digits = $integer;
}
// test if it's numeric
- if (!ctype_digit($digits)) return false;
+ if (!ctype_digit($digits)) {
+ return false;
+ }
// perform scope tests
- if (!$this->zero && $integer == 0) return false;
- if (!$this->positive && $integer > 0) return false;
- if (!$this->negative && $integer < 0) return false;
+ if (!$this->zero && $integer == 0) {
+ return false;
+ }
+ if (!$this->positive && $integer > 0) {
+ return false;
+ }
+ if (!$this->negative && $integer < 0) {
+ return false;
+ }
return $integer;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/Lang.php b/library/HTMLPurifier/AttrDef/Lang.php
index 10e6da56d..2a55cea64 100644
--- a/library/HTMLPurifier/AttrDef/Lang.php
+++ b/library/HTMLPurifier/AttrDef/Lang.php
@@ -7,15 +7,25 @@
class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
{
- public function validate($string, $config, $context) {
-
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$string = trim($string);
- if (!$string) return false;
+ if (!$string) {
+ return false;
+ }
$subtags = explode('-', $string);
$num_subtags = count($subtags);
- if ($num_subtags == 0) return false; // sanity check
+ if ($num_subtags == 0) { // sanity check
+ return false;
+ }
// process primary subtag : $subtags[0]
$length = strlen($subtags[0]);
@@ -23,15 +33,15 @@ class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
case 0:
return false;
case 1:
- if (! ($subtags[0] == 'x' || $subtags[0] == 'i') ) {
+ if (!($subtags[0] == 'x' || $subtags[0] == 'i')) {
return false;
}
break;
case 2:
case 3:
- if (! ctype_alpha($subtags[0]) ) {
+ if (!ctype_alpha($subtags[0])) {
return false;
- } elseif (! ctype_lower($subtags[0]) ) {
+ } elseif (!ctype_lower($subtags[0])) {
$subtags[0] = strtolower($subtags[0]);
}
break;
@@ -40,17 +50,23 @@ class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
}
$new_string = $subtags[0];
- if ($num_subtags == 1) return $new_string;
+ if ($num_subtags == 1) {
+ return $new_string;
+ }
// process second subtag : $subtags[1]
$length = strlen($subtags[1]);
if ($length == 0 || ($length == 1 && $subtags[1] != 'x') || $length > 8 || !ctype_alnum($subtags[1])) {
return $new_string;
}
- if (!ctype_lower($subtags[1])) $subtags[1] = strtolower($subtags[1]);
+ if (!ctype_lower($subtags[1])) {
+ $subtags[1] = strtolower($subtags[1]);
+ }
$new_string .= '-' . $subtags[1];
- if ($num_subtags == 2) return $new_string;
+ if ($num_subtags == 2) {
+ return $new_string;
+ }
// process all other subtags, index 2 and up
for ($i = 2; $i < $num_subtags; $i++) {
@@ -63,11 +79,8 @@ class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
}
$new_string .= '-' . $subtags[$i];
}
-
return $new_string;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/Switch.php b/library/HTMLPurifier/AttrDef/Switch.php
index c9e3ed193..c7eb3199a 100644
--- a/library/HTMLPurifier/AttrDef/Switch.php
+++ b/library/HTMLPurifier/AttrDef/Switch.php
@@ -6,21 +6,41 @@
class HTMLPurifier_AttrDef_Switch
{
+ /**
+ * @type string
+ */
protected $tag;
- protected $withTag, $withoutTag;
+
+ /**
+ * @type HTMLPurifier_AttrDef
+ */
+ protected $withTag;
+
+ /**
+ * @type HTMLPurifier_AttrDef
+ */
+ protected $withoutTag;
/**
* @param string $tag Tag name to switch upon
* @param HTMLPurifier_AttrDef $with_tag Call if token matches tag
* @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token
*/
- public function __construct($tag, $with_tag, $without_tag) {
+ public function __construct($tag, $with_tag, $without_tag)
+ {
$this->tag = $tag;
$this->withTag = $with_tag;
$this->withoutTag = $without_tag;
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$token = $context->get('CurrentToken', true);
if (!$token || $token->name !== $this->tag) {
return $this->withoutTag->validate($string, $config, $context);
@@ -28,7 +48,6 @@ class HTMLPurifier_AttrDef_Switch
return $this->withTag->validate($string, $config, $context);
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/Text.php b/library/HTMLPurifier/AttrDef/Text.php
index c6216cc53..4553a4ea9 100644
--- a/library/HTMLPurifier/AttrDef/Text.php
+++ b/library/HTMLPurifier/AttrDef/Text.php
@@ -6,10 +6,16 @@
class HTMLPurifier_AttrDef_Text extends HTMLPurifier_AttrDef
{
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
return $this->parseCDATA($string);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/URI.php b/library/HTMLPurifier/AttrDef/URI.php
index 01a6d83e9..c1cd89772 100644
--- a/library/HTMLPurifier/AttrDef/URI.php
+++ b/library/HTMLPurifier/AttrDef/URI.php
@@ -7,31 +7,54 @@
class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
{
+ /**
+ * @type HTMLPurifier_URIParser
+ */
protected $parser;
+
+ /**
+ * @type bool
+ */
protected $embedsResource;
/**
- * @param $embeds_resource_resource Does the URI here result in an extra HTTP request?
+ * @param bool $embeds_resource Does the URI here result in an extra HTTP request?
*/
- public function __construct($embeds_resource = false) {
+ public function __construct($embeds_resource = false)
+ {
$this->parser = new HTMLPurifier_URIParser();
- $this->embedsResource = (bool) $embeds_resource;
+ $this->embedsResource = (bool)$embeds_resource;
}
- public function make($string) {
- $embeds = (bool) $string;
+ /**
+ * @param string $string
+ * @return HTMLPurifier_AttrDef_URI
+ */
+ public function make($string)
+ {
+ $embeds = ($string === 'embedded');
return new HTMLPurifier_AttrDef_URI($embeds);
}
- public function validate($uri, $config, $context) {
-
- if ($config->get('URI.Disable')) return false;
+ /**
+ * @param string $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($uri, $config, $context)
+ {
+ if ($config->get('URI.Disable')) {
+ return false;
+ }
$uri = $this->parseCDATA($uri);
// parse the URI
$uri = $this->parser->parse($uri);
- if ($uri === false) return false;
+ if ($uri === false) {
+ return false;
+ }
// add embedded flag to context for validators
$context->register('EmbeddedURI', $this->embedsResource);
@@ -41,23 +64,35 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
// generic validation
$result = $uri->validate($config, $context);
- if (!$result) break;
+ if (!$result) {
+ break;
+ }
// chained filtering
$uri_def = $config->getDefinition('URI');
$result = $uri_def->filter($uri, $config, $context);
- if (!$result) break;
+ if (!$result) {
+ break;
+ }
// scheme-specific validation
$scheme_obj = $uri->getSchemeObj($config, $context);
- if (!$scheme_obj) break;
- if ($this->embedsResource && !$scheme_obj->browsable) break;
+ if (!$scheme_obj) {
+ break;
+ }
+ if ($this->embedsResource && !$scheme_obj->browsable) {
+ break;
+ }
$result = $scheme_obj->validate($uri, $config, $context);
- if (!$result) break;
+ if (!$result) {
+ break;
+ }
// Post chained filtering
$result = $uri_def->postFilter($uri, $config, $context);
- if (!$result) break;
+ if (!$result) {
+ break;
+ }
// survived gauntlet
$ok = true;
@@ -65,13 +100,12 @@ class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
} while (false);
$context->destroy('EmbeddedURI');
- if (!$ok) return false;
-
+ if (!$ok) {
+ return false;
+ }
// back to string
return $uri->toString();
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/URI/Email.php b/library/HTMLPurifier/AttrDef/URI/Email.php
index bfee9d166..daf32b764 100644
--- a/library/HTMLPurifier/AttrDef/URI/Email.php
+++ b/library/HTMLPurifier/AttrDef/URI/Email.php
@@ -5,8 +5,11 @@ abstract class HTMLPurifier_AttrDef_URI_Email extends HTMLPurifier_AttrDef
/**
* Unpacks a mailbox into its display-name and address
+ * @param string $string
+ * @return mixed
*/
- function unpack($string) {
+ public function unpack($string)
+ {
// needs to be implemented
}
diff --git a/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php b/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php
index 94c715ab4..52c0d5968 100644
--- a/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php
+++ b/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php
@@ -7,15 +7,23 @@
class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_URI_Email
{
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
// no support for named mailboxes i.e. "Bob <bob@example.com>"
// that needs more percent encoding to be done
- if ($string == '') return false;
+ if ($string == '') {
+ return false;
+ }
$string = trim($string);
$result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string);
return $result ? $string : false;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/URI/Host.php b/library/HTMLPurifier/AttrDef/URI/Host.php
index 2156c10c6..e7df800b1 100644
--- a/library/HTMLPurifier/AttrDef/URI/Host.php
+++ b/library/HTMLPurifier/AttrDef/URI/Host.php
@@ -7,56 +7,122 @@ class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
{
/**
- * Instance of HTMLPurifier_AttrDef_URI_IPv4 sub-validator
+ * IPv4 sub-validator.
+ * @type HTMLPurifier_AttrDef_URI_IPv4
*/
protected $ipv4;
/**
- * Instance of HTMLPurifier_AttrDef_URI_IPv6 sub-validator
+ * IPv6 sub-validator.
+ * @type HTMLPurifier_AttrDef_URI_IPv6
*/
protected $ipv6;
- public function __construct() {
+ public function __construct()
+ {
$this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4();
$this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6();
}
- public function validate($string, $config, $context) {
+ /**
+ * @param string $string
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($string, $config, $context)
+ {
$length = strlen($string);
- if ($string === '') return '';
- if ($length > 1 && $string[0] === '[' && $string[$length-1] === ']') {
+ // empty hostname is OK; it's usually semantically equivalent:
+ // the default host as defined by a URI scheme is used:
+ //
+ // If the URI scheme defines a default for host, then that
+ // default applies when the host subcomponent is undefined
+ // or when the registered name is empty (zero length).
+ if ($string === '') {
+ return '';
+ }
+ if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') {
//IPv6
$ip = substr($string, 1, $length - 2);
$valid = $this->ipv6->validate($ip, $config, $context);
- if ($valid === false) return false;
- return '['. $valid . ']';
+ if ($valid === false) {
+ return false;
+ }
+ return '[' . $valid . ']';
}
// need to do checks on unusual encodings too
$ipv4 = $this->ipv4->validate($string, $config, $context);
- if ($ipv4 !== false) return $ipv4;
+ if ($ipv4 !== false) {
+ return $ipv4;
+ }
// A regular domain name.
- // This breaks I18N domain names, but we don't have proper IRI support,
- // so force users to insert Punycode. If there's complaining we'll
- // try to fix things into an international friendly form.
+ // This doesn't match I18N domain names, but we don't have proper IRI support,
+ // so force users to insert Punycode.
+
+ // There is not a good sense in which underscores should be
+ // allowed, since it's technically not! (And if you go as
+ // far to allow everything as specified by the DNS spec...
+ // well, that's literally everything, modulo some space limits
+ // for the components and the overall name (which, by the way,
+ // we are NOT checking!). So we (arbitrarily) decide this:
+ // let's allow underscores wherever we would have allowed
+ // hyphens, if they are enabled. This is a pretty good match
+ // for browser behavior, for example, a large number of browsers
+ // cannot handle foo_.example.com, but foo_bar.example.com is
+ // fairly well supported.
+ $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : '';
// The productions describing this are:
$a = '[a-z]'; // alpha
$an = '[a-z0-9]'; // alphanum
- $and = '[a-z0-9-]'; // alphanum | "-"
+ $and = "[a-z0-9-$underscore]"; // alphanum | "-"
// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
- $domainlabel = "$an($and*$an)?";
+ $domainlabel = "$an($and*$an)?";
// toplabel = alpha | alpha *( alphanum | "-" ) alphanum
- $toplabel = "$a($and*$an)?";
+ $toplabel = "$a($and*$an)?";
// hostname = *( domainlabel "." ) toplabel [ "." ]
- $match = preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string);
- if (!$match) return false;
+ if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
+ return $string;
+ }
- return $string;
- }
+ // If we have Net_IDNA2 support, we can support IRIs by
+ // punycoding them. (This is the most portable thing to do,
+ // since otherwise we have to assume browsers support
+ if ($config->get('Core.EnableIDNA')) {
+ $idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true));
+ // we need to encode each period separately
+ $parts = explode('.', $string);
+ try {
+ $new_parts = array();
+ foreach ($parts as $part) {
+ $encodable = false;
+ for ($i = 0, $c = strlen($part); $i < $c; $i++) {
+ if (ord($part[$i]) > 0x7a) {
+ $encodable = true;
+ break;
+ }
+ }
+ if (!$encodable) {
+ $new_parts[] = $part;
+ } else {
+ $new_parts[] = $idna->encode($part);
+ }
+ }
+ $string = implode('.', $new_parts);
+ if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
+ return $string;
+ }
+ } catch (Exception $e) {
+ // XXX error reporting
+ }
+ }
+ return false;
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/URI/IPv4.php b/library/HTMLPurifier/AttrDef/URI/IPv4.php
index ec4cf591b..30ac16c9e 100644
--- a/library/HTMLPurifier/AttrDef/URI/IPv4.php
+++ b/library/HTMLPurifier/AttrDef/URI/IPv4.php
@@ -8,32 +8,38 @@ class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef
{
/**
- * IPv4 regex, protected so that IPv6 can reuse it
+ * IPv4 regex, protected so that IPv6 can reuse it.
+ * @type string
*/
protected $ip4;
- public function validate($aIP, $config, $context) {
-
- if (!$this->ip4) $this->_loadRegex();
-
- if (preg_match('#^' . $this->ip4 . '$#s', $aIP))
- {
- return $aIP;
+ /**
+ * @param string $aIP
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($aIP, $config, $context)
+ {
+ if (!$this->ip4) {
+ $this->_loadRegex();
}
+ if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) {
+ return $aIP;
+ }
return false;
-
}
/**
* Lazy load function to prevent regex from being stuffed in
* cache.
*/
- protected function _loadRegex() {
+ protected function _loadRegex()
+ {
$oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255
$this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})";
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrDef/URI/IPv6.php b/library/HTMLPurifier/AttrDef/URI/IPv6.php
index 9454e9be5..f243793ee 100644
--- a/library/HTMLPurifier/AttrDef/URI/IPv6.php
+++ b/library/HTMLPurifier/AttrDef/URI/IPv6.php
@@ -9,91 +9,81 @@
class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4
{
- public function validate($aIP, $config, $context) {
-
- if (!$this->ip4) $this->_loadRegex();
+ /**
+ * @param string $aIP
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string
+ */
+ public function validate($aIP, $config, $context)
+ {
+ if (!$this->ip4) {
+ $this->_loadRegex();
+ }
$original = $aIP;
$hex = '[0-9a-fA-F]';
$blk = '(?:' . $hex . '{1,4})';
- $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128
+ $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128
// prefix check
- if (strpos($aIP, '/') !== false)
- {
- if (preg_match('#' . $pre . '$#s', $aIP, $find))
- {
- $aIP = substr($aIP, 0, 0-strlen($find[0]));
- unset($find);
- }
- else
- {
- return false;
- }
+ if (strpos($aIP, '/') !== false) {
+ if (preg_match('#' . $pre . '$#s', $aIP, $find)) {
+ $aIP = substr($aIP, 0, 0 - strlen($find[0]));
+ unset($find);
+ } else {
+ return false;
+ }
}
// IPv4-compatiblity check
- if (preg_match('#(?<=:'.')' . $this->ip4 . '$#s', $aIP, $find))
- {
- $aIP = substr($aIP, 0, 0-strlen($find[0]));
- $ip = explode('.', $find[0]);
- $ip = array_map('dechex', $ip);
- $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3];
- unset($find, $ip);
+ if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) {
+ $aIP = substr($aIP, 0, 0 - strlen($find[0]));
+ $ip = explode('.', $find[0]);
+ $ip = array_map('dechex', $ip);
+ $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3];
+ unset($find, $ip);
}
// compression check
$aIP = explode('::', $aIP);
$c = count($aIP);
- if ($c > 2)
- {
+ if ($c > 2) {
+ return false;
+ } elseif ($c == 2) {
+ list($first, $second) = $aIP;
+ $first = explode(':', $first);
+ $second = explode(':', $second);
+
+ if (count($first) + count($second) > 8) {
return false;
- }
- elseif ($c == 2)
- {
- list($first, $second) = $aIP;
- $first = explode(':', $first);
- $second = explode(':', $second);
-
- if (count($first) + count($second) > 8)
- {
- return false;
- }
+ }
- while(count($first) < 8)
- {
- array_push($first, '0');
- }
+ while (count($first) < 8) {
+ array_push($first, '0');
+ }
- array_splice($first, 8 - count($second), 8, $second);
- $aIP = $first;
- unset($first,$second);
- }
- else
- {
- $aIP = explode(':', $aIP[0]);
+ array_splice($first, 8 - count($second), 8, $second);
+ $aIP = $first;
+ unset($first, $second);
+ } else {
+ $aIP = explode(':', $aIP[0]);
}
$c = count($aIP);
- if ($c != 8)
- {
- return false;
+ if ($c != 8) {
+ return false;
}
// All the pieces should be 16-bit hex strings. Are they?
- foreach ($aIP as $piece)
- {
- if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece)))
- {
- return false;
- }
+ foreach ($aIP as $piece) {
+ if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) {
+ return false;
+ }
}
-
return $original;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform.php b/library/HTMLPurifier/AttrTransform.php
index e61d3e01b..b428331f1 100644
--- a/library/HTMLPurifier/AttrTransform.php
+++ b/library/HTMLPurifier/AttrTransform.php
@@ -20,37 +20,41 @@ abstract class HTMLPurifier_AttrTransform
/**
* Abstract: makes changes to the attributes dependent on multiple values.
*
- * @param $attr Assoc array of attributes, usually from
+ * @param array $attr Assoc array of attributes, usually from
* HTMLPurifier_Token_Tag::$attr
- * @param $config Mandatory HTMLPurifier_Config object.
- * @param $context Mandatory HTMLPurifier_Context object
- * @returns Processed attribute array.
+ * @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object.
+ * @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object
+ * @return array Processed attribute array.
*/
abstract public function transform($attr, $config, $context);
/**
* Prepends CSS properties to the style attribute, creating the
* attribute if it doesn't exist.
- * @param $attr Attribute array to process (passed by reference)
- * @param $css CSS to prepend
+ * @param array &$attr Attribute array to process (passed by reference)
+ * @param string $css CSS to prepend
*/
- public function prependCSS(&$attr, $css) {
+ public function prependCSS(&$attr, $css)
+ {
$attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = $css . $attr['style'];
}
/**
* Retrieves and removes an attribute
- * @param $attr Attribute array to process (passed by reference)
- * @param $key Key of attribute to confiscate
+ * @param array &$attr Attribute array to process (passed by reference)
+ * @param mixed $key Key of attribute to confiscate
+ * @return mixed
*/
- public function confiscateAttr(&$attr, $key) {
- if (!isset($attr[$key])) return null;
+ public function confiscateAttr(&$attr, $key)
+ {
+ if (!isset($attr[$key])) {
+ return null;
+ }
$value = $attr[$key];
unset($attr[$key]);
return $value;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/Background.php b/library/HTMLPurifier/AttrTransform/Background.php
index 0e1ff24a3..2f72869a5 100644
--- a/library/HTMLPurifier/AttrTransform/Background.php
+++ b/library/HTMLPurifier/AttrTransform/Background.php
@@ -3,21 +3,26 @@
/**
* Pre-transform that changes proprietary background attribute to CSS.
*/
-class HTMLPurifier_AttrTransform_Background extends HTMLPurifier_AttrTransform {
-
- public function transform($attr, $config, $context) {
-
- if (!isset($attr['background'])) return $attr;
+class HTMLPurifier_AttrTransform_Background extends HTMLPurifier_AttrTransform
+{
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr['background'])) {
+ return $attr;
+ }
$background = $this->confiscateAttr($attr, 'background');
// some validation should happen here
$this->prependCSS($attr, "background-image:url($background);");
-
return $attr;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/BdoDir.php b/library/HTMLPurifier/AttrTransform/BdoDir.php
index 4d1a05665..d66c04a5b 100644
--- a/library/HTMLPurifier/AttrTransform/BdoDir.php
+++ b/library/HTMLPurifier/AttrTransform/BdoDir.php
@@ -8,12 +8,20 @@
class HTMLPurifier_AttrTransform_BdoDir extends HTMLPurifier_AttrTransform
{
- public function transform($attr, $config, $context) {
- if (isset($attr['dir'])) return $attr;
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (isset($attr['dir'])) {
+ return $attr;
+ }
$attr['dir'] = $config->get('Attr.DefaultTextDir');
return $attr;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/BgColor.php b/library/HTMLPurifier/AttrTransform/BgColor.php
index ad3916bb9..0f51fd2ce 100644
--- a/library/HTMLPurifier/AttrTransform/BgColor.php
+++ b/library/HTMLPurifier/AttrTransform/BgColor.php
@@ -3,21 +3,26 @@
/**
* Pre-transform that changes deprecated bgcolor attribute to CSS.
*/
-class HTMLPurifier_AttrTransform_BgColor extends HTMLPurifier_AttrTransform {
-
- public function transform($attr, $config, $context) {
-
- if (!isset($attr['bgcolor'])) return $attr;
+class HTMLPurifier_AttrTransform_BgColor extends HTMLPurifier_AttrTransform
+{
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr['bgcolor'])) {
+ return $attr;
+ }
$bgcolor = $this->confiscateAttr($attr, 'bgcolor');
// some validation should happen here
$this->prependCSS($attr, "background-color:$bgcolor;");
-
return $attr;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/BoolToCSS.php b/library/HTMLPurifier/AttrTransform/BoolToCSS.php
index 51159b671..f25cd0195 100644
--- a/library/HTMLPurifier/AttrTransform/BoolToCSS.php
+++ b/library/HTMLPurifier/AttrTransform/BoolToCSS.php
@@ -3,34 +3,45 @@
/**
* Pre-transform that changes converts a boolean attribute to fixed CSS
*/
-class HTMLPurifier_AttrTransform_BoolToCSS extends HTMLPurifier_AttrTransform {
-
+class HTMLPurifier_AttrTransform_BoolToCSS extends HTMLPurifier_AttrTransform
+{
/**
- * Name of boolean attribute that is trigger
+ * Name of boolean attribute that is trigger.
+ * @type string
*/
protected $attr;
/**
- * CSS declarations to add to style, needs trailing semicolon
+ * CSS declarations to add to style, needs trailing semicolon.
+ * @type string
*/
protected $css;
/**
- * @param $attr string attribute name to convert from
- * @param $css string CSS declarations to add to style (needs semicolon)
+ * @param string $attr attribute name to convert from
+ * @param string $css CSS declarations to add to style (needs semicolon)
*/
- public function __construct($attr, $css) {
+ public function __construct($attr, $css)
+ {
$this->attr = $attr;
- $this->css = $css;
+ $this->css = $css;
}
- public function transform($attr, $config, $context) {
- if (!isset($attr[$this->attr])) return $attr;
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr[$this->attr])) {
+ return $attr;
+ }
unset($attr[$this->attr]);
$this->prependCSS($attr, $this->css);
return $attr;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/Border.php b/library/HTMLPurifier/AttrTransform/Border.php
index 476b0b079..057dc017f 100644
--- a/library/HTMLPurifier/AttrTransform/Border.php
+++ b/library/HTMLPurifier/AttrTransform/Border.php
@@ -3,16 +3,24 @@
/**
* Pre-transform that changes deprecated border attribute to CSS.
*/
-class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform {
-
- public function transform($attr, $config, $context) {
- if (!isset($attr['border'])) return $attr;
+class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform
+{
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr['border'])) {
+ return $attr;
+ }
$border_width = $this->confiscateAttr($attr, 'border');
// some validation should happen here
$this->prependCSS($attr, "border:{$border_width}px solid;");
return $attr;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/EnumToCSS.php b/library/HTMLPurifier/AttrTransform/EnumToCSS.php
index 2a5b4514a..7ccd0e3fb 100644
--- a/library/HTMLPurifier/AttrTransform/EnumToCSS.php
+++ b/library/HTMLPurifier/AttrTransform/EnumToCSS.php
@@ -4,55 +4,65 @@
* Generic pre-transform that converts an attribute with a fixed number of
* values (enumerated) to CSS.
*/
-class HTMLPurifier_AttrTransform_EnumToCSS extends HTMLPurifier_AttrTransform {
-
+class HTMLPurifier_AttrTransform_EnumToCSS extends HTMLPurifier_AttrTransform
+{
/**
- * Name of attribute to transform from
+ * Name of attribute to transform from.
+ * @type string
*/
protected $attr;
/**
- * Lookup array of attribute values to CSS
+ * Lookup array of attribute values to CSS.
+ * @type array
*/
protected $enumToCSS = array();
/**
- * Case sensitivity of the matching
+ * Case sensitivity of the matching.
+ * @type bool
* @warning Currently can only be guaranteed to work with ASCII
* values.
*/
protected $caseSensitive = false;
/**
- * @param $attr String attribute name to transform from
- * @param $enumToCSS Lookup array of attribute values to CSS
- * @param $case_sensitive Boolean case sensitivity indicator, default false
+ * @param string $attr Attribute name to transform from
+ * @param array $enum_to_css Lookup array of attribute values to CSS
+ * @param bool $case_sensitive Case sensitivity indicator, default false
*/
- public function __construct($attr, $enum_to_css, $case_sensitive = false) {
+ public function __construct($attr, $enum_to_css, $case_sensitive = false)
+ {
$this->attr = $attr;
$this->enumToCSS = $enum_to_css;
- $this->caseSensitive = (bool) $case_sensitive;
+ $this->caseSensitive = (bool)$case_sensitive;
}
- public function transform($attr, $config, $context) {
-
- if (!isset($attr[$this->attr])) return $attr;
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr[$this->attr])) {
+ return $attr;
+ }
$value = trim($attr[$this->attr]);
unset($attr[$this->attr]);
- if (!$this->caseSensitive) $value = strtolower($value);
+ if (!$this->caseSensitive) {
+ $value = strtolower($value);
+ }
if (!isset($this->enumToCSS[$value])) {
return $attr;
}
-
$this->prependCSS($attr, $this->enumToCSS[$value]);
-
return $attr;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/ImgRequired.php b/library/HTMLPurifier/AttrTransform/ImgRequired.php
index 7f0e4b7a5..7df6cb3e1 100644
--- a/library/HTMLPurifier/AttrTransform/ImgRequired.php
+++ b/library/HTMLPurifier/AttrTransform/ImgRequired.php
@@ -11,11 +11,19 @@
class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
{
- public function transform($attr, $config, $context) {
-
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
$src = true;
if (!isset($attr['src'])) {
- if ($config->get('Core.RemoveInvalidImg')) return $attr;
+ if ($config->get('Core.RemoveInvalidImg')) {
+ return $attr;
+ }
$attr['src'] = $config->get('Attr.DefaultInvalidImage');
$src = false;
}
@@ -25,7 +33,7 @@ class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
$alt = $config->get('Attr.DefaultImageAlt');
if ($alt === null) {
// truncate if the alt is too long
- $attr['alt'] = substr(basename($attr['src']),0,40);
+ $attr['alt'] = substr(basename($attr['src']), 0, 40);
} else {
$attr['alt'] = $alt;
}
@@ -33,11 +41,8 @@ class HTMLPurifier_AttrTransform_ImgRequired extends HTMLPurifier_AttrTransform
$attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt');
}
}
-
return $attr;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/ImgSpace.php b/library/HTMLPurifier/AttrTransform/ImgSpace.php
index fd84c10c3..350b3358f 100644
--- a/library/HTMLPurifier/AttrTransform/ImgSpace.php
+++ b/library/HTMLPurifier/AttrTransform/ImgSpace.php
@@ -3,42 +3,59 @@
/**
* Pre-transform that changes deprecated hspace and vspace attributes to CSS
*/
-class HTMLPurifier_AttrTransform_ImgSpace extends HTMLPurifier_AttrTransform {
-
+class HTMLPurifier_AttrTransform_ImgSpace extends HTMLPurifier_AttrTransform
+{
+ /**
+ * @type string
+ */
protected $attr;
+
+ /**
+ * @type array
+ */
protected $css = array(
'hspace' => array('left', 'right'),
'vspace' => array('top', 'bottom')
);
- public function __construct($attr) {
+ /**
+ * @param string $attr
+ */
+ public function __construct($attr)
+ {
$this->attr = $attr;
if (!isset($this->css[$attr])) {
trigger_error(htmlspecialchars($attr) . ' is not valid space attribute');
}
}
- public function transform($attr, $config, $context) {
-
- if (!isset($attr[$this->attr])) return $attr;
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr[$this->attr])) {
+ return $attr;
+ }
$width = $this->confiscateAttr($attr, $this->attr);
// some validation could happen here
- if (!isset($this->css[$this->attr])) return $attr;
+ if (!isset($this->css[$this->attr])) {
+ return $attr;
+ }
$style = '';
foreach ($this->css[$this->attr] as $suffix) {
$property = "margin-$suffix";
$style .= "$property:{$width}px;";
}
-
$this->prependCSS($attr, $style);
-
return $attr;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/Input.php b/library/HTMLPurifier/AttrTransform/Input.php
index 16829552d..3ab47ed8c 100644
--- a/library/HTMLPurifier/AttrTransform/Input.php
+++ b/library/HTMLPurifier/AttrTransform/Input.php
@@ -4,17 +4,31 @@
* Performs miscellaneous cross attribute validation and filtering for
* input elements. This is meant to be a post-transform.
*/
-class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform {
-
+class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform
+{
+ /**
+ * @type HTMLPurifier_AttrDef_HTML_Pixels
+ */
protected $pixels;
- public function __construct() {
+ public function __construct()
+ {
$this->pixels = new HTMLPurifier_AttrDef_HTML_Pixels();
}
- public function transform($attr, $config, $context) {
- if (!isset($attr['type'])) $t = 'text';
- else $t = strtolower($attr['type']);
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr['type'])) {
+ $t = 'text';
+ } else {
+ $t = strtolower($attr['type']);
+ }
if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') {
unset($attr['checked']);
}
@@ -23,8 +37,11 @@ class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform {
}
if (isset($attr['size']) && $t !== 'text' && $t !== 'password') {
$result = $this->pixels->validate($attr['size'], $config, $context);
- if ($result === false) unset($attr['size']);
- else $attr['size'] = $result;
+ if ($result === false) {
+ unset($attr['size']);
+ } else {
+ $attr['size'] = $result;
+ }
}
if (isset($attr['src']) && $t !== 'image') {
unset($attr['src']);
@@ -34,7 +51,6 @@ class HTMLPurifier_AttrTransform_Input extends HTMLPurifier_AttrTransform {
}
return $attr;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/Lang.php b/library/HTMLPurifier/AttrTransform/Lang.php
index 5869e7f82..5b0aff0e4 100644
--- a/library/HTMLPurifier/AttrTransform/Lang.php
+++ b/library/HTMLPurifier/AttrTransform/Lang.php
@@ -8,9 +8,15 @@
class HTMLPurifier_AttrTransform_Lang extends HTMLPurifier_AttrTransform
{
- public function transform($attr, $config, $context) {
-
- $lang = isset($attr['lang']) ? $attr['lang'] : false;
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ $lang = isset($attr['lang']) ? $attr['lang'] : false;
$xml_lang = isset($attr['xml:lang']) ? $attr['xml:lang'] : false;
if ($lang !== false && $xml_lang === false) {
@@ -18,11 +24,8 @@ class HTMLPurifier_AttrTransform_Lang extends HTMLPurifier_AttrTransform
} elseif ($xml_lang !== false) {
$attr['lang'] = $xml_lang;
}
-
return $attr;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/Length.php b/library/HTMLPurifier/AttrTransform/Length.php
index ea2f30473..853f33549 100644
--- a/library/HTMLPurifier/AttrTransform/Length.php
+++ b/library/HTMLPurifier/AttrTransform/Length.php
@@ -6,22 +6,40 @@
class HTMLPurifier_AttrTransform_Length extends HTMLPurifier_AttrTransform
{
+ /**
+ * @type string
+ */
protected $name;
+
+ /**
+ * @type string
+ */
protected $cssName;
- public function __construct($name, $css_name = null) {
+ public function __construct($name, $css_name = null)
+ {
$this->name = $name;
$this->cssName = $css_name ? $css_name : $name;
}
- public function transform($attr, $config, $context) {
- if (!isset($attr[$this->name])) return $attr;
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr[$this->name])) {
+ return $attr;
+ }
$length = $this->confiscateAttr($attr, $this->name);
- if(ctype_digit($length)) $length .= 'px';
+ if (ctype_digit($length)) {
+ $length .= 'px';
+ }
$this->prependCSS($attr, $this->cssName . ":$length;");
return $attr;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/Name.php b/library/HTMLPurifier/AttrTransform/Name.php
index 15315bc73..63cce6837 100644
--- a/library/HTMLPurifier/AttrTransform/Name.php
+++ b/library/HTMLPurifier/AttrTransform/Name.php
@@ -6,16 +6,28 @@
class HTMLPurifier_AttrTransform_Name extends HTMLPurifier_AttrTransform
{
- public function transform($attr, $config, $context) {
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
// Abort early if we're using relaxed definition of name
- if ($config->get('HTML.Attr.Name.UseCDATA')) return $attr;
- if (!isset($attr['name'])) return $attr;
+ if ($config->get('HTML.Attr.Name.UseCDATA')) {
+ return $attr;
+ }
+ if (!isset($attr['name'])) {
+ return $attr;
+ }
$id = $this->confiscateAttr($attr, 'name');
- if ( isset($attr['id'])) return $attr;
+ if (isset($attr['id'])) {
+ return $attr;
+ }
$attr['id'] = $id;
return $attr;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/NameSync.php b/library/HTMLPurifier/AttrTransform/NameSync.php
index a95638c14..36079b786 100644
--- a/library/HTMLPurifier/AttrTransform/NameSync.php
+++ b/library/HTMLPurifier/AttrTransform/NameSync.php
@@ -8,20 +8,34 @@
class HTMLPurifier_AttrTransform_NameSync extends HTMLPurifier_AttrTransform
{
- public function __construct() {
+ public function __construct()
+ {
$this->idDef = new HTMLPurifier_AttrDef_HTML_ID();
}
- public function transform($attr, $config, $context) {
- if (!isset($attr['name'])) return $attr;
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr['name'])) {
+ return $attr;
+ }
$name = $attr['name'];
- if (isset($attr['id']) && $attr['id'] === $name) return $attr;
+ if (isset($attr['id']) && $attr['id'] === $name) {
+ return $attr;
+ }
$result = $this->idDef->validate($name, $config, $context);
- if ($result === false) unset($attr['name']);
- else $attr['name'] = $result;
+ if ($result === false) {
+ unset($attr['name']);
+ } else {
+ $attr['name'] = $result;
+ }
return $attr;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/Nofollow.php b/library/HTMLPurifier/AttrTransform/Nofollow.php
new file mode 100644
index 000000000..1057ebee1
--- /dev/null
+++ b/library/HTMLPurifier/AttrTransform/Nofollow.php
@@ -0,0 +1,52 @@
+<?php
+
+// must be called POST validation
+
+/**
+ * Adds rel="nofollow" to all outbound links. This transform is
+ * only attached if Attr.Nofollow is TRUE.
+ */
+class HTMLPurifier_AttrTransform_Nofollow extends HTMLPurifier_AttrTransform
+{
+ /**
+ * @type HTMLPurifier_URIParser
+ */
+ private $parser;
+
+ public function __construct()
+ {
+ $this->parser = new HTMLPurifier_URIParser();
+ }
+
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr['href'])) {
+ return $attr;
+ }
+
+ // XXX Kind of inefficient
+ $url = $this->parser->parse($attr['href']);
+ $scheme = $url->getSchemeObj($config, $context);
+
+ if ($scheme->browsable && !$url->isLocal($config, $context)) {
+ if (isset($attr['rel'])) {
+ $rels = explode(' ', $attr['rel']);
+ if (!in_array('nofollow', $rels)) {
+ $rels[] = 'nofollow';
+ }
+ $attr['rel'] = implode(' ', $rels);
+ } else {
+ $attr['rel'] = 'nofollow';
+ }
+ }
+ return $attr;
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/SafeEmbed.php b/library/HTMLPurifier/AttrTransform/SafeEmbed.php
index 4da449981..231c81a3f 100644
--- a/library/HTMLPurifier/AttrTransform/SafeEmbed.php
+++ b/library/HTMLPurifier/AttrTransform/SafeEmbed.php
@@ -2,9 +2,19 @@
class HTMLPurifier_AttrTransform_SafeEmbed extends HTMLPurifier_AttrTransform
{
+ /**
+ * @type string
+ */
public $name = "SafeEmbed";
- public function transform($attr, $config, $context) {
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
$attr['allowscriptaccess'] = 'never';
$attr['allownetworking'] = 'internal';
$attr['type'] = 'application/x-shockwave-flash';
diff --git a/library/HTMLPurifier/AttrTransform/SafeObject.php b/library/HTMLPurifier/AttrTransform/SafeObject.php
index 1ed74898b..d1f3a4d2e 100644
--- a/library/HTMLPurifier/AttrTransform/SafeObject.php
+++ b/library/HTMLPurifier/AttrTransform/SafeObject.php
@@ -5,10 +5,22 @@
*/
class HTMLPurifier_AttrTransform_SafeObject extends HTMLPurifier_AttrTransform
{
+ /**
+ * @type string
+ */
public $name = "SafeObject";
- function transform($attr, $config, $context) {
- if (!isset($attr['type'])) $attr['type'] = 'application/x-shockwave-flash';
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr['type'])) {
+ $attr['type'] = 'application/x-shockwave-flash';
+ }
return $attr;
}
}
diff --git a/library/HTMLPurifier/AttrTransform/SafeParam.php b/library/HTMLPurifier/AttrTransform/SafeParam.php
index 3f992ec31..1143b4b49 100644
--- a/library/HTMLPurifier/AttrTransform/SafeParam.php
+++ b/library/HTMLPurifier/AttrTransform/SafeParam.php
@@ -14,14 +14,30 @@
*/
class HTMLPurifier_AttrTransform_SafeParam extends HTMLPurifier_AttrTransform
{
+ /**
+ * @type string
+ */
public $name = "SafeParam";
+
+ /**
+ * @type HTMLPurifier_AttrDef_URI
+ */
private $uri;
- public function __construct() {
+ public function __construct()
+ {
$this->uri = new HTMLPurifier_AttrDef_URI(true); // embedded
+ $this->wmode = new HTMLPurifier_AttrDef_Enum(array('window', 'opaque', 'transparent'));
}
- public function transform($attr, $config, $context) {
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
// If we add support for other objects, we'll need to alter the
// transforms.
switch ($attr['name']) {
@@ -33,8 +49,15 @@ class HTMLPurifier_AttrTransform_SafeParam extends HTMLPurifier_AttrTransform
case 'allowNetworking':
$attr['value'] = 'internal';
break;
+ case 'allowFullScreen':
+ if ($config->get('HTML.FlashAllowFullScreen')) {
+ $attr['value'] = ($attr['value'] == 'true') ? 'true' : 'false';
+ } else {
+ $attr['value'] = 'false';
+ }
+ break;
case 'wmode':
- $attr['value'] = 'window';
+ $attr['value'] = $this->wmode->validate($attr['value'], $config, $context);
break;
case 'movie':
case 'src':
diff --git a/library/HTMLPurifier/AttrTransform/ScriptRequired.php b/library/HTMLPurifier/AttrTransform/ScriptRequired.php
index 4499050a2..b7057bbf8 100644
--- a/library/HTMLPurifier/AttrTransform/ScriptRequired.php
+++ b/library/HTMLPurifier/AttrTransform/ScriptRequired.php
@@ -5,7 +5,14 @@
*/
class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform
{
- public function transform($attr, $config, $context) {
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
if (!isset($attr['type'])) {
$attr['type'] = 'text/javascript';
}
diff --git a/library/HTMLPurifier/AttrTransform/TargetBlank.php b/library/HTMLPurifier/AttrTransform/TargetBlank.php
new file mode 100644
index 000000000..dd63ea89c
--- /dev/null
+++ b/library/HTMLPurifier/AttrTransform/TargetBlank.php
@@ -0,0 +1,45 @@
+<?php
+
+// must be called POST validation
+
+/**
+ * Adds target="blank" to all outbound links. This transform is
+ * only attached if Attr.TargetBlank is TRUE. This works regardless
+ * of whether or not Attr.AllowedFrameTargets
+ */
+class HTMLPurifier_AttrTransform_TargetBlank extends HTMLPurifier_AttrTransform
+{
+ /**
+ * @type HTMLPurifier_URIParser
+ */
+ private $parser;
+
+ public function __construct()
+ {
+ $this->parser = new HTMLPurifier_URIParser();
+ }
+
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
+ if (!isset($attr['href'])) {
+ return $attr;
+ }
+
+ // XXX Kind of inefficient
+ $url = $this->parser->parse($attr['href']);
+ $scheme = $url->getSchemeObj($config, $context);
+
+ if ($scheme->browsable && !$url->isBenign($config, $context)) {
+ $attr['target'] = '_blank';
+ }
+ return $attr;
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTransform/Textarea.php b/library/HTMLPurifier/AttrTransform/Textarea.php
index 81ac3488b..6a9f33a0c 100644
--- a/library/HTMLPurifier/AttrTransform/Textarea.php
+++ b/library/HTMLPurifier/AttrTransform/Textarea.php
@@ -5,14 +5,23 @@
*/
class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform
{
-
- public function transform($attr, $config, $context) {
+ /**
+ * @param array $attr
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function transform($attr, $config, $context)
+ {
// Calculated from Firefox
- if (!isset($attr['cols'])) $attr['cols'] = '22';
- if (!isset($attr['rows'])) $attr['rows'] = '3';
+ if (!isset($attr['cols'])) {
+ $attr['cols'] = '22';
+ }
+ if (!isset($attr['rows'])) {
+ $attr['rows'] = '3';
+ }
return $attr;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/AttrTypes.php b/library/HTMLPurifier/AttrTypes.php
index fc2ea4e58..3b70520b6 100644
--- a/library/HTMLPurifier/AttrTypes.php
+++ b/library/HTMLPurifier/AttrTypes.php
@@ -6,7 +6,8 @@
class HTMLPurifier_AttrTypes
{
/**
- * Lookup array of attribute string identifiers to concrete implementations
+ * Lookup array of attribute string identifiers to concrete implementations.
+ * @type HTMLPurifier_AttrDef[]
*/
protected $info = array();
@@ -14,7 +15,15 @@ class HTMLPurifier_AttrTypes
* Constructs the info array, supplying default implementations for attribute
* types.
*/
- public function __construct() {
+ public function __construct()
+ {
+ // XXX This is kind of poor, since we don't actually /clone/
+ // instances; instead, we use the supplied make() attribute. So,
+ // the underlying class must know how to deal with arguments.
+ // With the old implementation of Enum, that ignored its
+ // arguments when handling a make dispatch, the IAlign
+ // definition wouldn't work.
+
// pseudo-types, must be instantiated via shorthand
$this->info['Enum'] = new HTMLPurifier_AttrDef_Enum();
$this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool();
@@ -29,6 +38,9 @@ class HTMLPurifier_AttrTypes
$this->info['URI'] = new HTMLPurifier_AttrDef_URI();
$this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang();
$this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color();
+ $this->info['IAlign'] = self::makeEnum('top,middle,bottom,left,right');
+ $this->info['LAlign'] = self::makeEnum('top,bottom,left,right');
+ $this->info['FrameTarget'] = new HTMLPurifier_AttrDef_HTML_FrameTarget();
// unimplemented aliases
$this->info['ContentType'] = new HTMLPurifier_AttrDef_Text();
@@ -44,32 +56,39 @@ class HTMLPurifier_AttrTypes
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
}
+ private static function makeEnum($in)
+ {
+ return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in)));
+ }
+
/**
* Retrieves a type
- * @param $type String type name
- * @return Object AttrDef for type
+ * @param string $type String type name
+ * @return HTMLPurifier_AttrDef Object AttrDef for type
*/
- public function get($type) {
-
+ public function get($type)
+ {
// determine if there is any extra info tacked on
- if (strpos($type, '#') !== false) list($type, $string) = explode('#', $type, 2);
- else $string = '';
+ if (strpos($type, '#') !== false) {
+ list($type, $string) = explode('#', $type, 2);
+ } else {
+ $string = '';
+ }
if (!isset($this->info[$type])) {
trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR);
return;
}
-
return $this->info[$type]->make($string);
-
}
/**
* Sets a new implementation for a type
- * @param $type String type name
- * @param $impl Object AttrDef for type
+ * @param string $type String type name
+ * @param HTMLPurifier_AttrDef $impl Object AttrDef for type
*/
- public function set($type, $impl) {
+ public function set($type, $impl)
+ {
$this->info[$type] = $impl;
}
}
diff --git a/library/HTMLPurifier/AttrValidator.php b/library/HTMLPurifier/AttrValidator.php
index 829a0f8f2..f97dc93ed 100644
--- a/library/HTMLPurifier/AttrValidator.php
+++ b/library/HTMLPurifier/AttrValidator.php
@@ -9,17 +9,14 @@ class HTMLPurifier_AttrValidator
{
/**
- * Validates the attributes of a token, returning a modified token
+ * Validates the attributes of a token, mutating it as necessary.
* that has valid tokens
- * @param $token Reference to token to validate. We require a reference
- * because the operation this class performs on the token are
- * not atomic, so the context CurrentToken to be updated
- * throughout
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
+ * @param HTMLPurifier_Token $token Token to validate.
+ * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config
+ * @param HTMLPurifier_Context $context Instance of HTMLPurifier_Context
*/
- public function validateToken(&$token, &$config, $context) {
-
+ public function validateToken($token, $config, $context)
+ {
$definition = $config->getHTMLDefinition();
$e =& $context->get('ErrorCollector', true);
@@ -32,12 +29,15 @@ class HTMLPurifier_AttrValidator
// initialize CurrentToken if necessary
$current_token =& $context->get('CurrentToken', true);
- if (!$current_token) $context->register('CurrentToken', $token);
+ if (!$current_token) {
+ $context->register('CurrentToken', $token);
+ }
- if (
- !$token instanceof HTMLPurifier_Token_Start &&
+ if (!$token instanceof HTMLPurifier_Token_Start &&
!$token instanceof HTMLPurifier_Token_Empty
- ) return $token;
+ ) {
+ return;
+ }
// create alias to global definition array, see also $defs
// DEFINITION CALL
@@ -51,7 +51,9 @@ class HTMLPurifier_AttrValidator
foreach ($definition->info_attr_transform_pre as $transform) {
$attr = $transform->transform($o = $attr, $config, $context);
if ($e) {
- if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
+ if ($attr != $o) {
+ $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
+ }
}
}
@@ -60,7 +62,9 @@ class HTMLPurifier_AttrValidator
foreach ($definition->info[$token->name]->attr_transform_pre as $transform) {
$attr = $transform->transform($o = $attr, $config, $context);
if ($e) {
- if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
+ if ($attr != $o) {
+ $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
+ }
}
}
@@ -77,7 +81,7 @@ class HTMLPurifier_AttrValidator
foreach ($attr as $attr_key => $value) {
// call the definition
- if ( isset($defs[$attr_key]) ) {
+ if (isset($defs[$attr_key])) {
// there is a local definition defined
if ($defs[$attr_key] === false) {
// We've explicitly been told not to allow this element.
@@ -89,15 +93,19 @@ class HTMLPurifier_AttrValidator
} else {
// validate according to the element's definition
$result = $defs[$attr_key]->validate(
- $value, $config, $context
- );
+ $value,
+ $config,
+ $context
+ );
}
- } elseif ( isset($d_defs[$attr_key]) ) {
+ } elseif (isset($d_defs[$attr_key])) {
// there is a global definition defined, validate according
// to the global definition
$result = $d_defs[$attr_key]->validate(
- $value, $config, $context
- );
+ $value,
+ $config,
+ $context
+ );
} else {
// system never heard of the attribute? DELETE!
$result = false;
@@ -107,7 +115,9 @@ class HTMLPurifier_AttrValidator
if ($result === false || $result === null) {
// this is a generic error message that should replaced
// with more specific ones when possible
- if ($e) $e->send(E_ERROR, 'AttrValidator: Attribute removed');
+ if ($e) {
+ $e->send(E_ERROR, 'AttrValidator: Attribute removed');
+ }
// remove the attribute
unset($attr[$attr_key]);
@@ -137,7 +147,9 @@ class HTMLPurifier_AttrValidator
foreach ($definition->info_attr_transform_post as $transform) {
$attr = $transform->transform($o = $attr, $config, $context);
if ($e) {
- if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
+ if ($attr != $o) {
+ $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
+ }
}
}
@@ -145,14 +157,18 @@ class HTMLPurifier_AttrValidator
foreach ($definition->info[$token->name]->attr_transform_post as $transform) {
$attr = $transform->transform($o = $attr, $config, $context);
if ($e) {
- if ($attr != $o) $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
+ if ($attr != $o) {
+ $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr);
+ }
}
}
$token->attr = $attr;
// destroy CurrentToken if we made it ourselves
- if (!$current_token) $context->destroy('CurrentToken');
+ if (!$current_token) {
+ $context->destroy('CurrentToken');
+ }
}
diff --git a/library/HTMLPurifier/Bootstrap.php b/library/HTMLPurifier/Bootstrap.php
index 559f61a23..707122bb2 100644
--- a/library/HTMLPurifier/Bootstrap.php
+++ b/library/HTMLPurifier/Bootstrap.php
@@ -32,20 +32,34 @@ class HTMLPurifier_Bootstrap
/**
* Autoload function for HTML Purifier
- * @param $class Class to load
+ * @param string $class Class to load
+ * @return bool
*/
- public static function autoload($class) {
+ public static function autoload($class)
+ {
$file = HTMLPurifier_Bootstrap::getPath($class);
- if (!$file) return false;
- require HTMLPURIFIER_PREFIX . '/' . $file;
+ if (!$file) {
+ return false;
+ }
+ // Technically speaking, it should be ok and more efficient to
+ // just do 'require', but Antonio Parraga reports that with
+ // Zend extensions such as Zend debugger and APC, this invariant
+ // may be broken. Since we have efficient alternatives, pay
+ // the cost here and avoid the bug.
+ require_once HTMLPURIFIER_PREFIX . '/' . $file;
return true;
}
/**
* Returns the path for a specific class.
+ * @param string $class Class path to get
+ * @return string
*/
- public static function getPath($class) {
- if (strncmp('HTMLPurifier', $class, 12) !== 0) return false;
+ public static function getPath($class)
+ {
+ if (strncmp('HTMLPurifier', $class, 12) !== 0) {
+ return false;
+ }
// Custom implementations
if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) {
$code = str_replace('_', '-', substr($class, 22));
@@ -53,46 +67,58 @@ class HTMLPurifier_Bootstrap
} else {
$file = str_replace('_', '/', $class) . '.php';
}
- if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) return false;
+ if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) {
+ return false;
+ }
return $file;
}
/**
* "Pre-registers" our autoloader on the SPL stack.
*/
- public static function registerAutoload() {
+ public static function registerAutoload()
+ {
$autoload = array('HTMLPurifier_Bootstrap', 'autoload');
- if ( ($funcs = spl_autoload_functions()) === false ) {
+ if (($funcs = spl_autoload_functions()) === false) {
spl_autoload_register($autoload);
} elseif (function_exists('spl_autoload_unregister')) {
- $compat = version_compare(PHP_VERSION, '5.1.2', '<=') &&
- version_compare(PHP_VERSION, '5.1.0', '>=');
- foreach ($funcs as $func) {
- if (is_array($func)) {
- // :TRICKY: There are some compatibility issues and some
- // places where we need to error out
- $reflector = new ReflectionMethod($func[0], $func[1]);
- if (!$reflector->isStatic()) {
- throw new Exception('
- HTML Purifier autoloader registrar is not compatible
- with non-static object methods due to PHP Bug #44144;
- Please do not use HTMLPurifier.autoload.php (or any
- file that includes this file); instead, place the code:
- spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\'))
- after your own autoloaders.
- ');
+ if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
+ // prepend flag exists, no need for shenanigans
+ spl_autoload_register($autoload, true, true);
+ } else {
+ $buggy = version_compare(PHP_VERSION, '5.2.11', '<');
+ $compat = version_compare(PHP_VERSION, '5.1.2', '<=') &&
+ version_compare(PHP_VERSION, '5.1.0', '>=');
+ foreach ($funcs as $func) {
+ if ($buggy && is_array($func)) {
+ // :TRICKY: There are some compatibility issues and some
+ // places where we need to error out
+ $reflector = new ReflectionMethod($func[0], $func[1]);
+ if (!$reflector->isStatic()) {
+ throw new Exception(
+ 'HTML Purifier autoloader registrar is not compatible
+ with non-static object methods due to PHP Bug #44144;
+ Please do not use HTMLPurifier.autoload.php (or any
+ file that includes this file); instead, place the code:
+ spl_autoload_register(array(\'HTMLPurifier_Bootstrap\', \'autoload\'))
+ after your own autoloaders.'
+ );
+ }
+ // Suprisingly, spl_autoload_register supports the
+ // Class::staticMethod callback format, although call_user_func doesn't
+ if ($compat) {
+ $func = implode('::', $func);
+ }
}
- // Suprisingly, spl_autoload_register supports the
- // Class::staticMethod callback format, although call_user_func doesn't
- if ($compat) $func = implode('::', $func);
+ spl_autoload_unregister($func);
+ }
+ spl_autoload_register($autoload);
+ foreach ($funcs as $func) {
+ spl_autoload_register($func);
}
- spl_autoload_unregister($func);
}
- spl_autoload_register($autoload);
- foreach ($funcs as $func) spl_autoload_register($func);
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/CSSDefinition.php b/library/HTMLPurifier/CSSDefinition.php
index 6a2e6f56d..0acdee2d9 100644
--- a/library/HTMLPurifier/CSSDefinition.php
+++ b/library/HTMLPurifier/CSSDefinition.php
@@ -11,35 +11,59 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
/**
* Assoc array of attribute name to definition object.
+ * @type HTMLPurifier_AttrDef[]
*/
public $info = array();
/**
* Constructs the info array. The meat of this class.
+ * @param HTMLPurifier_Config $config
*/
- protected function doSetup($config) {
-
+ protected function doSetup($config)
+ {
$this->info['text-align'] = new HTMLPurifier_AttrDef_Enum(
- array('left', 'right', 'center', 'justify'), false);
+ array('left', 'right', 'center', 'justify'),
+ false
+ );
$border_style =
- $this->info['border-bottom-style'] =
- $this->info['border-right-style'] =
- $this->info['border-left-style'] =
- $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum(
- array('none', 'hidden', 'dotted', 'dashed', 'solid', 'double',
- 'groove', 'ridge', 'inset', 'outset'), false);
+ $this->info['border-bottom-style'] =
+ $this->info['border-right-style'] =
+ $this->info['border-left-style'] =
+ $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum(
+ array(
+ 'none',
+ 'hidden',
+ 'dotted',
+ 'dashed',
+ 'solid',
+ 'double',
+ 'groove',
+ 'ridge',
+ 'inset',
+ 'outset'
+ ),
+ false
+ );
$this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style);
$this->info['clear'] = new HTMLPurifier_AttrDef_Enum(
- array('none', 'left', 'right', 'both'), false);
+ array('none', 'left', 'right', 'both'),
+ false
+ );
$this->info['float'] = new HTMLPurifier_AttrDef_Enum(
- array('none', 'left', 'right'), false);
+ array('none', 'left', 'right'),
+ false
+ );
$this->info['font-style'] = new HTMLPurifier_AttrDef_Enum(
- array('normal', 'italic', 'oblique'), false);
+ array('normal', 'italic', 'oblique'),
+ false
+ );
$this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum(
- array('normal', 'small-caps'), false);
+ array('normal', 'small-caps'),
+ false
+ );
$uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite(
array(
@@ -49,16 +73,31 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
);
$this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum(
- array('inside', 'outside'), false);
+ array('inside', 'outside'),
+ false
+ );
$this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum(
- array('disc', 'circle', 'square', 'decimal', 'lower-roman',
- 'upper-roman', 'lower-alpha', 'upper-alpha', 'none'), false);
+ array(
+ 'disc',
+ 'circle',
+ 'square',
+ 'decimal',
+ 'lower-roman',
+ 'upper-roman',
+ 'lower-alpha',
+ 'upper-alpha',
+ 'none'
+ ),
+ false
+ );
$this->info['list-style-image'] = $uri_or_none;
$this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config);
$this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum(
- array('capitalize', 'uppercase', 'lowercase', 'none'), false);
+ array('capitalize', 'uppercase', 'lowercase', 'none'),
+ false
+ );
$this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color();
$this->info['background-image'] = $uri_or_none;
@@ -71,104 +110,137 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition();
$border_color =
- $this->info['border-top-color'] =
- $this->info['border-bottom-color'] =
- $this->info['border-left-color'] =
- $this->info['border-right-color'] =
- $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_Enum(array('transparent')),
- new HTMLPurifier_AttrDef_CSS_Color()
- ));
+ $this->info['border-top-color'] =
+ $this->info['border-bottom-color'] =
+ $this->info['border-left-color'] =
+ $this->info['border-right-color'] =
+ $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_Enum(array('transparent')),
+ new HTMLPurifier_AttrDef_CSS_Color()
+ )
+ );
$this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config);
$this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color);
$border_width =
- $this->info['border-top-width'] =
- $this->info['border-bottom-width'] =
- $this->info['border-left-width'] =
- $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')),
- new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative
- ));
+ $this->info['border-top-width'] =
+ $this->info['border-bottom-width'] =
+ $this->info['border-left-width'] =
+ $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')),
+ new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative
+ )
+ );
$this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width);
- $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_Enum(array('normal')),
- new HTMLPurifier_AttrDef_CSS_Length()
- ));
-
- $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_Enum(array('normal')),
- new HTMLPurifier_AttrDef_CSS_Length()
- ));
-
- $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_Enum(array('xx-small', 'x-small',
- 'small', 'medium', 'large', 'x-large', 'xx-large',
- 'larger', 'smaller')),
- new HTMLPurifier_AttrDef_CSS_Percentage(),
- new HTMLPurifier_AttrDef_CSS_Length()
- ));
-
- $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_Enum(array('normal')),
- new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives
- new HTMLPurifier_AttrDef_CSS_Length('0'),
- new HTMLPurifier_AttrDef_CSS_Percentage(true)
- ));
+ $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_Enum(array('normal')),
+ new HTMLPurifier_AttrDef_CSS_Length()
+ )
+ );
+
+ $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_Enum(array('normal')),
+ new HTMLPurifier_AttrDef_CSS_Length()
+ )
+ );
+
+ $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_Enum(
+ array(
+ 'xx-small',
+ 'x-small',
+ 'small',
+ 'medium',
+ 'large',
+ 'x-large',
+ 'xx-large',
+ 'larger',
+ 'smaller'
+ )
+ ),
+ new HTMLPurifier_AttrDef_CSS_Percentage(),
+ new HTMLPurifier_AttrDef_CSS_Length()
+ )
+ );
+
+ $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_Enum(array('normal')),
+ new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives
+ new HTMLPurifier_AttrDef_CSS_Length('0'),
+ new HTMLPurifier_AttrDef_CSS_Percentage(true)
+ )
+ );
$margin =
- $this->info['margin-top'] =
- $this->info['margin-bottom'] =
- $this->info['margin-left'] =
- $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_CSS_Length(),
- new HTMLPurifier_AttrDef_CSS_Percentage(),
- new HTMLPurifier_AttrDef_Enum(array('auto'))
- ));
+ $this->info['margin-top'] =
+ $this->info['margin-bottom'] =
+ $this->info['margin-left'] =
+ $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_CSS_Length(),
+ new HTMLPurifier_AttrDef_CSS_Percentage(),
+ new HTMLPurifier_AttrDef_Enum(array('auto'))
+ )
+ );
$this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin);
// non-negative
$padding =
- $this->info['padding-top'] =
- $this->info['padding-bottom'] =
- $this->info['padding-left'] =
- $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_CSS_Length('0'),
- new HTMLPurifier_AttrDef_CSS_Percentage(true)
- ));
+ $this->info['padding-top'] =
+ $this->info['padding-bottom'] =
+ $this->info['padding-left'] =
+ $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_CSS_Length('0'),
+ new HTMLPurifier_AttrDef_CSS_Percentage(true)
+ )
+ );
$this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding);
- $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_CSS_Length(),
- new HTMLPurifier_AttrDef_CSS_Percentage()
- ));
+ $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_CSS_Length(),
+ new HTMLPurifier_AttrDef_CSS_Percentage()
+ )
+ );
- $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_CSS_Length('0'),
- new HTMLPurifier_AttrDef_CSS_Percentage(true),
- new HTMLPurifier_AttrDef_Enum(array('auto'))
- ));
+ $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_CSS_Length('0'),
+ new HTMLPurifier_AttrDef_CSS_Percentage(true),
+ new HTMLPurifier_AttrDef_Enum(array('auto'))
+ )
+ );
$max = $config->get('CSS.MaxImgLength');
$this->info['width'] =
$this->info['height'] =
$max === null ?
- $trusted_wh :
- new HTMLPurifier_AttrDef_Switch('img',
- // For img tags:
- new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_CSS_Length('0', $max),
- new HTMLPurifier_AttrDef_Enum(array('auto'))
- )),
- // For everyone else:
- $trusted_wh
- );
+ $trusted_wh :
+ new HTMLPurifier_AttrDef_Switch(
+ 'img',
+ // For img tags:
+ new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_CSS_Length('0', $max),
+ new HTMLPurifier_AttrDef_Enum(array('auto'))
+ )
+ ),
+ // For everyone else:
+ $trusted_wh
+ );
$this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();
@@ -176,8 +248,23 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
// this could use specialized code
$this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum(
- array('normal', 'bold', 'bolder', 'lighter', '100', '200', '300',
- '400', '500', '600', '700', '800', '900'), false);
+ array(
+ 'normal',
+ 'bold',
+ 'bolder',
+ 'lighter',
+ '100',
+ '200',
+ '300',
+ '400',
+ '500',
+ '600',
+ '700',
+ '800',
+ '900'
+ ),
+ false
+ );
// MUST be called after other font properties, as it references
// a CSSDefinition object
@@ -190,26 +277,44 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->info['border-left'] =
$this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config);
- $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(array(
- 'collapse', 'separate'));
+ $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(
+ array('collapse', 'separate')
+ );
- $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(array(
- 'top', 'bottom'));
+ $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(
+ array('top', 'bottom')
+ );
- $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(array(
- 'auto', 'fixed'));
+ $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(
+ array('auto', 'fixed')
+ );
- $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(array(
- new HTMLPurifier_AttrDef_Enum(array('baseline', 'sub', 'super',
- 'top', 'text-top', 'middle', 'bottom', 'text-bottom')),
- new HTMLPurifier_AttrDef_CSS_Length(),
- new HTMLPurifier_AttrDef_CSS_Percentage()
- ));
+ $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_Enum(
+ array(
+ 'baseline',
+ 'sub',
+ 'super',
+ 'top',
+ 'text-top',
+ 'middle',
+ 'bottom',
+ 'text-bottom'
+ )
+ ),
+ new HTMLPurifier_AttrDef_CSS_Length(),
+ new HTMLPurifier_AttrDef_CSS_Percentage()
+ )
+ );
$this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2);
- // partial support
- $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(array('nowrap'));
+ // These CSS properties don't work on many browsers, but we live
+ // in THE FUTURE!
+ $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(
+ array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line')
+ );
if ($config->get('CSS.Proprietary')) {
$this->doSetupProprietary($config);
@@ -219,6 +324,10 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->doSetupTricky($config);
}
+ if ($config->get('CSS.Trusted')) {
+ $this->doSetupTrusted($config);
+ }
+
$allow_important = $config->get('CSS.AllowImportant');
// wrap all attr-defs with decorator that handles !important
foreach ($this->info as $k => $v) {
@@ -228,64 +337,137 @@ class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition
$this->setupConfigStuff($config);
}
- protected function doSetupProprietary($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ protected function doSetupProprietary($config)
+ {
// Internet Explorer only scrollbar colors
- $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
- $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color();
- $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
- $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color();
- $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color();
- $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
+ $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
+ $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color();
+ $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
+ $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color();
+ $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color();
+ $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();
// technically not proprietary, but CSS3, and no one supports it
- $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
- $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
- $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
+ $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
+ $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
+ $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();
// only opacity, for now
$this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter();
+ // more CSS3
+ $this->info['page-break-after'] =
+ $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum(
+ array(
+ 'auto',
+ 'always',
+ 'avoid',
+ 'left',
+ 'right'
+ )
+ );
+ $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid'));
+
}
- protected function doSetupTricky($config) {
- $this->info['display'] = new HTMLPurifier_AttrDef_Enum(array(
- 'inline', 'block', 'list-item', 'run-in', 'compact',
- 'marker', 'table', 'inline-table', 'table-row-group',
- 'table-header-group', 'table-footer-group', 'table-row',
- 'table-column-group', 'table-column', 'table-cell', 'table-caption', 'none'
- ));
- $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(array(
- 'visible', 'hidden', 'collapse'
- ));
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ protected function doSetupTricky($config)
+ {
+ $this->info['display'] = new HTMLPurifier_AttrDef_Enum(
+ array(
+ 'inline',
+ 'block',
+ 'list-item',
+ 'run-in',
+ 'compact',
+ 'marker',
+ 'table',
+ 'inline-block',
+ 'inline-table',
+ 'table-row-group',
+ 'table-header-group',
+ 'table-footer-group',
+ 'table-row',
+ 'table-column-group',
+ 'table-column',
+ 'table-cell',
+ 'table-caption',
+ 'none'
+ )
+ );
+ $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(
+ array('visible', 'hidden', 'collapse')
+ );
$this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll'));
}
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ protected function doSetupTrusted($config)
+ {
+ $this->info['position'] = new HTMLPurifier_AttrDef_Enum(
+ array('static', 'relative', 'absolute', 'fixed')
+ );
+ $this->info['top'] =
+ $this->info['left'] =
+ $this->info['right'] =
+ $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_CSS_Length(),
+ new HTMLPurifier_AttrDef_CSS_Percentage(),
+ new HTMLPurifier_AttrDef_Enum(array('auto')),
+ )
+ );
+ $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite(
+ array(
+ new HTMLPurifier_AttrDef_Integer(),
+ new HTMLPurifier_AttrDef_Enum(array('auto')),
+ )
+ );
+ }
/**
* Performs extra config-based processing. Based off of
* HTMLPurifier_HTMLDefinition.
+ * @param HTMLPurifier_Config $config
* @todo Refactor duplicate elements into common class (probably using
* composition, not inheritance).
*/
- protected function setupConfigStuff($config) {
-
+ protected function setupConfigStuff($config)
+ {
// setup allowed elements
- $support = "(for information on implementing this, see the ".
- "support forums) ";
- $allowed_attributes = $config->get('CSS.AllowedProperties');
- if ($allowed_attributes !== null) {
+ $support = "(for information on implementing this, see the " .
+ "support forums) ";
+ $allowed_properties = $config->get('CSS.AllowedProperties');
+ if ($allowed_properties !== null) {
foreach ($this->info as $name => $d) {
- if(!isset($allowed_attributes[$name])) unset($this->info[$name]);
- unset($allowed_attributes[$name]);
+ if (!isset($allowed_properties[$name])) {
+ unset($this->info[$name]);
+ }
+ unset($allowed_properties[$name]);
}
// emit errors
- foreach ($allowed_attributes as $name => $d) {
+ foreach ($allowed_properties as $name => $d) {
// :TODO: Is this htmlspecialchars() call really necessary?
$name = htmlspecialchars($name);
trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING);
}
}
+ $forbidden_properties = $config->get('CSS.ForbiddenProperties');
+ if ($forbidden_properties !== null) {
+ foreach ($this->info as $name => $d) {
+ if (isset($forbidden_properties[$name])) {
+ unset($this->info[$name]);
+ }
+ }
+ }
}
}
diff --git a/library/HTMLPurifier/ChildDef.php b/library/HTMLPurifier/ChildDef.php
index c5d5216da..8eb17b82e 100644
--- a/library/HTMLPurifier/ChildDef.php
+++ b/library/HTMLPurifier/ChildDef.php
@@ -1,48 +1,52 @@
<?php
/**
- * Defines allowed child nodes and validates tokens against it.
+ * Defines allowed child nodes and validates nodes against it.
*/
abstract class HTMLPurifier_ChildDef
{
/**
* Type of child definition, usually right-most part of class name lowercase.
* Used occasionally in terms of context.
+ * @type string
*/
public $type;
/**
- * Bool that indicates whether or not an empty array of children is okay
+ * Indicates whether or not an empty array of children is okay.
*
* This is necessary for redundant checking when changes affecting
* a child node may cause a parent node to now be disallowed.
+ * @type bool
*/
public $allow_empty;
/**
- * Lookup array of all elements that this definition could possibly allow
+ * Lookup array of all elements that this definition could possibly allow.
+ * @type array
*/
public $elements = array();
/**
* Get lookup of tag names that should not close this element automatically.
* All other elements will do so.
+ * @param HTMLPurifier_Config $config HTMLPurifier_Config object
+ * @return array
*/
- public function getAllowedElements($config) {
+ public function getAllowedElements($config)
+ {
return $this->elements;
}
/**
* Validates nodes according to definition and returns modification.
*
- * @param $tokens_of_children Array of HTMLPurifier_Token
- * @param $config HTMLPurifier_Config object
- * @param $context HTMLPurifier_Context object
- * @return bool true to leave nodes as is
- * @return bool false to remove parent node
- * @return array of replacement child tokens
+ * @param HTMLPurifier_Node[] $children Array of HTMLPurifier_Node
+ * @param HTMLPurifier_Config $config HTMLPurifier_Config object
+ * @param HTMLPurifier_Context $context HTMLPurifier_Context object
+ * @return bool|array true to leave nodes as is, false to remove parent node, array of replacement children
*/
- abstract public function validateChildren($tokens_of_children, $config, $context);
+ abstract public function validateChildren($children, $config, $context);
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ChildDef/Chameleon.php b/library/HTMLPurifier/ChildDef/Chameleon.php
index 15c364ee3..7439be26b 100644
--- a/library/HTMLPurifier/ChildDef/Chameleon.php
+++ b/library/HTMLPurifier/ChildDef/Chameleon.php
@@ -14,33 +14,52 @@ class HTMLPurifier_ChildDef_Chameleon extends HTMLPurifier_ChildDef
/**
* Instance of the definition object to use when inline. Usually stricter.
+ * @type HTMLPurifier_ChildDef_Optional
*/
public $inline;
/**
* Instance of the definition object to use when block.
+ * @type HTMLPurifier_ChildDef_Optional
*/
public $block;
+ /**
+ * @type string
+ */
public $type = 'chameleon';
/**
- * @param $inline List of elements to allow when inline.
- * @param $block List of elements to allow when block.
+ * @param array $inline List of elements to allow when inline.
+ * @param array $block List of elements to allow when block.
*/
- public function __construct($inline, $block) {
+ public function __construct($inline, $block)
+ {
$this->inline = new HTMLPurifier_ChildDef_Optional($inline);
- $this->block = new HTMLPurifier_ChildDef_Optional($block);
+ $this->block = new HTMLPurifier_ChildDef_Optional($block);
$this->elements = $this->block->elements;
}
- public function validateChildren($tokens_of_children, $config, $context) {
+ /**
+ * @param HTMLPurifier_Node[] $children
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function validateChildren($children, $config, $context)
+ {
if ($context->get('IsInline') === false) {
return $this->block->validateChildren(
- $tokens_of_children, $config, $context);
+ $children,
+ $config,
+ $context
+ );
} else {
return $this->inline->validateChildren(
- $tokens_of_children, $config, $context);
+ $children,
+ $config,
+ $context
+ );
}
}
}
diff --git a/library/HTMLPurifier/ChildDef/Custom.php b/library/HTMLPurifier/ChildDef/Custom.php
index b68047b4b..128132e96 100644
--- a/library/HTMLPurifier/ChildDef/Custom.php
+++ b/library/HTMLPurifier/ChildDef/Custom.php
@@ -8,28 +8,42 @@
*/
class HTMLPurifier_ChildDef_Custom extends HTMLPurifier_ChildDef
{
+ /**
+ * @type string
+ */
public $type = 'custom';
+
+ /**
+ * @type bool
+ */
public $allow_empty = false;
+
/**
- * Allowed child pattern as defined by the DTD
+ * Allowed child pattern as defined by the DTD.
+ * @type string
*/
public $dtd_regex;
+
/**
- * PCRE regex derived from $dtd_regex
- * @private
+ * PCRE regex derived from $dtd_regex.
+ * @type string
*/
private $_pcre_regex;
+
/**
* @param $dtd_regex Allowed child pattern from the DTD
*/
- public function __construct($dtd_regex) {
+ public function __construct($dtd_regex)
+ {
$this->dtd_regex = $dtd_regex;
$this->_compileRegex();
}
+
/**
* Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex)
*/
- protected function _compileRegex() {
+ protected function _compileRegex()
+ {
$raw = str_replace(' ', '', $this->dtd_regex);
if ($raw{0} != '(') {
$raw = "($raw)";
@@ -57,33 +71,31 @@ class HTMLPurifier_ChildDef_Custom extends HTMLPurifier_ChildDef
$this->_pcre_regex = $reg;
}
- public function validateChildren($tokens_of_children, $config, $context) {
+
+ /**
+ * @param HTMLPurifier_Node[] $children
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function validateChildren($children, $config, $context)
+ {
$list_of_children = '';
$nesting = 0; // depth into the nest
- foreach ($tokens_of_children as $token) {
- if (!empty($token->is_whitespace)) continue;
-
- $is_child = ($nesting == 0); // direct
-
- if ($token instanceof HTMLPurifier_Token_Start) {
- $nesting++;
- } elseif ($token instanceof HTMLPurifier_Token_End) {
- $nesting--;
- }
-
- if ($is_child) {
- $list_of_children .= $token->name . ',';
+ foreach ($children as $node) {
+ if (!empty($node->is_whitespace)) {
+ continue;
}
+ $list_of_children .= $node->name . ',';
}
// add leading comma to deal with stray comma declarations
$list_of_children = ',' . rtrim($list_of_children, ',');
$okay =
preg_match(
- '/^,?'.$this->_pcre_regex.'$/',
+ '/^,?' . $this->_pcre_regex . '$/',
$list_of_children
);
-
- return (bool) $okay;
+ return (bool)$okay;
}
}
diff --git a/library/HTMLPurifier/ChildDef/Empty.php b/library/HTMLPurifier/ChildDef/Empty.php
index 13171f665..a8a6cbdd2 100644
--- a/library/HTMLPurifier/ChildDef/Empty.php
+++ b/library/HTMLPurifier/ChildDef/Empty.php
@@ -9,10 +9,28 @@
*/
class HTMLPurifier_ChildDef_Empty extends HTMLPurifier_ChildDef
{
+ /**
+ * @type bool
+ */
public $allow_empty = true;
+
+ /**
+ * @type string
+ */
public $type = 'empty';
- public function __construct() {}
- public function validateChildren($tokens_of_children, $config, $context) {
+
+ public function __construct()
+ {
+ }
+
+ /**
+ * @param HTMLPurifier_Node[] $children
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function validateChildren($children, $config, $context)
+ {
return array();
}
}
diff --git a/library/HTMLPurifier/ChildDef/List.php b/library/HTMLPurifier/ChildDef/List.php
new file mode 100644
index 000000000..891b9f6f5
--- /dev/null
+++ b/library/HTMLPurifier/ChildDef/List.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * Definition for list containers ul and ol.
+ *
+ * What does this do? The big thing is to handle ol/ul at the top
+ * level of list nodes, which should be handled specially by /folding/
+ * them into the previous list node. We generally shouldn't ever
+ * see other disallowed elements, because the autoclose behavior
+ * in MakeWellFormed handles it.
+ */
+class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef
+{
+ /**
+ * @type string
+ */
+ public $type = 'list';
+ /**
+ * @type array
+ */
+ // lying a little bit, so that we can handle ul and ol ourselves
+ // XXX: This whole business with 'wrap' is all a bit unsatisfactory
+ public $elements = array('li' => true, 'ul' => true, 'ol' => true);
+
+ /**
+ * @param array $children
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function validateChildren($children, $config, $context)
+ {
+ // Flag for subclasses
+ $this->whitespace = false;
+
+ // if there are no tokens, delete parent node
+ if (empty($children)) {
+ return false;
+ }
+
+ // the new set of children
+ $result = array();
+
+ // a little sanity check to make sure it's not ALL whitespace
+ $all_whitespace = true;
+
+ $current_li = false;
+
+ foreach ($children as $node) {
+ if (!empty($node->is_whitespace)) {
+ $result[] = $node;
+ continue;
+ }
+ $all_whitespace = false; // phew, we're not talking about whitespace
+
+ if ($node->name === 'li') {
+ // good
+ $current_li = $node;
+ $result[] = $node;
+ } else {
+ // we want to tuck this into the previous li
+ // Invariant: we expect the node to be ol/ul
+ // ToDo: Make this more robust in the case of not ol/ul
+ // by distinguishing between existing li and li created
+ // to handle non-list elements; non-list elements should
+ // not be appended to an existing li; only li created
+ // for non-list. This distinction is not currently made.
+ if ($current_li === false) {
+ $current_li = new HTMLPurifier_Node_Element('li');
+ $result[] = $current_li;
+ }
+ $current_li->children[] = $node;
+ $current_li->empty = false; // XXX fascinating! Check for this error elsewhere ToDo
+ }
+ }
+ if (empty($result)) {
+ return false;
+ }
+ if ($all_whitespace) {
+ return false;
+ }
+ return $result;
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ChildDef/Optional.php b/library/HTMLPurifier/ChildDef/Optional.php
index 32bcb9898..b9468063b 100644
--- a/library/HTMLPurifier/ChildDef/Optional.php
+++ b/library/HTMLPurifier/ChildDef/Optional.php
@@ -9,15 +9,34 @@
*/
class HTMLPurifier_ChildDef_Optional extends HTMLPurifier_ChildDef_Required
{
+ /**
+ * @type bool
+ */
public $allow_empty = true;
+
+ /**
+ * @type string
+ */
public $type = 'optional';
- public function validateChildren($tokens_of_children, $config, $context) {
- $result = parent::validateChildren($tokens_of_children, $config, $context);
- // we assume that $tokens_of_children is not modified
+
+ /**
+ * @param array $children
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function validateChildren($children, $config, $context)
+ {
+ $result = parent::validateChildren($children, $config, $context);
+ // we assume that $children is not modified
if ($result === false) {
- if (empty($tokens_of_children)) return true;
- elseif ($this->whitespace) return $tokens_of_children;
- else return array();
+ if (empty($children)) {
+ return true;
+ } elseif ($this->whitespace) {
+ return $children;
+ } else {
+ return array();
+ }
}
return $result;
}
diff --git a/library/HTMLPurifier/ChildDef/Required.php b/library/HTMLPurifier/ChildDef/Required.php
index 4889f249b..0d1c8f5f3 100644
--- a/library/HTMLPurifier/ChildDef/Required.php
+++ b/library/HTMLPurifier/ChildDef/Required.php
@@ -7,17 +7,21 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
{
/**
* Lookup table of allowed elements.
- * @public
+ * @type array
*/
public $elements = array();
+
/**
* Whether or not the last passed node was all whitespace.
+ * @type bool
*/
protected $whitespace = false;
+
/**
- * @param $elements List of allowed element names (lowercase).
+ * @param array|string $elements List of allowed element names (lowercase).
*/
- public function __construct($elements) {
+ public function __construct($elements)
+ {
if (is_string($elements)) {
$elements = str_replace(' ', '', $elements);
$elements = explode('|', $elements);
@@ -27,29 +31,43 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
$elements = array_flip($elements);
foreach ($elements as $i => $x) {
$elements[$i] = true;
- if (empty($i)) unset($elements[$i]); // remove blank
+ if (empty($i)) {
+ unset($elements[$i]);
+ } // remove blank
}
}
$this->elements = $elements;
}
+
+ /**
+ * @type bool
+ */
public $allow_empty = false;
+
+ /**
+ * @type string
+ */
public $type = 'required';
- public function validateChildren($tokens_of_children, $config, $context) {
+
+ /**
+ * @param array $children
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function validateChildren($children, $config, $context)
+ {
// Flag for subclasses
$this->whitespace = false;
// if there are no tokens, delete parent node
- if (empty($tokens_of_children)) return false;
+ if (empty($children)) {
+ return false;
+ }
// the new set of children
$result = array();
- // current depth into the nest
- $nesting = 0;
-
- // whether or not we're deleting a node
- $is_deleting = false;
-
// whether or not parsed character data is allowed
// this controls whether or not we silently drop a tag
// or generate escaped HTML from it
@@ -58,58 +76,41 @@ class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef
// a little sanity check to make sure it's not ALL whitespace
$all_whitespace = true;
- // some configuration
- $escape_invalid_children = $config->get('Core.EscapeInvalidChildren');
-
- // generator
- $gen = new HTMLPurifier_Generator($config, $context);
-
- foreach ($tokens_of_children as $token) {
- if (!empty($token->is_whitespace)) {
- $result[] = $token;
+ $stack = array_reverse($children);
+ while (!empty($stack)) {
+ $node = array_pop($stack);
+ if (!empty($node->is_whitespace)) {
+ $result[] = $node;
continue;
}
$all_whitespace = false; // phew, we're not talking about whitespace
- $is_child = ($nesting == 0);
-
- if ($token instanceof HTMLPurifier_Token_Start) {
- $nesting++;
- } elseif ($token instanceof HTMLPurifier_Token_End) {
- $nesting--;
- }
-
- if ($is_child) {
- $is_deleting = false;
- if (!isset($this->elements[$token->name])) {
- $is_deleting = true;
- if ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text) {
- $result[] = $token;
- } elseif ($pcdata_allowed && $escape_invalid_children) {
- $result[] = new HTMLPurifier_Token_Text(
- $gen->generateFromToken($token)
- );
+ if (!isset($this->elements[$node->name])) {
+ // special case text
+ // XXX One of these ought to be redundant or something
+ if ($pcdata_allowed && $node instanceof HTMLPurifier_Node_Text) {
+ $result[] = $node;
+ continue;
+ }
+ // spill the child contents in
+ // ToDo: Make configurable
+ if ($node instanceof HTMLPurifier_Node_Element) {
+ for ($i = count($node->children) - 1; $i >= 0; $i--) {
+ $stack[] = $node->children[$i];
}
continue;
}
+ continue;
}
- if (!$is_deleting || ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text)) {
- $result[] = $token;
- } elseif ($pcdata_allowed && $escape_invalid_children) {
- $result[] =
- new HTMLPurifier_Token_Text(
- $gen->generateFromToken($token)
- );
- } else {
- // drop silently
- }
+ $result[] = $node;
+ }
+ if (empty($result)) {
+ return false;
}
- if (empty($result)) return false;
if ($all_whitespace) {
$this->whitespace = true;
return false;
}
- if ($tokens_of_children == $result) return true;
return $result;
}
}
diff --git a/library/HTMLPurifier/ChildDef/StrictBlockquote.php b/library/HTMLPurifier/ChildDef/StrictBlockquote.php
index dfae8a6e5..3270a46e1 100644
--- a/library/HTMLPurifier/ChildDef/StrictBlockquote.php
+++ b/library/HTMLPurifier/ChildDef/StrictBlockquote.php
@@ -5,75 +5,97 @@
*/
class HTMLPurifier_ChildDef_StrictBlockquote extends HTMLPurifier_ChildDef_Required
{
+ /**
+ * @type array
+ */
protected $real_elements;
+
+ /**
+ * @type array
+ */
protected $fake_elements;
+
+ /**
+ * @type bool
+ */
public $allow_empty = true;
+
+ /**
+ * @type string
+ */
public $type = 'strictblockquote';
+
+ /**
+ * @type bool
+ */
protected $init = false;
/**
+ * @param HTMLPurifier_Config $config
+ * @return array
* @note We don't want MakeWellFormed to auto-close inline elements since
* they might be allowed.
*/
- public function getAllowedElements($config) {
+ public function getAllowedElements($config)
+ {
$this->init($config);
return $this->fake_elements;
}
- public function validateChildren($tokens_of_children, $config, $context) {
-
+ /**
+ * @param array $children
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function validateChildren($children, $config, $context)
+ {
$this->init($config);
// trick the parent class into thinking it allows more
$this->elements = $this->fake_elements;
- $result = parent::validateChildren($tokens_of_children, $config, $context);
+ $result = parent::validateChildren($children, $config, $context);
$this->elements = $this->real_elements;
- if ($result === false) return array();
- if ($result === true) $result = $tokens_of_children;
+ if ($result === false) {
+ return array();
+ }
+ if ($result === true) {
+ $result = $children;
+ }
$def = $config->getHTMLDefinition();
- $block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper);
- $block_wrap_end = new HTMLPurifier_Token_End( $def->info_block_wrapper);
- $is_inline = false;
- $depth = 0;
+ $block_wrap_name = $def->info_block_wrapper;
+ $block_wrap = false;
$ret = array();
- // assuming that there are no comment tokens
- foreach ($result as $i => $token) {
- $token = $result[$i];
- // ifs are nested for readability
- if (!$is_inline) {
- if (!$depth) {
- if (
- ($token instanceof HTMLPurifier_Token_Text && !$token->is_whitespace) ||
- (!$token instanceof HTMLPurifier_Token_Text && !isset($this->elements[$token->name]))
- ) {
- $is_inline = true;
- $ret[] = $block_wrap_start;
- }
+ foreach ($result as $node) {
+ if ($block_wrap === false) {
+ if (($node instanceof HTMLPurifier_Node_Text && !$node->is_whitespace) ||
+ ($node instanceof HTMLPurifier_Node_Element && !isset($this->elements[$node->name]))) {
+ $block_wrap = new HTMLPurifier_Node_Element($def->info_block_wrapper);
+ $ret[] = $block_wrap;
}
} else {
- if (!$depth) {
- // starting tokens have been inline text / empty
- if ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) {
- if (isset($this->elements[$token->name])) {
- // ended
- $ret[] = $block_wrap_end;
- $is_inline = false;
- }
- }
+ if ($node instanceof HTMLPurifier_Node_Element && isset($this->elements[$node->name])) {
+ $block_wrap = false;
+
}
}
- $ret[] = $token;
- if ($token instanceof HTMLPurifier_Token_Start) $depth++;
- if ($token instanceof HTMLPurifier_Token_End) $depth--;
+ if ($block_wrap) {
+ $block_wrap->children[] = $node;
+ } else {
+ $ret[] = $node;
+ }
}
- if ($is_inline) $ret[] = $block_wrap_end;
return $ret;
}
- private function init($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ private function init($config)
+ {
if (!$this->init) {
$def = $config->getHTMLDefinition();
// allow all inline elements
diff --git a/library/HTMLPurifier/ChildDef/Table.php b/library/HTMLPurifier/ChildDef/Table.php
index 34f0227dd..3e4a0f218 100644
--- a/library/HTMLPurifier/ChildDef/Table.php
+++ b/library/HTMLPurifier/ChildDef/Table.php
@@ -1,140 +1,222 @@
<?php
/**
- * Definition for tables
+ * Definition for tables. The general idea is to extract out all of the
+ * essential bits, and then reconstruct it later.
+ *
+ * This is a bit confusing, because the DTDs and the W3C
+ * validators seem to disagree on the appropriate definition. The
+ * DTD claims:
+ *
+ * (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)
+ *
+ * But actually, the HTML4 spec then has this to say:
+ *
+ * The TBODY start tag is always required except when the table
+ * contains only one table body and no table head or foot sections.
+ * The TBODY end tag may always be safely omitted.
+ *
+ * So the DTD is kind of wrong. The validator is, unfortunately, kind
+ * of on crack.
+ *
+ * The definition changed again in XHTML1.1; and in my opinion, this
+ * formulation makes the most sense.
+ *
+ * caption?, ( col* | colgroup* ), (( thead?, tfoot?, tbody+ ) | ( tr+ ))
+ *
+ * Essentially, we have two modes: thead/tfoot/tbody mode, and tr mode.
+ * If we encounter a thead, tfoot or tbody, we are placed in the former
+ * mode, and we *must* wrap any stray tr segments with a tbody. But if
+ * we don't run into any of them, just have tr tags is OK.
*/
class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef
{
+ /**
+ * @type bool
+ */
public $allow_empty = false;
+
+ /**
+ * @type string
+ */
public $type = 'table';
- public $elements = array('tr' => true, 'tbody' => true, 'thead' => true,
- 'tfoot' => true, 'caption' => true, 'colgroup' => true, 'col' => true);
- public function __construct() {}
- public function validateChildren($tokens_of_children, $config, $context) {
- if (empty($tokens_of_children)) return false;
- // this ensures that the loop gets run one last time before closing
- // up. It's a little bit of a hack, but it works! Just make sure you
- // get rid of the token later.
- $tokens_of_children[] = false;
+ /**
+ * @type array
+ */
+ public $elements = array(
+ 'tr' => true,
+ 'tbody' => true,
+ 'thead' => true,
+ 'tfoot' => true,
+ 'caption' => true,
+ 'colgroup' => true,
+ 'col' => true
+ );
+
+ public function __construct()
+ {
+ }
+
+ /**
+ * @param array $children
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array
+ */
+ public function validateChildren($children, $config, $context)
+ {
+ if (empty($children)) {
+ return false;
+ }
// only one of these elements is allowed in a table
$caption = false;
- $thead = false;
- $tfoot = false;
+ $thead = false;
+ $tfoot = false;
+
+ // whitespace
+ $initial_ws = array();
+ $after_caption_ws = array();
+ $after_thead_ws = array();
+ $after_tfoot_ws = array();
// as many of these as you want
- $cols = array();
+ $cols = array();
$content = array();
- $nesting = 0; // current depth so we can determine nodes
- $is_collecting = false; // are we globbing together tokens to package
- // into one of the collectors?
- $collection = array(); // collected nodes
- $tag_index = 0; // the first node might be whitespace,
- // so this tells us where the start tag is
-
- foreach ($tokens_of_children as $token) {
- $is_child = ($nesting == 0);
-
- if ($token === false) {
- // terminating sequence started
- } elseif ($token instanceof HTMLPurifier_Token_Start) {
- $nesting++;
- } elseif ($token instanceof HTMLPurifier_Token_End) {
- $nesting--;
- }
+ $tbody_mode = false; // if true, then we need to wrap any stray
+ // <tr>s with a <tbody>.
- // handle node collection
- if ($is_collecting) {
- if ($is_child) {
- // okay, let's stash the tokens away
- // first token tells us the type of the collection
- switch ($collection[$tag_index]->name) {
- case 'tr':
- case 'tbody':
- $content[] = $collection;
- break;
- case 'caption':
- if ($caption !== false) break;
- $caption = $collection;
- break;
- case 'thead':
- case 'tfoot':
- // access the appropriate variable, $thead or $tfoot
- $var = $collection[$tag_index]->name;
- if ($$var === false) {
- $$var = $collection;
- } else {
- // transmutate the first and less entries into
- // tbody tags, and then put into content
- $collection[$tag_index]->name = 'tbody';
- $collection[count($collection)-1]->name = 'tbody';
- $content[] = $collection;
- }
- break;
- case 'colgroup':
- $cols[] = $collection;
- break;
- }
- $collection = array();
- $is_collecting = false;
- $tag_index = 0;
+ $ws_accum =& $initial_ws;
+
+ foreach ($children as $node) {
+ if ($node instanceof HTMLPurifier_Node_Comment) {
+ $ws_accum[] = $node;
+ continue;
+ }
+ switch ($node->name) {
+ case 'tbody':
+ $tbody_mode = true;
+ // fall through
+ case 'tr':
+ $content[] = $node;
+ $ws_accum =& $content;
+ break;
+ case 'caption':
+ // there can only be one caption!
+ if ($caption !== false) break;
+ $caption = $node;
+ $ws_accum =& $after_caption_ws;
+ break;
+ case 'thead':
+ $tbody_mode = true;
+ // XXX This breaks rendering properties with
+ // Firefox, which never floats a <thead> to
+ // the top. Ever. (Our scheme will float the
+ // first <thead> to the top.) So maybe
+ // <thead>s that are not first should be
+ // turned into <tbody>? Very tricky, indeed.
+ if ($thead === false) {
+ $thead = $node;
+ $ws_accum =& $after_thead_ws;
} else {
- // add the node to the collection
- $collection[] = $token;
+ // Oops, there's a second one! What
+ // should we do? Current behavior is to
+ // transmutate the first and last entries into
+ // tbody tags, and then put into content.
+ // Maybe a better idea is to *attach
+ // it* to the existing thead or tfoot?
+ // We don't do this, because Firefox
+ // doesn't float an extra tfoot to the
+ // bottom like it does for the first one.
+ $node->name = 'tbody';
+ $content[] = $node;
+ $ws_accum =& $content;
}
- }
-
- // terminate
- if ($token === false) break;
-
- if ($is_child) {
- // determine what we're dealing with
- if ($token->name == 'col') {
- // the only empty tag in the possie, we can handle it
- // immediately
- $cols[] = array_merge($collection, array($token));
- $collection = array();
- $tag_index = 0;
- continue;
+ break;
+ case 'tfoot':
+ // see above for some aveats
+ $tbody_mode = true;
+ if ($tfoot === false) {
+ $tfoot = $node;
+ $ws_accum =& $after_tfoot_ws;
+ } else {
+ $node->name = 'tbody';
+ $content[] = $node;
+ $ws_accum =& $content;
}
- switch($token->name) {
- case 'caption':
- case 'colgroup':
- case 'thead':
- case 'tfoot':
- case 'tbody':
- case 'tr':
- $is_collecting = true;
- $collection[] = $token;
- continue;
- default:
- if (!empty($token->is_whitespace)) {
- $collection[] = $token;
- $tag_index++;
- }
- continue;
+ break;
+ case 'colgroup':
+ case 'col':
+ $cols[] = $node;
+ $ws_accum =& $cols;
+ break;
+ case '#PCDATA':
+ // How is whitespace handled? We treat is as sticky to
+ // the *end* of the previous element. So all of the
+ // nonsense we have worked on is to keep things
+ // together.
+ if (!empty($node->is_whitespace)) {
+ $ws_accum[] = $node;
}
+ break;
}
}
- if (empty($content)) return false;
-
- $ret = array();
- if ($caption !== false) $ret = array_merge($ret, $caption);
- if ($cols !== false) foreach ($cols as $token_array) $ret = array_merge($ret, $token_array);
- if ($thead !== false) $ret = array_merge($ret, $thead);
- if ($tfoot !== false) $ret = array_merge($ret, $tfoot);
- foreach ($content as $token_array) $ret = array_merge($ret, $token_array);
- if (!empty($collection) && $is_collecting == false){
- // grab the trailing space
- $ret = array_merge($ret, $collection);
+ if (empty($content)) {
+ return false;
+ }
+
+ $ret = $initial_ws;
+ if ($caption !== false) {
+ $ret[] = $caption;
+ $ret = array_merge($ret, $after_caption_ws);
+ }
+ if ($cols !== false) {
+ $ret = array_merge($ret, $cols);
+ }
+ if ($thead !== false) {
+ $ret[] = $thead;
+ $ret = array_merge($ret, $after_thead_ws);
+ }
+ if ($tfoot !== false) {
+ $ret[] = $tfoot;
+ $ret = array_merge($ret, $after_tfoot_ws);
}
- array_pop($tokens_of_children); // remove phantom token
+ if ($tbody_mode) {
+ // we have to shuffle tr into tbody
+ $current_tr_tbody = null;
+
+ foreach($content as $node) {
+ switch ($node->name) {
+ case 'tbody':
+ $current_tr_tbody = null;
+ $ret[] = $node;
+ break;
+ case 'tr':
+ if ($current_tr_tbody === null) {
+ $current_tr_tbody = new HTMLPurifier_Node_Element('tbody');
+ $ret[] = $current_tr_tbody;
+ }
+ $current_tr_tbody->children[] = $node;
+ break;
+ case '#PCDATA':
+ assert($node->is_whitespace);
+ if ($current_tr_tbody === null) {
+ $ret[] = $node;
+ } else {
+ $current_tr_tbody->children[] = $node;
+ }
+ break;
+ }
+ }
+ } else {
+ $ret = array_merge($ret, $content);
+ }
- return ($ret === $tokens_of_children) ? true : $ret;
+ return $ret;
}
}
diff --git a/library/HTMLPurifier/Config.php b/library/HTMLPurifier/Config.php
index 2a334b0d8..7ada59b94 100644
--- a/library/HTMLPurifier/Config.php
+++ b/library/HTMLPurifier/Config.php
@@ -19,77 +19,92 @@ class HTMLPurifier_Config
/**
* HTML Purifier's version
+ * @type string
*/
- public $version = '4.1.1';
+ public $version = '4.6.0';
/**
- * Bool indicator whether or not to automatically finalize
- * the object if a read operation is done
+ * Whether or not to automatically finalize
+ * the object if a read operation is done.
+ * @type bool
*/
public $autoFinalize = true;
// protected member variables
/**
- * Namespace indexed array of serials for specific namespaces (see
- * getSerial() for more info).
+ * Namespace indexed array of serials for specific namespaces.
+ * @see getSerial() for more info.
+ * @type string[]
*/
protected $serials = array();
/**
- * Serial for entire configuration object
+ * Serial for entire configuration object.
+ * @type string
*/
protected $serial;
/**
- * Parser for variables
+ * Parser for variables.
+ * @type HTMLPurifier_VarParser_Flexible
*/
- protected $parser;
+ protected $parser = null;
/**
- * Reference HTMLPurifier_ConfigSchema for value checking
+ * Reference HTMLPurifier_ConfigSchema for value checking.
+ * @type HTMLPurifier_ConfigSchema
* @note This is public for introspective purposes. Please don't
* abuse!
*/
public $def;
/**
- * Indexed array of definitions
+ * Indexed array of definitions.
+ * @type HTMLPurifier_Definition[]
*/
protected $definitions;
/**
- * Bool indicator whether or not config is finalized
+ * Whether or not config is finalized.
+ * @type bool
*/
protected $finalized = false;
/**
* Property list containing configuration directives.
+ * @type array
*/
protected $plist;
/**
- * Whether or not a set is taking place due to an
- * alias lookup.
+ * Whether or not a set is taking place due to an alias lookup.
+ * @type bool
*/
private $aliasMode;
/**
- * Set to false if you do not want line and file numbers in errors
- * (useful when unit testing)
+ * Set to false if you do not want line and file numbers in errors.
+ * (useful when unit testing). This will also compress some errors
+ * and exceptions.
+ * @type bool
*/
public $chatty = true;
/**
* Current lock; only gets to this namespace are allowed.
+ * @type string
*/
private $lock;
/**
- * @param $definition HTMLPurifier_ConfigSchema that defines what directives
- * are allowed.
+ * Constructor
+ * @param HTMLPurifier_ConfigSchema $definition ConfigSchema that defines
+ * what directives are allowed.
+ * @param HTMLPurifier_PropertyList $parent
*/
- public function __construct($definition, $parent = null) {
+ public function __construct($definition, $parent = null)
+ {
$parent = $parent ? $parent : $definition->defaultPlist;
$this->plist = new HTMLPurifier_PropertyList($parent);
$this->def = $definition; // keep a copy around for checking
@@ -102,10 +117,11 @@ class HTMLPurifier_Config
* object. Can be: a HTMLPurifier_Config() object,
* an array of directives based on loadArray(),
* or a string filename of an ini file.
- * @param HTMLPurifier_ConfigSchema Schema object
- * @return Configured HTMLPurifier_Config object
+ * @param HTMLPurifier_ConfigSchema $schema Schema object
+ * @return HTMLPurifier_Config Configured object
*/
- public static function create($config, $schema = null) {
+ public static function create($config, $schema = null)
+ {
if ($config instanceof HTMLPurifier_Config) {
// pass-through
return $config;
@@ -115,57 +131,79 @@ class HTMLPurifier_Config
} else {
$ret = new HTMLPurifier_Config($schema);
}
- if (is_string($config)) $ret->loadIni($config);
- elseif (is_array($config)) $ret->loadArray($config);
+ if (is_string($config)) {
+ $ret->loadIni($config);
+ } elseif (is_array($config)) $ret->loadArray($config);
return $ret;
}
/**
* Creates a new config object that inherits from a previous one.
- * @param HTMLPurifier_Config $config Configuration object to inherit
- * from.
+ * @param HTMLPurifier_Config $config Configuration object to inherit from.
* @return HTMLPurifier_Config object with $config as its parent.
*/
- public static function inherit(HTMLPurifier_Config $config) {
+ public static function inherit(HTMLPurifier_Config $config)
+ {
return new HTMLPurifier_Config($config->def, $config->plist);
}
/**
* Convenience constructor that creates a default configuration object.
- * @return Default HTMLPurifier_Config object.
+ * @return HTMLPurifier_Config default object.
*/
- public static function createDefault() {
+ public static function createDefault()
+ {
$definition = HTMLPurifier_ConfigSchema::instance();
$config = new HTMLPurifier_Config($definition);
return $config;
}
/**
- * Retreives a value from the configuration.
- * @param $key String key
+ * Retrieves a value from the configuration.
+ *
+ * @param string $key String key
+ * @param mixed $a
+ *
+ * @return mixed
*/
- public function get($key, $a = null) {
+ public function get($key, $a = null)
+ {
if ($a !== null) {
- $this->triggerError("Using deprecated API: use \$config->get('$key.$a') instead", E_USER_WARNING);
+ $this->triggerError(
+ "Using deprecated API: use \$config->get('$key.$a') instead",
+ E_USER_WARNING
+ );
$key = "$key.$a";
}
- if (!$this->finalized) $this->autoFinalize();
+ if (!$this->finalized) {
+ $this->autoFinalize();
+ }
if (!isset($this->def->info[$key])) {
// can't add % due to SimpleTest bug
- $this->triggerError('Cannot retrieve value of undefined directive ' . htmlspecialchars($key),
- E_USER_WARNING);
+ $this->triggerError(
+ 'Cannot retrieve value of undefined directive ' . htmlspecialchars($key),
+ E_USER_WARNING
+ );
return;
}
if (isset($this->def->info[$key]->isAlias)) {
$d = $this->def->info[$key];
- $this->triggerError('Cannot get value from aliased directive, use real name ' . $d->key,
- E_USER_ERROR);
+ $this->triggerError(
+ 'Cannot get value from aliased directive, use real name ' . $d->key,
+ E_USER_ERROR
+ );
return;
}
if ($this->lock) {
list($ns) = explode('.', $key);
if ($ns !== $this->lock) {
- $this->triggerError('Cannot get value of namespace ' . $ns . ' when lock for ' . $this->lock . ' is active, this probably indicates a Definition setup method is accessing directives that are not within its namespace', E_USER_ERROR);
+ $this->triggerError(
+ 'Cannot get value of namespace ' . $ns . ' when lock for ' .
+ $this->lock .
+ ' is active, this probably indicates a Definition setup method ' .
+ 'is accessing directives that are not within its namespace',
+ E_USER_ERROR
+ );
return;
}
}
@@ -173,53 +211,73 @@ class HTMLPurifier_Config
}
/**
- * Retreives an array of directives to values from a given namespace
- * @param $namespace String namespace
+ * Retrieves an array of directives to values from a given namespace
+ *
+ * @param string $namespace String namespace
+ *
+ * @return array
*/
- public function getBatch($namespace) {
- if (!$this->finalized) $this->autoFinalize();
+ public function getBatch($namespace)
+ {
+ if (!$this->finalized) {
+ $this->autoFinalize();
+ }
$full = $this->getAll();
if (!isset($full[$namespace])) {
- $this->triggerError('Cannot retrieve undefined namespace ' . htmlspecialchars($namespace),
- E_USER_WARNING);
+ $this->triggerError(
+ 'Cannot retrieve undefined namespace ' .
+ htmlspecialchars($namespace),
+ E_USER_WARNING
+ );
return;
}
return $full[$namespace];
}
/**
- * Returns a md5 signature of a segment of the configuration object
+ * Returns a SHA-1 signature of a segment of the configuration object
* that uniquely identifies that particular configuration
+ *
+ * @param string $namespace Namespace to get serial for
+ *
+ * @return string
* @note Revision is handled specially and is removed from the batch
* before processing!
- * @param $namespace Namespace to get serial for
*/
- public function getBatchSerial($namespace) {
+ public function getBatchSerial($namespace)
+ {
if (empty($this->serials[$namespace])) {
$batch = $this->getBatch($namespace);
unset($batch['DefinitionRev']);
- $this->serials[$namespace] = md5(serialize($batch));
+ $this->serials[$namespace] = sha1(serialize($batch));
}
return $this->serials[$namespace];
}
/**
- * Returns a md5 signature for the entire configuration object
+ * Returns a SHA-1 signature for the entire configuration object
* that uniquely identifies that particular configuration
+ *
+ * @return string
*/
- public function getSerial() {
+ public function getSerial()
+ {
if (empty($this->serial)) {
- $this->serial = md5(serialize($this->getAll()));
+ $this->serial = sha1(serialize($this->getAll()));
}
return $this->serial;
}
/**
* Retrieves all directives, organized by namespace
+ *
* @warning This is a pretty inefficient function, avoid if you can
*/
- public function getAll() {
- if (!$this->finalized) $this->autoFinalize();
+ public function getAll()
+ {
+ if (!$this->finalized) {
+ $this->autoFinalize();
+ }
$ret = array();
foreach ($this->plist->squash() as $name => $value) {
list($ns, $key) = explode('.', $name, 2);
@@ -230,10 +288,13 @@ class HTMLPurifier_Config
/**
* Sets a value to configuration.
- * @param $key String key
- * @param $value Mixed value
+ *
+ * @param string $key key
+ * @param mixed $value value
+ * @param mixed $a
*/
- public function set($key, $value, $a = null) {
+ public function set($key, $value, $a = null)
+ {
if (strpos($key, '.') === false) {
$namespace = $key;
$directive = $value;
@@ -243,18 +304,25 @@ class HTMLPurifier_Config
} else {
list($namespace) = explode('.', $key);
}
- if ($this->isFinalized('Cannot set directive after finalization')) return;
+ if ($this->isFinalized('Cannot set directive after finalization')) {
+ return;
+ }
if (!isset($this->def->info[$key])) {
- $this->triggerError('Cannot set undefined directive ' . htmlspecialchars($key) . ' to value',
- E_USER_WARNING);
+ $this->triggerError(
+ 'Cannot set undefined directive ' . htmlspecialchars($key) . ' to value',
+ E_USER_WARNING
+ );
return;
}
$def = $this->def->info[$key];
if (isset($def->isAlias)) {
if ($this->aliasMode) {
- $this->triggerError('Double-aliases not allowed, please fix '.
- 'ConfigSchema bug with' . $key, E_USER_ERROR);
+ $this->triggerError(
+ 'Double-aliases not allowed, please fix '.
+ 'ConfigSchema bug with' . $key,
+ E_USER_ERROR
+ );
return;
}
$this->aliasMode = true;
@@ -278,7 +346,11 @@ class HTMLPurifier_Config
try {
$value = $this->parser->parse($value, $type, $allow_null);
} catch (HTMLPurifier_VarParserException $e) {
- $this->triggerError('Value for ' . $key . ' is of invalid type, should be ' . HTMLPurifier_VarParser::getTypeName($type), E_USER_WARNING);
+ $this->triggerError(
+ 'Value for ' . $key . ' is of invalid type, should be ' .
+ HTMLPurifier_VarParser::getTypeName($type),
+ E_USER_WARNING
+ );
return;
}
if (is_string($value) && is_object($def)) {
@@ -288,8 +360,11 @@ class HTMLPurifier_Config
}
// check to see if the value is allowed
if (isset($def->allowed) && !isset($def->allowed[$value])) {
- $this->triggerError('Value not supported, valid values are: ' .
- $this->_listify($def->allowed), E_USER_WARNING);
+ $this->triggerError(
+ 'Value not supported, valid values are: ' .
+ $this->_listify($def->allowed),
+ E_USER_WARNING
+ );
return;
}
}
@@ -307,38 +382,102 @@ class HTMLPurifier_Config
/**
* Convenience function for error reporting
+ *
+ * @param array $lookup
+ *
+ * @return string
*/
- private function _listify($lookup) {
+ private function _listify($lookup)
+ {
$list = array();
- foreach ($lookup as $name => $b) $list[] = $name;
+ foreach ($lookup as $name => $b) {
+ $list[] = $name;
+ }
return implode(', ', $list);
}
/**
* Retrieves object reference to the HTML definition.
- * @param $raw Return a copy that has not been setup yet. Must be
+ *
+ * @param bool $raw Return a copy that has not been setup yet. Must be
* called before it's been setup, otherwise won't work.
- */
- public function getHTMLDefinition($raw = false) {
- return $this->getDefinition('HTML', $raw);
+ * @param bool $optimized If true, this method may return null, to
+ * indicate that a cached version of the modified
+ * definition object is available and no further edits
+ * are necessary. Consider using
+ * maybeGetRawHTMLDefinition, which is more explicitly
+ * named, instead.
+ *
+ * @return HTMLPurifier_HTMLDefinition
+ */
+ public function getHTMLDefinition($raw = false, $optimized = false)
+ {
+ return $this->getDefinition('HTML', $raw, $optimized);
}
/**
* Retrieves object reference to the CSS definition
- * @param $raw Return a copy that has not been setup yet. Must be
+ *
+ * @param bool $raw Return a copy that has not been setup yet. Must be
* called before it's been setup, otherwise won't work.
- */
- public function getCSSDefinition($raw = false) {
- return $this->getDefinition('CSS', $raw);
+ * @param bool $optimized If true, this method may return null, to
+ * indicate that a cached version of the modified
+ * definition object is available and no further edits
+ * are necessary. Consider using
+ * maybeGetRawCSSDefinition, which is more explicitly
+ * named, instead.
+ *
+ * @return HTMLPurifier_CSSDefinition
+ */
+ public function getCSSDefinition($raw = false, $optimized = false)
+ {
+ return $this->getDefinition('CSS', $raw, $optimized);
+ }
+
+ /**
+ * Retrieves object reference to the URI definition
+ *
+ * @param bool $raw Return a copy that has not been setup yet. Must be
+ * called before it's been setup, otherwise won't work.
+ * @param bool $optimized If true, this method may return null, to
+ * indicate that a cached version of the modified
+ * definition object is available and no further edits
+ * are necessary. Consider using
+ * maybeGetRawURIDefinition, which is more explicitly
+ * named, instead.
+ *
+ * @return HTMLPurifier_URIDefinition
+ */
+ public function getURIDefinition($raw = false, $optimized = false)
+ {
+ return $this->getDefinition('URI', $raw, $optimized);
}
/**
* Retrieves a definition
- * @param $type Type of definition: HTML, CSS, etc
- * @param $raw Whether or not definition should be returned raw
- */
- public function getDefinition($type, $raw = false) {
- if (!$this->finalized) $this->autoFinalize();
+ *
+ * @param string $type Type of definition: HTML, CSS, etc
+ * @param bool $raw Whether or not definition should be returned raw
+ * @param bool $optimized Only has an effect when $raw is true. Whether
+ * or not to return null if the result is already present in
+ * the cache. This is off by default for backwards
+ * compatibility reasons, but you need to do things this
+ * way in order to ensure that caching is done properly.
+ * Check out enduser-customize.html for more details.
+ * We probably won't ever change this default, as much as the
+ * maybe semantics is the "right thing to do."
+ *
+ * @throws HTMLPurifier_Exception
+ * @return HTMLPurifier_Definition
+ */
+ public function getDefinition($type, $raw = false, $optimized = false)
+ {
+ if ($optimized && !$raw) {
+ throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false");
+ }
+ if (!$this->finalized) {
+ $this->autoFinalize();
+ }
// temporarily suspend locks, so we can handle recursive definition calls
$lock = $this->lock;
$this->lock = null;
@@ -346,61 +485,193 @@ class HTMLPurifier_Config
$cache = $factory->create($type, $this);
$this->lock = $lock;
if (!$raw) {
- // see if we can quickly supply a definition
+ // full definition
+ // ---------------
+ // check if definition is in memory
+ if (!empty($this->definitions[$type])) {
+ $def = $this->definitions[$type];
+ // check if the definition is setup
+ if ($def->setup) {
+ return $def;
+ } else {
+ $def->setup($this);
+ if ($def->optimized) {
+ $cache->add($def, $this);
+ }
+ return $def;
+ }
+ }
+ // check if definition is in cache
+ $def = $cache->get($this);
+ if ($def) {
+ // definition in cache, save to memory and return it
+ $this->definitions[$type] = $def;
+ return $def;
+ }
+ // initialize it
+ $def = $this->initDefinition($type);
+ // set it up
+ $this->lock = $type;
+ $def->setup($this);
+ $this->lock = null;
+ // save in cache
+ $cache->add($def, $this);
+ // return it
+ return $def;
+ } else {
+ // raw definition
+ // --------------
+ // check preconditions
+ $def = null;
+ if ($optimized) {
+ if (is_null($this->get($type . '.DefinitionID'))) {
+ // fatally error out if definition ID not set
+ throw new HTMLPurifier_Exception(
+ "Cannot retrieve raw version without specifying %$type.DefinitionID"
+ );
+ }
+ }
if (!empty($this->definitions[$type])) {
- if (!$this->definitions[$type]->setup) {
- $this->definitions[$type]->setup($this);
- $cache->set($this->definitions[$type], $this);
+ $def = $this->definitions[$type];
+ if ($def->setup && !$optimized) {
+ $extra = $this->chatty ?
+ " (try moving this code block earlier in your initialization)" :
+ "";
+ throw new HTMLPurifier_Exception(
+ "Cannot retrieve raw definition after it has already been setup" .
+ $extra
+ );
+ }
+ if ($def->optimized === null) {
+ $extra = $this->chatty ? " (try flushing your cache)" : "";
+ throw new HTMLPurifier_Exception(
+ "Optimization status of definition is unknown" . $extra
+ );
+ }
+ if ($def->optimized !== $optimized) {
+ $msg = $optimized ? "optimized" : "unoptimized";
+ $extra = $this->chatty ?
+ " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)"
+ : "";
+ throw new HTMLPurifier_Exception(
+ "Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra
+ );
}
- return $this->definitions[$type];
}
- // memory check missed, try cache
- $this->definitions[$type] = $cache->get($this);
- if ($this->definitions[$type]) {
- // definition in cache, return it
- return $this->definitions[$type];
+ // check if definition was in memory
+ if ($def) {
+ if ($def->setup) {
+ // invariant: $optimized === true (checked above)
+ return null;
+ } else {
+ return $def;
+ }
}
- } elseif (
- !empty($this->definitions[$type]) &&
- !$this->definitions[$type]->setup
- ) {
- // raw requested, raw in memory, quick return
- return $this->definitions[$type];
+ // if optimized, check if definition was in cache
+ // (because we do the memory check first, this formulation
+ // is prone to cache slamming, but I think
+ // guaranteeing that either /all/ of the raw
+ // setup code or /none/ of it is run is more important.)
+ if ($optimized) {
+ // This code path only gets run once; once we put
+ // something in $definitions (which is guaranteed by the
+ // trailing code), we always short-circuit above.
+ $def = $cache->get($this);
+ if ($def) {
+ // save the full definition for later, but don't
+ // return it yet
+ $this->definitions[$type] = $def;
+ return null;
+ }
+ }
+ // check invariants for creation
+ if (!$optimized) {
+ if (!is_null($this->get($type . '.DefinitionID'))) {
+ if ($this->chatty) {
+ $this->triggerError(
+ 'Due to a documentation error in previous version of HTML Purifier, your ' .
+ 'definitions are not being cached. If this is OK, you can remove the ' .
+ '%$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, ' .
+ 'modify your code to use maybeGetRawDefinition, and test if the returned ' .
+ 'value is null before making any edits (if it is null, that means that a ' .
+ 'cached version is available, and no raw operations are necessary). See ' .
+ '<a href="http://htmlpurifier.org/docs/enduser-customize.html#optimized">' .
+ 'Customize</a> for more details',
+ E_USER_WARNING
+ );
+ } else {
+ $this->triggerError(
+ "Useless DefinitionID declaration",
+ E_USER_WARNING
+ );
+ }
+ }
+ }
+ // initialize it
+ $def = $this->initDefinition($type);
+ $def->optimized = $optimized;
+ return $def;
}
+ throw new HTMLPurifier_Exception("The impossible happened!");
+ }
+
+ /**
+ * Initialise definition
+ *
+ * @param string $type What type of definition to create
+ *
+ * @return HTMLPurifier_CSSDefinition|HTMLPurifier_HTMLDefinition|HTMLPurifier_URIDefinition
+ * @throws HTMLPurifier_Exception
+ */
+ private function initDefinition($type)
+ {
// quick checks failed, let's create the object
if ($type == 'HTML') {
- $this->definitions[$type] = new HTMLPurifier_HTMLDefinition();
+ $def = new HTMLPurifier_HTMLDefinition();
} elseif ($type == 'CSS') {
- $this->definitions[$type] = new HTMLPurifier_CSSDefinition();
+ $def = new HTMLPurifier_CSSDefinition();
} elseif ($type == 'URI') {
- $this->definitions[$type] = new HTMLPurifier_URIDefinition();
+ $def = new HTMLPurifier_URIDefinition();
} else {
- throw new HTMLPurifier_Exception("Definition of $type type not supported");
+ throw new HTMLPurifier_Exception(
+ "Definition of $type type not supported"
+ );
}
- // quick abort if raw
- if ($raw) {
- if (is_null($this->get($type . '.DefinitionID'))) {
- // fatally error out if definition ID not set
- throw new HTMLPurifier_Exception("Cannot retrieve raw version without specifying %$type.DefinitionID");
- }
- return $this->definitions[$type];
- }
- // set it up
- $this->lock = $type;
- $this->definitions[$type]->setup($this);
- $this->lock = null;
- // save in cache
- $cache->set($this->definitions[$type], $this);
- return $this->definitions[$type];
+ $this->definitions[$type] = $def;
+ return $def;
+ }
+
+ public function maybeGetRawDefinition($name)
+ {
+ return $this->getDefinition($name, true, true);
+ }
+
+ public function maybeGetRawHTMLDefinition()
+ {
+ return $this->getDefinition('HTML', true, true);
+ }
+
+ public function maybeGetRawCSSDefinition()
+ {
+ return $this->getDefinition('CSS', true, true);
+ }
+
+ public function maybeGetRawURIDefinition()
+ {
+ return $this->getDefinition('URI', true, true);
}
/**
* Loads configuration values from an array with the following structure:
* Namespace.Directive => Value
- * @param $config_array Configuration associative array
+ *
+ * @param array $config_array Configuration associative array
*/
- public function loadArray($config_array) {
- if ($this->isFinalized('Cannot load directives after finalization')) return;
+ public function loadArray($config_array)
+ {
+ if ($this->isFinalized('Cannot load directives after finalization')) {
+ return;
+ }
foreach ($config_array as $key => $value) {
$key = str_replace('_', '.', $key);
if (strpos($key, '.') !== false) {
@@ -408,8 +679,8 @@ class HTMLPurifier_Config
} else {
$namespace = $key;
$namespace_values = $value;
- foreach ($namespace_values as $directive => $value) {
- $this->set($namespace .'.'. $directive, $value);
+ foreach ($namespace_values as $directive => $value2) {
+ $this->set($namespace .'.'. $directive, $value2);
}
}
}
@@ -419,40 +690,55 @@ class HTMLPurifier_Config
* Returns a list of array(namespace, directive) for all directives
* that are allowed in a web-form context as per an allowed
* namespaces/directives list.
- * @param $allowed List of allowed namespaces/directives
- */
- public static function getAllowedDirectivesForForm($allowed, $schema = null) {
+ *
+ * @param array $allowed List of allowed namespaces/directives
+ * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
+ *
+ * @return array
+ */
+ public static function getAllowedDirectivesForForm($allowed, $schema = null)
+ {
if (!$schema) {
$schema = HTMLPurifier_ConfigSchema::instance();
}
if ($allowed !== true) {
- if (is_string($allowed)) $allowed = array($allowed);
- $allowed_ns = array();
- $allowed_directives = array();
- $blacklisted_directives = array();
- foreach ($allowed as $ns_or_directive) {
- if (strpos($ns_or_directive, '.') !== false) {
- // directive
- if ($ns_or_directive[0] == '-') {
- $blacklisted_directives[substr($ns_or_directive, 1)] = true;
- } else {
- $allowed_directives[$ns_or_directive] = true;
- }
- } else {
- // namespace
- $allowed_ns[$ns_or_directive] = true;
- }
- }
+ if (is_string($allowed)) {
+ $allowed = array($allowed);
+ }
+ $allowed_ns = array();
+ $allowed_directives = array();
+ $blacklisted_directives = array();
+ foreach ($allowed as $ns_or_directive) {
+ if (strpos($ns_or_directive, '.') !== false) {
+ // directive
+ if ($ns_or_directive[0] == '-') {
+ $blacklisted_directives[substr($ns_or_directive, 1)] = true;
+ } else {
+ $allowed_directives[$ns_or_directive] = true;
+ }
+ } else {
+ // namespace
+ $allowed_ns[$ns_or_directive] = true;
+ }
+ }
}
$ret = array();
foreach ($schema->info as $key => $def) {
list($ns, $directive) = explode('.', $key, 2);
if ($allowed !== true) {
- if (isset($blacklisted_directives["$ns.$directive"])) continue;
- if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) continue;
+ if (isset($blacklisted_directives["$ns.$directive"])) {
+ continue;
+ }
+ if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) {
+ continue;
+ }
+ }
+ if (isset($def->isAlias)) {
+ continue;
+ }
+ if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') {
+ continue;
}
- if (isset($def->isAlias)) continue;
- if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') continue;
$ret[] = array($ns, $directive);
}
return $ret;
@@ -461,13 +747,17 @@ class HTMLPurifier_Config
/**
* Loads configuration values from $_GET/$_POST that were posted
* via ConfigForm
- * @param $array $_GET or $_POST array to import
- * @param $index Index/name that the config variables are in
- * @param $allowed List of allowed namespaces/directives
- * @param $mq_fix Boolean whether or not to enable magic quotes fix
- * @param $schema Instance of HTMLPurifier_ConfigSchema to use, if not global copy
- */
- public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
+ *
+ * @param array $array $_GET or $_POST array to import
+ * @param string|bool $index Index/name that the config variables are in
+ * @param array|bool $allowed List of allowed namespaces/directives
+ * @param bool $mq_fix Boolean whether or not to enable magic quotes fix
+ * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
+ *
+ * @return mixed
+ */
+ public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null)
+ {
$ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema);
$config = HTMLPurifier_Config::create($ret, $schema);
return $config;
@@ -475,9 +765,14 @@ class HTMLPurifier_Config
/**
* Merges in configuration values from $_GET/$_POST to object. NOT STATIC.
- * @note Same parameters as loadArrayFromForm
- */
- public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) {
+ *
+ * @param array $array $_GET or $_POST array to import
+ * @param string|bool $index Index/name that the config variables are in
+ * @param array|bool $allowed List of allowed namespaces/directives
+ * @param bool $mq_fix Boolean whether or not to enable magic quotes fix
+ */
+ public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true)
+ {
$ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def);
$this->loadArray($ret);
}
@@ -485,9 +780,20 @@ class HTMLPurifier_Config
/**
* Prepares an array from a form into something usable for the more
* strict parts of HTMLPurifier_Config
- */
- public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) {
- if ($index !== false) $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
+ *
+ * @param array $array $_GET or $_POST array to import
+ * @param string|bool $index Index/name that the config variables are in
+ * @param array|bool $allowed List of allowed namespaces/directives
+ * @param bool $mq_fix Boolean whether or not to enable magic quotes fix
+ * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy
+ *
+ * @return array
+ */
+ public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null)
+ {
+ if ($index !== false) {
+ $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array();
+ }
$mq = $mq_fix && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc();
$allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema);
@@ -499,7 +805,9 @@ class HTMLPurifier_Config
$ret[$ns][$directive] = null;
continue;
}
- if (!isset($array[$skey])) continue;
+ if (!isset($array[$skey])) {
+ continue;
+ }
$value = $mq ? stripslashes($array[$skey]) : $array[$skey];
$ret[$ns][$directive] = $value;
}
@@ -508,19 +816,27 @@ class HTMLPurifier_Config
/**
* Loads configuration values from an ini file
- * @param $filename Name of ini file
+ *
+ * @param string $filename Name of ini file
*/
- public function loadIni($filename) {
- if ($this->isFinalized('Cannot load directives after finalization')) return;
+ public function loadIni($filename)
+ {
+ if ($this->isFinalized('Cannot load directives after finalization')) {
+ return;
+ }
$array = parse_ini_file($filename, true);
$this->loadArray($array);
}
/**
* Checks whether or not the configuration object is finalized.
- * @param $error String error message, or false for no error
+ *
+ * @param string|bool $error String error message, or false for no error
+ *
+ * @return bool
*/
- public function isFinalized($error = false) {
+ public function isFinalized($error = false)
+ {
if ($this->finalized && $error) {
$this->triggerError($error, E_USER_ERROR);
}
@@ -531,7 +847,8 @@ class HTMLPurifier_Config
* Finalizes configuration only if auto finalize is on and not
* already finalized
*/
- public function autoFinalize() {
+ public function autoFinalize()
+ {
if ($this->autoFinalize) {
$this->finalize();
} else {
@@ -542,24 +859,35 @@ class HTMLPurifier_Config
/**
* Finalizes a configuration object, prohibiting further change
*/
- public function finalize() {
+ public function finalize()
+ {
$this->finalized = true;
- unset($this->parser);
+ $this->parser = null;
}
/**
* Produces a nicely formatted error message by supplying the
- * stack frame information from two levels up and OUTSIDE of
- * HTMLPurifier_Config.
+ * stack frame information OUTSIDE of HTMLPurifier_Config.
+ *
+ * @param string $msg An error message
+ * @param int $no An error number
*/
- protected function triggerError($msg, $no) {
+ protected function triggerError($msg, $no)
+ {
// determine previous stack frame
- $backtrace = debug_backtrace();
- if ($this->chatty && isset($backtrace[1])) {
- $frame = $backtrace[1];
- $extra = " on line {$frame['line']} in file {$frame['file']}";
- } else {
- $extra = '';
+ $extra = '';
+ if ($this->chatty) {
+ $trace = debug_backtrace();
+ // zip(tail(trace), trace) -- but PHP is not Haskell har har
+ for ($i = 0, $c = count($trace); $i < $c - 1; $i++) {
+ // XXX this is not correct on some versions of HTML Purifier
+ if ($trace[$i + 1]['class'] === 'HTMLPurifier_Config') {
+ continue;
+ }
+ $frame = $trace[$i];
+ $extra = " invoked on line {$frame['line']} in file {$frame['file']}";
+ break;
+ }
}
trigger_error($msg . $extra, $no);
}
@@ -567,8 +895,11 @@ class HTMLPurifier_Config
/**
* Returns a serialized form of the configuration object that can
* be reconstituted.
+ *
+ * @return string
*/
- public function serialize() {
+ public function serialize()
+ {
$this->getDefinition('HTML');
$this->getDefinition('CSS');
$this->getDefinition('URI');
diff --git a/library/HTMLPurifier/ConfigSchema.php b/library/HTMLPurifier/ConfigSchema.php
index 67be5c71f..bfbb0f92f 100644
--- a/library/HTMLPurifier/ConfigSchema.php
+++ b/library/HTMLPurifier/ConfigSchema.php
@@ -3,21 +3,24 @@
/**
* Configuration definition, defines directives and their defaults.
*/
-class HTMLPurifier_ConfigSchema {
-
+class HTMLPurifier_ConfigSchema
+{
/**
* Defaults of the directives and namespaces.
+ * @type array
* @note This shares the exact same structure as HTMLPurifier_Config::$conf
*/
public $defaults = array();
/**
* The default property list. Do not edit this property list.
+ * @type array
*/
public $defaultPlist;
/**
- * Definition of the directives. The structure of this is:
+ * Definition of the directives.
+ * The structure of this is:
*
* array(
* 'Namespace' => array(
@@ -44,29 +47,43 @@ class HTMLPurifier_ConfigSchema {
* This class is friendly with HTMLPurifier_Config. If you need introspection
* about the schema, you're better of using the ConfigSchema_Interchange,
* which uses more memory but has much richer information.
+ * @type array
*/
public $info = array();
/**
* Application-wide singleton
+ * @type HTMLPurifier_ConfigSchema
*/
- static protected $singleton;
+ protected static $singleton;
- public function __construct() {
+ public function __construct()
+ {
$this->defaultPlist = new HTMLPurifier_PropertyList();
}
/**
* Unserializes the default ConfigSchema.
+ * @return HTMLPurifier_ConfigSchema
*/
- public static function makeFromSerial() {
- return unserialize(file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser'));
+ public static function makeFromSerial()
+ {
+ $contents = file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser');
+ $r = unserialize($contents);
+ if (!$r) {
+ $hash = sha1($contents);
+ trigger_error("Unserialization of configuration schema failed, sha1 of file was $hash", E_USER_ERROR);
+ }
+ return $r;
}
/**
* Retrieves an instance of the application-wide configuration definition.
+ * @param HTMLPurifier_ConfigSchema $prototype
+ * @return HTMLPurifier_ConfigSchema
*/
- public static function instance($prototype = null) {
+ public static function instance($prototype = null)
+ {
if ($prototype !== null) {
HTMLPurifier_ConfigSchema::$singleton = $prototype;
} elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) {
@@ -80,17 +97,19 @@ class HTMLPurifier_ConfigSchema {
* @warning Will fail of directive's namespace is defined.
* @warning This method's signature is slightly different from the legacy
* define() static method! Beware!
- * @param $namespace Namespace the directive is in
- * @param $name Key of directive
- * @param $default Default value of directive
- * @param $type Allowed type of the directive. See
+ * @param string $key Name of directive
+ * @param mixed $default Default value of directive
+ * @param string $type Allowed type of the directive. See
* HTMLPurifier_DirectiveDef::$type for allowed values
- * @param $allow_null Whether or not to allow null values
+ * @param bool $allow_null Whether or not to allow null values
*/
- public function add($key, $default, $type, $allow_null) {
+ public function add($key, $default, $type, $allow_null)
+ {
$obj = new stdclass();
$obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type];
- if ($allow_null) $obj->allow_null = true;
+ if ($allow_null) {
+ $obj->allow_null = true;
+ }
$this->info[$key] = $obj;
$this->defaults[$key] = $default;
$this->defaultPlist->set($key, $default);
@@ -101,11 +120,11 @@ class HTMLPurifier_ConfigSchema {
*
* Directive value aliases are convenient for developers because it lets
* them set a directive to several values and get the same result.
- * @param $namespace Directive's namespace
- * @param $name Name of Directive
- * @param $aliases Hash of aliased values to the real alias
+ * @param string $key Name of Directive
+ * @param array $aliases Hash of aliased values to the real alias
*/
- public function addValueAliases($key, $aliases) {
+ public function addValueAliases($key, $aliases)
+ {
if (!isset($this->info[$key]->aliases)) {
$this->info[$key]->aliases = array();
}
@@ -118,22 +137,21 @@ class HTMLPurifier_ConfigSchema {
* Defines a set of allowed values for a directive.
* @warning This is slightly different from the corresponding static
* method definition.
- * @param $namespace Namespace of directive
- * @param $name Name of directive
- * @param $allowed Lookup array of allowed values
+ * @param string $key Name of directive
+ * @param array $allowed Lookup array of allowed values
*/
- public function addAllowedValues($key, $allowed) {
+ public function addAllowedValues($key, $allowed)
+ {
$this->info[$key]->allowed = $allowed;
}
/**
* Defines a directive alias for backwards compatibility
- * @param $namespace
- * @param $name Directive that will be aliased
- * @param $new_namespace
- * @param $new_name Directive that the alias will be to
+ * @param string $key Directive that will be aliased
+ * @param string $new_key Directive that the alias will be to
*/
- public function addAlias($key, $new_key) {
+ public function addAlias($key, $new_key)
+ {
$obj = new stdclass;
$obj->key = $new_key;
$obj->isAlias = true;
@@ -143,7 +161,8 @@ class HTMLPurifier_ConfigSchema {
/**
* Replaces any stdclass that only has the type property with type integer.
*/
- public function postProcess() {
+ public function postProcess()
+ {
foreach ($this->info as $key => $v) {
if (count((array) $v) == 1) {
$this->info[$key] = $v->type;
@@ -152,7 +171,6 @@ class HTMLPurifier_ConfigSchema {
}
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php b/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php
index c05668a70..d5906cd46 100644
--- a/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php
+++ b/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php
@@ -7,7 +7,12 @@
class HTMLPurifier_ConfigSchema_Builder_ConfigSchema
{
- public function build($interchange) {
+ /**
+ * @param HTMLPurifier_ConfigSchema_Interchange $interchange
+ * @return HTMLPurifier_ConfigSchema
+ */
+ public function build($interchange)
+ {
$schema = new HTMLPurifier_ConfigSchema();
foreach ($interchange->directives as $d) {
$schema->add(
@@ -38,7 +43,6 @@ class HTMLPurifier_ConfigSchema_Builder_ConfigSchema
$schema->postProcess();
return $schema;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/Builder/Xml.php b/library/HTMLPurifier/ConfigSchema/Builder/Xml.php
index 244561a37..5fa56f7dd 100644
--- a/library/HTMLPurifier/ConfigSchema/Builder/Xml.php
+++ b/library/HTMLPurifier/ConfigSchema/Builder/Xml.php
@@ -7,10 +7,21 @@
class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
{
+ /**
+ * @type HTMLPurifier_ConfigSchema_Interchange
+ */
protected $interchange;
+
+ /**
+ * @type string
+ */
private $namespace;
- protected function writeHTMLDiv($html) {
+ /**
+ * @param string $html
+ */
+ protected function writeHTMLDiv($html)
+ {
$this->startElement('div');
$purifier = HTMLPurifier::getInstance();
@@ -21,12 +32,23 @@ class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
$this->endElement(); // div
}
- protected function export($var) {
- if ($var === array()) return 'array()';
+ /**
+ * @param mixed $var
+ * @return string
+ */
+ protected function export($var)
+ {
+ if ($var === array()) {
+ return 'array()';
+ }
return var_export($var, true);
}
- public function build($interchange) {
+ /**
+ * @param HTMLPurifier_ConfigSchema_Interchange $interchange
+ */
+ public function build($interchange)
+ {
// global access, only use as last resort
$this->interchange = $interchange;
@@ -39,19 +61,26 @@ class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
$this->buildDirective($directive);
}
- if ($this->namespace) $this->endElement(); // namespace
+ if ($this->namespace) {
+ $this->endElement();
+ } // namespace
$this->endElement(); // configdoc
$this->flush();
}
- public function buildDirective($directive) {
-
+ /**
+ * @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive
+ */
+ public function buildDirective($directive)
+ {
// Kludge, although I suppose having a notion of a "root namespace"
// certainly makes things look nicer when documentation is built.
// Depends on things being sorted.
if (!$this->namespace || $this->namespace !== $directive->id->getRootNamespace()) {
- if ($this->namespace) $this->endElement(); // namespace
+ if ($this->namespace) {
+ $this->endElement();
+ } // namespace
$this->namespace = $directive->id->getRootNamespace();
$this->startElement('namespace');
$this->writeAttribute('id', $this->namespace);
@@ -64,43 +93,52 @@ class HTMLPurifier_ConfigSchema_Builder_Xml extends XMLWriter
$this->writeElement('name', $directive->id->getDirective());
$this->startElement('aliases');
- foreach ($directive->aliases as $alias) $this->writeElement('alias', $alias->toString());
+ foreach ($directive->aliases as $alias) {
+ $this->writeElement('alias', $alias->toString());
+ }
$this->endElement(); // aliases
$this->startElement('constraints');
- if ($directive->version) $this->writeElement('version', $directive->version);
- $this->startElement('type');
- if ($directive->typeAllowsNull) $this->writeAttribute('allow-null', 'yes');
- $this->text($directive->type);
- $this->endElement(); // type
- if ($directive->allowed) {
- $this->startElement('allowed');
- foreach ($directive->allowed as $value => $x) $this->writeElement('value', $value);
- $this->endElement(); // allowed
+ if ($directive->version) {
+ $this->writeElement('version', $directive->version);
+ }
+ $this->startElement('type');
+ if ($directive->typeAllowsNull) {
+ $this->writeAttribute('allow-null', 'yes');
+ }
+ $this->text($directive->type);
+ $this->endElement(); // type
+ if ($directive->allowed) {
+ $this->startElement('allowed');
+ foreach ($directive->allowed as $value => $x) {
+ $this->writeElement('value', $value);
}
- $this->writeElement('default', $this->export($directive->default));
- $this->writeAttribute('xml:space', 'preserve');
- if ($directive->external) {
- $this->startElement('external');
- foreach ($directive->external as $project) $this->writeElement('project', $project);
- $this->endElement();
+ $this->endElement(); // allowed
+ }
+ $this->writeElement('default', $this->export($directive->default));
+ $this->writeAttribute('xml:space', 'preserve');
+ if ($directive->external) {
+ $this->startElement('external');
+ foreach ($directive->external as $project) {
+ $this->writeElement('project', $project);
}
+ $this->endElement();
+ }
$this->endElement(); // constraints
if ($directive->deprecatedVersion) {
$this->startElement('deprecated');
- $this->writeElement('version', $directive->deprecatedVersion);
- $this->writeElement('use', $directive->deprecatedUse->toString());
+ $this->writeElement('version', $directive->deprecatedVersion);
+ $this->writeElement('use', $directive->deprecatedUse->toString());
$this->endElement(); // deprecated
}
$this->startElement('description');
- $this->writeHTMLDiv($directive->description);
+ $this->writeHTMLDiv($directive->description);
$this->endElement(); // description
$this->endElement(); // directive
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/Interchange.php b/library/HTMLPurifier/ConfigSchema/Interchange.php
index 91a5aa730..0e08ae8fe 100644
--- a/library/HTMLPurifier/ConfigSchema/Interchange.php
+++ b/library/HTMLPurifier/ConfigSchema/Interchange.php
@@ -10,18 +10,23 @@ class HTMLPurifier_ConfigSchema_Interchange
/**
* Name of the application this schema is describing.
+ * @type string
*/
public $name;
/**
* Array of Directive ID => array(directive info)
+ * @type HTMLPurifier_ConfigSchema_Interchange_Directive[]
*/
public $directives = array();
/**
* Adds a directive array to $directives
+ * @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive
+ * @throws HTMLPurifier_ConfigSchema_Exception
*/
- public function addDirective($directive) {
+ public function addDirective($directive)
+ {
if (isset($this->directives[$i = $directive->id->toString()])) {
throw new HTMLPurifier_ConfigSchema_Exception("Cannot redefine directive '$i'");
}
@@ -32,11 +37,11 @@ class HTMLPurifier_ConfigSchema_Interchange
* Convenience function to perform standard validation. Throws exception
* on failed validation.
*/
- public function validate() {
+ public function validate()
+ {
$validator = new HTMLPurifier_ConfigSchema_Validator();
return $validator->validate($this);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php b/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php
index ac8be0d97..127a39a67 100644
--- a/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php
+++ b/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php
@@ -7,71 +7,83 @@ class HTMLPurifier_ConfigSchema_Interchange_Directive
{
/**
- * ID of directive, instance of HTMLPurifier_ConfigSchema_Interchange_Id.
+ * ID of directive.
+ * @type HTMLPurifier_ConfigSchema_Interchange_Id
*/
public $id;
/**
- * String type, e.g. 'integer' or 'istring'.
+ * Type, e.g. 'integer' or 'istring'.
+ * @type string
*/
public $type;
/**
* Default value, e.g. 3 or 'DefaultVal'.
+ * @type mixed
*/
public $default;
/**
* HTML description.
+ * @type string
*/
public $description;
/**
- * Boolean whether or not null is allowed as a value.
+ * Whether or not null is allowed as a value.
+ * @type bool
*/
public $typeAllowsNull = false;
/**
- * Lookup table of allowed scalar values, e.g. array('allowed' => true).
+ * Lookup table of allowed scalar values.
+ * e.g. array('allowed' => true).
* Null if all values are allowed.
+ * @type array
*/
public $allowed;
/**
- * List of aliases for the directive,
+ * List of aliases for the directive.
* e.g. array(new HTMLPurifier_ConfigSchema_Interchange_Id('Ns', 'Dir'))).
+ * @type HTMLPurifier_ConfigSchema_Interchange_Id[]
*/
public $aliases = array();
/**
* Hash of value aliases, e.g. array('alt' => 'real'). Null if value
* aliasing is disabled (necessary for non-scalar types).
+ * @type array
*/
public $valueAliases;
/**
* Version of HTML Purifier the directive was introduced, e.g. '1.3.1'.
* Null if the directive has always existed.
+ * @type string
*/
public $version;
/**
- * ID of directive that supercedes this old directive, is an instance
- * of HTMLPurifier_ConfigSchema_Interchange_Id. Null if not deprecated.
+ * ID of directive that supercedes this old directive.
+ * Null if not deprecated.
+ * @type HTMLPurifier_ConfigSchema_Interchange_Id
*/
public $deprecatedUse;
/**
* Version of HTML Purifier this directive was deprecated. Null if not
* deprecated.
+ * @type string
*/
public $deprecatedVersion;
/**
* List of external projects this directive depends on, e.g. array('CSSTidy').
+ * @type array
*/
public $external = array();
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/Interchange/Id.php b/library/HTMLPurifier/ConfigSchema/Interchange/Id.php
index b9b3c6f5c..126f09d95 100644
--- a/library/HTMLPurifier/ConfigSchema/Interchange/Id.php
+++ b/library/HTMLPurifier/ConfigSchema/Interchange/Id.php
@@ -6,32 +6,53 @@
class HTMLPurifier_ConfigSchema_Interchange_Id
{
+ /**
+ * @type string
+ */
public $key;
- public function __construct($key) {
+ /**
+ * @param string $key
+ */
+ public function __construct($key)
+ {
$this->key = $key;
}
/**
+ * @return string
* @warning This is NOT magic, to ensure that people don't abuse SPL and
* cause problems for PHP 5.0 support.
*/
- public function toString() {
+ public function toString()
+ {
return $this->key;
}
- public function getRootNamespace() {
+ /**
+ * @return string
+ */
+ public function getRootNamespace()
+ {
return substr($this->key, 0, strpos($this->key, "."));
}
- public function getDirective() {
+ /**
+ * @return string
+ */
+ public function getDirective()
+ {
return substr($this->key, strpos($this->key, ".") + 1);
}
- public static function make($id) {
+ /**
+ * @param string $id
+ * @return HTMLPurifier_ConfigSchema_Interchange_Id
+ */
+ public static function make($id)
+ {
return new HTMLPurifier_ConfigSchema_Interchange_Id($id);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php b/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php
index 785b72ce8..655e6dd1b 100644
--- a/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php
+++ b/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php
@@ -5,21 +5,39 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
/**
* Used for processing DEFAULT, nothing else.
+ * @type HTMLPurifier_VarParser
*/
protected $varParser;
- public function __construct($varParser = null) {
+ /**
+ * @param HTMLPurifier_VarParser $varParser
+ */
+ public function __construct($varParser = null)
+ {
$this->varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native();
}
- public static function buildFromDirectory($dir = null) {
- $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder();
+ /**
+ * @param string $dir
+ * @return HTMLPurifier_ConfigSchema_Interchange
+ */
+ public static function buildFromDirectory($dir = null)
+ {
+ $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder();
$interchange = new HTMLPurifier_ConfigSchema_Interchange();
return $builder->buildDir($interchange, $dir);
}
- public function buildDir($interchange, $dir = null) {
- if (!$dir) $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema';
+ /**
+ * @param HTMLPurifier_ConfigSchema_Interchange $interchange
+ * @param string $dir
+ * @return HTMLPurifier_ConfigSchema_Interchange
+ */
+ public function buildDir($interchange, $dir = null)
+ {
+ if (!$dir) {
+ $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema';
+ }
if (file_exists($dir . '/info.ini')) {
$info = parse_ini_file($dir . '/info.ini');
$interchange->name = $info['name'];
@@ -39,24 +57,30 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
foreach ($files as $file) {
$this->buildFile($interchange, $dir . '/' . $file);
}
-
return $interchange;
}
- public function buildFile($interchange, $file) {
+ /**
+ * @param HTMLPurifier_ConfigSchema_Interchange $interchange
+ * @param string $file
+ */
+ public function buildFile($interchange, $file)
+ {
$parser = new HTMLPurifier_StringHashParser();
$this->build(
$interchange,
- new HTMLPurifier_StringHash( $parser->parseFile($file) )
+ new HTMLPurifier_StringHash($parser->parseFile($file))
);
}
/**
* Builds an interchange object based on a hash.
- * @param $interchange HTMLPurifier_ConfigSchema_Interchange object to build
- * @param $hash HTMLPurifier_ConfigSchema_StringHash source data
+ * @param HTMLPurifier_ConfigSchema_Interchange $interchange HTMLPurifier_ConfigSchema_Interchange object to build
+ * @param HTMLPurifier_StringHash $hash source data
+ * @throws HTMLPurifier_ConfigSchema_Exception
*/
- public function build($interchange, $hash) {
+ public function build($interchange, $hash)
+ {
if (!$hash instanceof HTMLPurifier_StringHash) {
$hash = new HTMLPurifier_StringHash($hash);
}
@@ -75,7 +99,13 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
$this->_findUnused($hash);
}
- public function buildDirective($interchange, $hash) {
+ /**
+ * @param HTMLPurifier_ConfigSchema_Interchange $interchange
+ * @param HTMLPurifier_StringHash $hash
+ * @throws HTMLPurifier_ConfigSchema_Exception
+ */
+ public function buildDirective($interchange, $hash)
+ {
$directive = new HTMLPurifier_ConfigSchema_Interchange_Directive();
// These are required elements:
@@ -84,7 +114,9 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
if (isset($hash['TYPE'])) {
$type = explode('/', $hash->offsetGet('TYPE'));
- if (isset($type[1])) $directive->typeAllowsNull = true;
+ if (isset($type[1])) {
+ $directive->typeAllowsNull = true;
+ }
$directive->type = $type[0];
} else {
throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined");
@@ -92,7 +124,11 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
if (isset($hash['DEFAULT'])) {
try {
- $directive->default = $this->varParser->parse($hash->offsetGet('DEFAULT'), $directive->type, $directive->typeAllowsNull);
+ $directive->default = $this->varParser->parse(
+ $hash->offsetGet('DEFAULT'),
+ $directive->type,
+ $directive->typeAllowsNull
+ );
} catch (HTMLPurifier_VarParserException $e) {
throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'");
}
@@ -139,34 +175,45 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
/**
* Evaluates an array PHP code string without array() wrapper
+ * @param string $contents
*/
- protected function evalArray($contents) {
- return eval('return array('. $contents .');');
+ protected function evalArray($contents)
+ {
+ return eval('return array(' . $contents . ');');
}
/**
* Converts an array list into a lookup array.
+ * @param array $array
+ * @return array
*/
- protected function lookup($array) {
+ protected function lookup($array)
+ {
$ret = array();
- foreach ($array as $val) $ret[$val] = true;
+ foreach ($array as $val) {
+ $ret[$val] = true;
+ }
return $ret;
}
/**
* Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id
* object based on a string Id.
+ * @param string $id
+ * @return HTMLPurifier_ConfigSchema_Interchange_Id
*/
- protected function id($id) {
+ protected function id($id)
+ {
return HTMLPurifier_ConfigSchema_Interchange_Id::make($id);
}
/**
* Triggers errors for any unused keys passed in the hash; such keys
* may indicate typos, missing values, etc.
- * @param $hash Instance of ConfigSchema_StringHash to check.
+ * @param HTMLPurifier_StringHash $hash Hash to check.
*/
- protected function _findUnused($hash) {
+ protected function _findUnused($hash)
+ {
$accessed = $hash->getAccessed();
foreach ($hash as $k => $v) {
if (!isset($accessed[$k])) {
@@ -174,7 +221,6 @@ class HTMLPurifier_ConfigSchema_InterchangeBuilder
}
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/Validator.php b/library/HTMLPurifier/ConfigSchema/Validator.php
index f374f6a02..fb3127788 100644
--- a/library/HTMLPurifier/ConfigSchema/Validator.php
+++ b/library/HTMLPurifier/ConfigSchema/Validator.php
@@ -12,36 +12,48 @@ class HTMLPurifier_ConfigSchema_Validator
{
/**
- * Easy to access global objects.
+ * @type HTMLPurifier_ConfigSchema_Interchange
*/
- protected $interchange, $aliases;
+ protected $interchange;
+
+ /**
+ * @type array
+ */
+ protected $aliases;
/**
* Context-stack to provide easy to read error messages.
+ * @type array
*/
protected $context = array();
/**
- * HTMLPurifier_VarParser to test default's type.
+ * to test default's type.
+ * @type HTMLPurifier_VarParser
*/
protected $parser;
- public function __construct() {
+ public function __construct()
+ {
$this->parser = new HTMLPurifier_VarParser();
}
/**
- * Validates a fully-formed interchange object. Throws an
- * HTMLPurifier_ConfigSchema_Exception if there's a problem.
+ * Validates a fully-formed interchange object.
+ * @param HTMLPurifier_ConfigSchema_Interchange $interchange
+ * @return bool
*/
- public function validate($interchange) {
+ public function validate($interchange)
+ {
$this->interchange = $interchange;
$this->aliases = array();
// PHP is a bit lax with integer <=> string conversions in
// arrays, so we don't use the identical !== comparison
foreach ($interchange->directives as $i => $directive) {
$id = $directive->id->toString();
- if ($i != $id) $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'");
+ if ($i != $id) {
+ $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'");
+ }
$this->validateDirective($directive);
}
return true;
@@ -49,8 +61,10 @@ class HTMLPurifier_ConfigSchema_Validator
/**
* Validates a HTMLPurifier_ConfigSchema_Interchange_Id object.
+ * @param HTMLPurifier_ConfigSchema_Interchange_Id $id
*/
- public function validateId($id) {
+ public function validateId($id)
+ {
$id_string = $id->toString();
$this->context[] = "id '$id_string'";
if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) {
@@ -67,8 +81,10 @@ class HTMLPurifier_ConfigSchema_Validator
/**
* Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object.
+ * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
*/
- public function validateDirective($d) {
+ public function validateDirective($d)
+ {
$id = $d->id->toString();
$this->context[] = "directive '$id'";
$this->validateId($d->id);
@@ -108,9 +124,13 @@ class HTMLPurifier_ConfigSchema_Validator
/**
* Extra validation if $allowed member variable of
* HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
+ * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
*/
- public function validateDirectiveAllowed($d) {
- if (is_null($d->allowed)) return;
+ public function validateDirectiveAllowed($d)
+ {
+ if (is_null($d->allowed)) {
+ return;
+ }
$this->with($d, 'allowed')
->assertNotEmpty()
->assertIsLookup(); // handled by InterchangeBuilder
@@ -119,7 +139,9 @@ class HTMLPurifier_ConfigSchema_Validator
}
$this->context[] = 'allowed';
foreach ($d->allowed as $val => $x) {
- if (!is_string($val)) $this->error("value $val", 'must be a string');
+ if (!is_string($val)) {
+ $this->error("value $val", 'must be a string');
+ }
}
array_pop($this->context);
}
@@ -127,15 +149,23 @@ class HTMLPurifier_ConfigSchema_Validator
/**
* Extra validation if $valueAliases member variable of
* HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
+ * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
*/
- public function validateDirectiveValueAliases($d) {
- if (is_null($d->valueAliases)) return;
+ public function validateDirectiveValueAliases($d)
+ {
+ if (is_null($d->valueAliases)) {
+ return;
+ }
$this->with($d, 'valueAliases')
->assertIsArray(); // handled by InterchangeBuilder
$this->context[] = 'valueAliases';
foreach ($d->valueAliases as $alias => $real) {
- if (!is_string($alias)) $this->error("alias $alias", 'must be a string');
- if (!is_string($real)) $this->error("alias target $real from alias '$alias'", 'must be a string');
+ if (!is_string($alias)) {
+ $this->error("alias $alias", 'must be a string');
+ }
+ if (!is_string($real)) {
+ $this->error("alias target $real from alias '$alias'", 'must be a string');
+ }
if ($alias === $real) {
$this->error("alias '$alias'", "must not be an alias to itself");
}
@@ -155,8 +185,10 @@ class HTMLPurifier_ConfigSchema_Validator
/**
* Extra validation if $aliases member variable of
* HTMLPurifier_ConfigSchema_Interchange_Directive is defined.
+ * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d
*/
- public function validateDirectiveAliases($d) {
+ public function validateDirectiveAliases($d)
+ {
$this->with($d, 'aliases')
->assertIsArray(); // handled by InterchangeBuilder
$this->context[] = 'aliases';
@@ -180,27 +212,37 @@ class HTMLPurifier_ConfigSchema_Validator
/**
* Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom
* for validating simple member variables of objects.
+ * @param $obj
+ * @param $member
+ * @return HTMLPurifier_ConfigSchema_ValidatorAtom
*/
- protected function with($obj, $member) {
+ protected function with($obj, $member)
+ {
return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member);
}
/**
* Emits an error, providing helpful context.
+ * @throws HTMLPurifier_ConfigSchema_Exception
*/
- protected function error($target, $msg) {
- if ($target !== false) $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext();
- else $prefix = ucfirst($this->getFormattedContext());
+ protected function error($target, $msg)
+ {
+ if ($target !== false) {
+ $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext();
+ } else {
+ $prefix = ucfirst($this->getFormattedContext());
+ }
throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg));
}
/**
* Returns a formatted context string.
+ * @return string
*/
- protected function getFormattedContext() {
+ protected function getFormattedContext()
+ {
return implode(' in ', array_reverse($this->context));
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php
index b95aea18c..c9aa3644a 100644
--- a/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php
+++ b/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php
@@ -8,59 +8,123 @@
*/
class HTMLPurifier_ConfigSchema_ValidatorAtom
{
+ /**
+ * @type string
+ */
+ protected $context;
- protected $context, $obj, $member, $contents;
+ /**
+ * @type object
+ */
+ protected $obj;
- public function __construct($context, $obj, $member) {
- $this->context = $context;
- $this->obj = $obj;
- $this->member = $member;
- $this->contents =& $obj->$member;
+ /**
+ * @type string
+ */
+ protected $member;
+
+ /**
+ * @type mixed
+ */
+ protected $contents;
+
+ public function __construct($context, $obj, $member)
+ {
+ $this->context = $context;
+ $this->obj = $obj;
+ $this->member = $member;
+ $this->contents =& $obj->$member;
}
- public function assertIsString() {
- if (!is_string($this->contents)) $this->error('must be a string');
+ /**
+ * @return HTMLPurifier_ConfigSchema_ValidatorAtom
+ */
+ public function assertIsString()
+ {
+ if (!is_string($this->contents)) {
+ $this->error('must be a string');
+ }
return $this;
}
- public function assertIsBool() {
- if (!is_bool($this->contents)) $this->error('must be a boolean');
+ /**
+ * @return HTMLPurifier_ConfigSchema_ValidatorAtom
+ */
+ public function assertIsBool()
+ {
+ if (!is_bool($this->contents)) {
+ $this->error('must be a boolean');
+ }
return $this;
}
- public function assertIsArray() {
- if (!is_array($this->contents)) $this->error('must be an array');
+ /**
+ * @return HTMLPurifier_ConfigSchema_ValidatorAtom
+ */
+ public function assertIsArray()
+ {
+ if (!is_array($this->contents)) {
+ $this->error('must be an array');
+ }
return $this;
}
- public function assertNotNull() {
- if ($this->contents === null) $this->error('must not be null');
+ /**
+ * @return HTMLPurifier_ConfigSchema_ValidatorAtom
+ */
+ public function assertNotNull()
+ {
+ if ($this->contents === null) {
+ $this->error('must not be null');
+ }
return $this;
}
- public function assertAlnum() {
+ /**
+ * @return HTMLPurifier_ConfigSchema_ValidatorAtom
+ */
+ public function assertAlnum()
+ {
$this->assertIsString();
- if (!ctype_alnum($this->contents)) $this->error('must be alphanumeric');
+ if (!ctype_alnum($this->contents)) {
+ $this->error('must be alphanumeric');
+ }
return $this;
}
- public function assertNotEmpty() {
- if (empty($this->contents)) $this->error('must not be empty');
+ /**
+ * @return HTMLPurifier_ConfigSchema_ValidatorAtom
+ */
+ public function assertNotEmpty()
+ {
+ if (empty($this->contents)) {
+ $this->error('must not be empty');
+ }
return $this;
}
- public function assertIsLookup() {
+ /**
+ * @return HTMLPurifier_ConfigSchema_ValidatorAtom
+ */
+ public function assertIsLookup()
+ {
$this->assertIsArray();
foreach ($this->contents as $v) {
- if ($v !== true) $this->error('must be a lookup array');
+ if ($v !== true) {
+ $this->error('must be a lookup array');
+ }
}
return $this;
}
- protected function error($msg) {
+ /**
+ * @param string $msg
+ * @throws HTMLPurifier_ConfigSchema_Exception
+ */
+ protected function error($msg)
+ {
throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema.ser b/library/HTMLPurifier/ConfigSchema/schema.ser
index 22b8d54a5..22ea32185 100644
--- a/library/HTMLPurifier/ConfigSchema/schema.ser
+++ b/library/HTMLPurifier/ConfigSchema/schema.ser
Binary files differ
diff --git a/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt b/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt
new file mode 100644
index 000000000..3fd465406
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt
@@ -0,0 +1,12 @@
+CSS.AllowedFonts
+TYPE: lookup/null
+VERSION: 4.3.0
+DEFAULT: NULL
+--DESCRIPTION--
+<p>
+ Allows you to manually specify a set of allowed fonts. If
+ <code>NULL</code>, all fonts are allowed. This directive
+ affects generic names (serif, sans-serif, monospace, cursive,
+ fantasy) as well as specific font families.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt b/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt
new file mode 100644
index 000000000..f1f5c5f12
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt
@@ -0,0 +1,13 @@
+CSS.ForbiddenProperties
+TYPE: lookup
+VERSION: 4.2.0
+DEFAULT: array()
+--DESCRIPTION--
+<p>
+ This is the logical inverse of %CSS.AllowedProperties, and it will
+ override that directive or any other directive. If possible,
+ %CSS.AllowedProperties is recommended over this directive,
+ because it can sometimes be difficult to tell whether or not you've
+ forbidden all of the CSS properties you truly would like to disallow.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt b/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt
new file mode 100644
index 000000000..e733a61e8
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt
@@ -0,0 +1,9 @@
+CSS.Trusted
+TYPE: bool
+VERSION: 4.2.1
+DEFAULT: false
+--DESCRIPTION--
+Indicates whether or not the user's CSS input is trusted or not. If the
+input is trusted, a more expansive set of allowed properties. See
+also %HTML.Trusted.
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt b/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt
new file mode 100644
index 000000000..b2b83d9ab
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt
@@ -0,0 +1,11 @@
+Cache.SerializerPermissions
+TYPE: int
+VERSION: 4.3.0
+DEFAULT: 0755
+--DESCRIPTION--
+
+<p>
+ Directory permissions of the files and directories created inside
+ the DefinitionCache/Serializer or other custom serializer path.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt b/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt
new file mode 100644
index 000000000..2c910cc7d
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt
@@ -0,0 +1,16 @@
+Core.AllowHostnameUnderscore
+TYPE: bool
+VERSION: 4.6.0
+DEFAULT: false
+--DESCRIPTION--
+<p>
+ By RFC 1123, underscores are not permitted in host names.
+ (This is in contrast to the specification for DNS, RFC
+ 2181, which allows underscores.)
+ However, most browsers do the right thing when faced with
+ an underscore in the host name, and so some poorly written
+ websites are written with the expectation this should work.
+ Setting this parameter to true relaxes our allowed character
+ check so that underscores are permitted.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt b/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt
index 08b381d34..c572c14ec 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt
@@ -24,5 +24,6 @@ array (
--DESCRIPTION--
Lookup array of color names to six digit hexadecimal number corresponding
-to color, with preceding hash mark. Used when parsing colors.
+to color, with preceding hash mark. Used when parsing colors. The lookup
+is done in a case-insensitive manner.
--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt b/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt
new file mode 100644
index 000000000..1cd4c2c96
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt
@@ -0,0 +1,14 @@
+Core.DisableExcludes
+TYPE: bool
+DEFAULT: false
+VERSION: 4.5.0
+--DESCRIPTION--
+<p>
+ This directive disables SGML-style exclusions, e.g. the exclusion of
+ <code>&lt;object&gt;</code> in any descendant of a
+ <code>&lt;pre&gt;</code> tag. Disabling excludes will allow some
+ invalid documents to pass through HTML Purifier, but HTML Purifier
+ will also be less likely to accidentally remove large documents during
+ processing.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt b/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt
new file mode 100644
index 000000000..ce243c35d
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt
@@ -0,0 +1,9 @@
+Core.EnableIDNA
+TYPE: bool
+DEFAULT: false
+VERSION: 4.4.0
+--DESCRIPTION--
+Allows international domain names in URLs. This configuration option
+requires the PEAR Net_IDNA2 module to be installed. It operates by
+punycoding any internationalized host names for maximum portability.
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt b/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt
index 4d5b5055c..a3881be75 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt
@@ -2,9 +2,11 @@ Core.EscapeInvalidChildren
TYPE: bool
DEFAULT: false
--DESCRIPTION--
-When true, a child is found that is not allowed in the context of the
+<p><strong>Warning:</strong> this configuration option is no longer does anything as of 4.6.0.</p>
+
+<p>When true, a child is found that is not allowed in the context of the
parent element will be transformed into text as if it were ASCII. When
false, that element and all internal tags will be dropped, though text will
be preserved. There is no option for dropping the element but preserving
-child nodes.
+child nodes.</p>
--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt b/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt
new file mode 100644
index 000000000..d77f5360d
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt
@@ -0,0 +1,11 @@
+Core.NormalizeNewlines
+TYPE: bool
+VERSION: 4.2.0
+DEFAULT: true
+--DESCRIPTION--
+<p>
+ Whether or not to normalize newlines to the operating
+ system default. When <code>false</code>, HTML Purifier
+ will attempt to preserve mixed newline files.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt b/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt
new file mode 100644
index 000000000..3397d9f71
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt
@@ -0,0 +1,11 @@
+Core.RemoveProcessingInstructions
+TYPE: bool
+VERSION: 4.2.0
+DEFAULT: false
+--DESCRIPTION--
+Instead of escaping processing instructions in the form <code>&lt;? ...
+?&gt;</code>, remove it out-right. This may be useful if the HTML
+you are validating contains XML processing instruction gunk, however,
+it can also be user-unfriendly for people attempting to post PHP
+snippets.
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt b/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt
index 7fa6536b2..321eaa2d8 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt
@@ -4,6 +4,11 @@ VERSION: 3.1.0
DEFAULT: false
--DESCRIPTION--
<p>
+ <strong>Warning:</strong> Deprecated in favor of %HTML.SafeObject and
+ %Output.FlashCompat (turn both on to allow YouTube videos and other
+ Flash content).
+</p>
+<p>
This directive enables YouTube video embedding in HTML Purifier. Check
<a href="http://htmlpurifier.org/docs/enduser-youtube.html">this document
on embedding videos</a> for more information on what this filter does.
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt
index 3e231d2d1..0b2c106da 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt
@@ -5,11 +5,14 @@ DEFAULT: NULL
--DESCRIPTION--
<p>
- This is a convenience directive that rolls the functionality of
- %HTML.AllowedElements and %HTML.AllowedAttributes into one directive.
+ This is a preferred convenience directive that combines
+ %HTML.AllowedElements and %HTML.AllowedAttributes.
Specify elements and attributes that are allowed using:
- <code>element1[attr1|attr2],element2...</code>. You can also use
- newlines instead of commas to separate elements.
+ <code>element1[attr1|attr2],element2...</code>. For example,
+ if you would like to only allow paragraphs and links, specify
+ <code>a[href],p</code>. You can specify attributes that apply
+ to all elements using an asterisk, e.g. <code>*[lang]</code>.
+ You can also use newlines instead of commas to separate elements.
</p>
<p>
<strong>Warning</strong>:
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt
new file mode 100644
index 000000000..140e21423
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt
@@ -0,0 +1,10 @@
+HTML.AllowedComments
+TYPE: lookup
+VERSION: 4.4.0
+DEFAULT: array()
+--DESCRIPTION--
+A whitelist which indicates what explicit comment bodies should be
+allowed, modulo leading and trailing whitespace. See also %HTML.AllowedCommentsRegexp
+(these directives are union'ed together, so a comment is considered
+valid if any directive deems it valid.)
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt
new file mode 100644
index 000000000..f22e977d4
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt
@@ -0,0 +1,15 @@
+HTML.AllowedCommentsRegexp
+TYPE: string/null
+VERSION: 4.4.0
+DEFAULT: NULL
+--DESCRIPTION--
+A regexp, which if it matches the body of a comment, indicates that
+it should be allowed. Trailing and leading spaces are removed prior
+to running this regular expression.
+<strong>Warning:</strong> Make sure you specify
+correct anchor metacharacters <code>^regex$</code>, otherwise you may accept
+comments that you did not mean to! In particular, the regex <code>/foo|bar/</code>
+is probably not sufficiently strict, since it also allows <code>foobar</code>.
+See also %HTML.AllowedComments (these directives are union'ed together,
+so a comment is considered valid if any directive deems it valid.)
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt
index 888d55819..1d3fa7907 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt
@@ -4,12 +4,17 @@ VERSION: 1.3.0
DEFAULT: NULL
--DESCRIPTION--
<p>
- If HTML Purifier's tag set is unsatisfactory for your needs, you
- can overload it with your own list of tags to allow. Note that this
- method is subtractive: it does its job by taking away from HTML Purifier
- usual feature set, so you cannot add a tag that HTML Purifier never
- supported in the first place (like embed, form or head). If you
- change this, you probably also want to change %HTML.AllowedAttributes.
+ If HTML Purifier's tag set is unsatisfactory for your needs, you can
+ overload it with your own list of tags to allow. If you change
+ this, you probably also want to change %HTML.AllowedAttributes; see
+ also %HTML.Allowed which lets you set allowed elements and
+ attributes at the same time.
+</p>
+<p>
+ If you attempt to allow an element that HTML Purifier does not know
+ about, HTML Purifier will raise an error. You will need to manually
+ tell HTML Purifier about this element by using the
+ <a href="http://htmlpurifier.org/docs/enduser-customize.html">advanced customization features.</a>
</p>
<p>
<strong>Warning:</strong> If another directive conflicts with the
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt
new file mode 100644
index 000000000..7878dc0bf
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt
@@ -0,0 +1,11 @@
+HTML.FlashAllowFullScreen
+TYPE: bool
+VERSION: 4.2.0
+DEFAULT: false
+--DESCRIPTION--
+<p>
+ Whether or not to permit embedded Flash content from
+ %HTML.SafeObject to expand to the full screen. Corresponds to
+ the <code>allowFullScreen</code> parameter.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt
new file mode 100644
index 000000000..700b30924
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt
@@ -0,0 +1,7 @@
+HTML.Nofollow
+TYPE: bool
+VERSION: 4.3.0
+DEFAULT: FALSE
+--DESCRIPTION--
+If enabled, nofollow rel attributes are added to all outgoing links.
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt
new file mode 100644
index 000000000..5eb6ec2b5
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt
@@ -0,0 +1,13 @@
+HTML.SafeIframe
+TYPE: bool
+VERSION: 4.4.0
+DEFAULT: false
+--DESCRIPTION--
+<p>
+ Whether or not to permit iframe tags in untrusted documents. This
+ directive must be accompanied by a whitelist of permitted iframes,
+ such as %URI.SafeIframeRegexp, otherwise it will fatally error.
+ This directive has no effect on strict doctypes, as iframes are not
+ valid.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt
new file mode 100644
index 000000000..5ebc7a19d
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt
@@ -0,0 +1,10 @@
+HTML.SafeScripting
+TYPE: lookup
+VERSION: 4.5.0
+DEFAULT: array()
+--DESCRIPTION--
+<p>
+ Whether or not to permit script tags to external scripts in documents.
+ Inline scripting is not allowed, and the script must match an explicit whitelist.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt
new file mode 100644
index 000000000..587a16778
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt
@@ -0,0 +1,8 @@
+HTML.TargetBlank
+TYPE: bool
+VERSION: 4.4.0
+DEFAULT: FALSE
+--DESCRIPTION--
+If enabled, <code>target=blank</code> attributes are added to all outgoing links.
+(This includes links from an HTTPS version of a page to an HTTP version.)
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt b/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt
index 89133b1a3..1db9237e9 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt
@@ -5,4 +5,5 @@ DEFAULT: false
--DESCRIPTION--
Indicates whether or not the user input is trusted or not. If the input is
trusted, a more expansive set of allowed tags and attributes will be used.
+See also %CSS.Trusted.
--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt b/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt
new file mode 100644
index 000000000..d6f0d9f29
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt
@@ -0,0 +1,15 @@
+Output.FixInnerHTML
+TYPE: bool
+VERSION: 4.3.0
+DEFAULT: true
+--DESCRIPTION--
+<p>
+ If true, HTML Purifier will protect against Internet Explorer's
+ mishandling of the <code>innerHTML</code> attribute by appending
+ a space to any attribute that does not contain angled brackets, spaces
+ or quotes, but contains a backtick. This slightly changes the
+ semantics of any given attribute, so if this is unacceptable and
+ you do not use <code>innerHTML</code> on any of your pages, you can
+ turn this directive off.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt b/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt
index ae3a913f2..666635a5f 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt
@@ -12,6 +12,6 @@ array (
--DESCRIPTION--
Whitelist that defines the schemes that a URI is allowed to have. This
prevents XSS attacks from using pseudo-schemes like javascript or mocha.
-There is also support for the <code>data</code> URI scheme, but it is not
-enabled by default.
+There is also support for the <code>data</code> and <code>file</code>
+URI schemes, but they are not enabled by default.
--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt b/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt
index 51e6ea91f..f891de499 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt
@@ -1,12 +1,15 @@
URI.DisableResources
TYPE: bool
-VERSION: 1.3.0
+VERSION: 4.2.0
DEFAULT: false
--DESCRIPTION--
-
<p>
Disables embedding resources, essentially meaning no pictures. You can
still link to them though. See %URI.DisableExternalResources for why
this might be a good idea.
</p>
+<p>
+ <em>Note:</em> While this directive has been available since 1.3.0,
+ it didn't actually start doing anything until 4.2.0.
+</p>
--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt b/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt
index 0d00f62ea..1e17c1d46 100644
--- a/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt
+++ b/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt
@@ -11,7 +11,7 @@ DEFAULT: NULL
to check if a URI has passed through HTML Purifier with this line:
</p>
-<pre>$checksum === sha1($secret_key . ':' . $url)</pre>
+<pre>$checksum === hash_hmac("sha256", $url, $secret_key)</pre>
<p>
If the output is TRUE, the redirector script should accept the URI.
diff --git a/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt b/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt
new file mode 100644
index 000000000..79084832b
--- /dev/null
+++ b/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt
@@ -0,0 +1,22 @@
+URI.SafeIframeRegexp
+TYPE: string/null
+VERSION: 4.4.0
+DEFAULT: NULL
+--DESCRIPTION--
+<p>
+ A PCRE regular expression that will be matched against an iframe URI. This is
+ a relatively inflexible scheme, but works well enough for the most common
+ use-case of iframes: embedded video. This directive only has an effect if
+ %HTML.SafeIframe is enabled. Here are some example values:
+</p>
+<ul>
+ <li><code>%^http://www.youtube.com/embed/%</code> - Allow YouTube videos</li>
+ <li><code>%^http://player.vimeo.com/video/%</code> - Allow Vimeo videos</li>
+ <li><code>%^http://(www.youtube.com/embed/|player.vimeo.com/video/)%</code> - Allow both</li>
+</ul>
+<p>
+ Note that this directive does not give you enough granularity to, say, disable
+ all <code>autoplay</code> videos. Pipe up on the HTML Purifier forums if this
+ is a capability you want.
+</p>
+--# vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ContentSets.php b/library/HTMLPurifier/ContentSets.php
index 3b6e96f5f..543e3f8f1 100644
--- a/library/HTMLPurifier/ContentSets.php
+++ b/library/HTMLPurifier/ContentSets.php
@@ -7,35 +7,42 @@ class HTMLPurifier_ContentSets
{
/**
- * List of content set strings (pipe seperators) indexed by name.
+ * List of content set strings (pipe separators) indexed by name.
+ * @type array
*/
public $info = array();
/**
* List of content set lookups (element => true) indexed by name.
+ * @type array
* @note This is in HTMLPurifier_HTMLDefinition->info_content_sets
*/
public $lookup = array();
/**
- * Synchronized list of defined content sets (keys of info)
+ * Synchronized list of defined content sets (keys of info).
+ * @type array
*/
protected $keys = array();
/**
- * Synchronized list of defined content values (values of info)
+ * Synchronized list of defined content values (values of info).
+ * @type array
*/
protected $values = array();
/**
* Merges in module's content sets, expands identifiers in the content
* sets and populates the keys, values and lookup member variables.
- * @param $modules List of HTMLPurifier_HTMLModule
+ * @param HTMLPurifier_HTMLModule[] $modules List of HTMLPurifier_HTMLModule
*/
- public function __construct($modules) {
- if (!is_array($modules)) $modules = array($modules);
+ public function __construct($modules)
+ {
+ if (!is_array($modules)) {
+ $modules = array($modules);
+ }
// populate content_sets based on module hints
// sorry, no way of overloading
- foreach ($modules as $module_i => $module) {
+ foreach ($modules as $module) {
foreach ($module->content_sets as $key => $value) {
$temp = $this->convertToLookup($value);
if (isset($this->lookup[$key])) {
@@ -70,11 +77,14 @@ class HTMLPurifier_ContentSets
/**
* Accepts a definition; generates and assigns a ChildDef for it
- * @param $def HTMLPurifier_ElementDef reference
- * @param $module Module that defined the ElementDef
+ * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef reference
+ * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef
*/
- public function generateChildDef(&$def, $module) {
- if (!empty($def->child)) return; // already done!
+ public function generateChildDef(&$def, $module)
+ {
+ if (!empty($def->child)) { // already done!
+ return;
+ }
$content_model = $def->content_model;
if (is_string($content_model)) {
// Assume that $this->keys is alphanumeric
@@ -89,7 +99,8 @@ class HTMLPurifier_ContentSets
$def->child = $this->getChildDef($def, $module);
}
- public function generateChildDefCallback($matches) {
+ public function generateChildDefCallback($matches)
+ {
return $this->info[$matches[0]];
}
@@ -98,10 +109,12 @@ class HTMLPurifier_ContentSets
* member variables in HTMLPurifier_ElementDef
* @note This will also defer to modules for custom HTMLPurifier_ChildDef
* subclasses that need content set expansion
- * @param $def HTMLPurifier_ElementDef to have ChildDef extracted
+ * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef to have ChildDef extracted
+ * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef
* @return HTMLPurifier_ChildDef corresponding to ElementDef
*/
- public function getChildDef($def, $module) {
+ public function getChildDef($def, $module)
+ {
$value = $def->content_model;
if (is_object($value)) {
trigger_error(
@@ -126,7 +139,9 @@ class HTMLPurifier_ContentSets
if ($module->defines_child_def) { // save a func call
$return = $module->getChildDef($def);
}
- if ($return !== false) return $return;
+ if ($return !== false) {
+ return $return;
+ }
// error-out
trigger_error(
'Could not determine which ChildDef class to instantiate',
@@ -138,18 +153,18 @@ class HTMLPurifier_ContentSets
/**
* Converts a string list of elements separated by pipes into
* a lookup array.
- * @param $string List of elements
- * @return Lookup array of elements
+ * @param string $string List of elements
+ * @return array Lookup array of elements
*/
- protected function convertToLookup($string) {
+ protected function convertToLookup($string)
+ {
$array = explode('|', str_replace(' ', '', $string));
$ret = array();
- foreach ($array as $i => $k) {
+ foreach ($array as $k) {
$ret[$k] = true;
}
return $ret;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Context.php b/library/HTMLPurifier/Context.php
index 9ddf0c547..00e509c85 100644
--- a/library/HTMLPurifier/Context.php
+++ b/library/HTMLPurifier/Context.php
@@ -12,18 +12,22 @@ class HTMLPurifier_Context
/**
* Private array that stores the references.
+ * @type array
*/
private $_storage = array();
/**
* Registers a variable into the context.
- * @param $name String name
- * @param $ref Reference to variable to be registered
+ * @param string $name String name
+ * @param mixed $ref Reference to variable to be registered
*/
- public function register($name, &$ref) {
- if (isset($this->_storage[$name])) {
- trigger_error("Name $name produces collision, cannot re-register",
- E_USER_ERROR);
+ public function register($name, &$ref)
+ {
+ if (array_key_exists($name, $this->_storage)) {
+ trigger_error(
+ "Name $name produces collision, cannot re-register",
+ E_USER_ERROR
+ );
return;
}
$this->_storage[$name] =& $ref;
@@ -31,14 +35,18 @@ class HTMLPurifier_Context
/**
* Retrieves a variable reference from the context.
- * @param $name String name
- * @param $ignore_error Boolean whether or not to ignore error
+ * @param string $name String name
+ * @param bool $ignore_error Boolean whether or not to ignore error
+ * @return mixed
*/
- public function &get($name, $ignore_error = false) {
- if (!isset($this->_storage[$name])) {
+ public function &get($name, $ignore_error = false)
+ {
+ if (!array_key_exists($name, $this->_storage)) {
if (!$ignore_error) {
- trigger_error("Attempted to retrieve non-existent variable $name",
- E_USER_ERROR);
+ trigger_error(
+ "Attempted to retrieve non-existent variable $name",
+ E_USER_ERROR
+ );
}
$var = null; // so we can return by reference
return $var;
@@ -47,13 +55,16 @@ class HTMLPurifier_Context
}
/**
- * Destorys a variable in the context.
- * @param $name String name
+ * Destroys a variable in the context.
+ * @param string $name String name
*/
- public function destroy($name) {
- if (!isset($this->_storage[$name])) {
- trigger_error("Attempted to destroy non-existent variable $name",
- E_USER_ERROR);
+ public function destroy($name)
+ {
+ if (!array_key_exists($name, $this->_storage)) {
+ trigger_error(
+ "Attempted to destroy non-existent variable $name",
+ E_USER_ERROR
+ );
return;
}
unset($this->_storage[$name]);
@@ -61,22 +72,24 @@ class HTMLPurifier_Context
/**
* Checks whether or not the variable exists.
- * @param $name String name
+ * @param string $name String name
+ * @return bool
*/
- public function exists($name) {
- return isset($this->_storage[$name]);
+ public function exists($name)
+ {
+ return array_key_exists($name, $this->_storage);
}
/**
* Loads a series of variables from an associative array
- * @param $context_array Assoc array of variables to load
+ * @param array $context_array Assoc array of variables to load
*/
- public function loadArray($context_array) {
+ public function loadArray($context_array)
+ {
foreach ($context_array as $key => $discard) {
$this->register($key, $context_array[$key]);
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Definition.php b/library/HTMLPurifier/Definition.php
index a7408c974..bc6d43364 100644
--- a/library/HTMLPurifier/Definition.php
+++ b/library/HTMLPurifier/Definition.php
@@ -9,31 +9,47 @@ abstract class HTMLPurifier_Definition
/**
* Has setup() been called yet?
+ * @type bool
*/
public $setup = false;
/**
+ * If true, write out the final definition object to the cache after
+ * setup. This will be true only if all invocations to get a raw
+ * definition object are also optimized. This does not cause file
+ * system thrashing because on subsequent calls the cached object
+ * is used and any writes to the raw definition object are short
+ * circuited. See enduser-customize.html for the high-level
+ * picture.
+ * @type bool
+ */
+ public $optimized = null;
+
+ /**
* What type of definition is it?
+ * @type string
*/
public $type;
/**
* Sets up the definition object into the final form, something
* not done by the constructor
- * @param $config HTMLPurifier_Config instance
+ * @param HTMLPurifier_Config $config
*/
abstract protected function doSetup($config);
/**
* Setup function that aborts if already setup
- * @param $config HTMLPurifier_Config instance
+ * @param HTMLPurifier_Config $config
*/
- public function setup($config) {
- if ($this->setup) return;
+ public function setup($config)
+ {
+ if ($this->setup) {
+ return;
+ }
$this->setup = true;
$this->doSetup($config);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/DefinitionCache.php b/library/HTMLPurifier/DefinitionCache.php
index c6e1e388c..67bb5b1e6 100644
--- a/library/HTMLPurifier/DefinitionCache.php
+++ b/library/HTMLPurifier/DefinitionCache.php
@@ -10,22 +10,27 @@
*/
abstract class HTMLPurifier_DefinitionCache
{
-
+ /**
+ * @type string
+ */
public $type;
/**
- * @param $name Type of definition objects this instance of the
+ * @param string $type Type of definition objects this instance of the
* cache will handle.
*/
- public function __construct($type) {
+ public function __construct($type)
+ {
$this->type = $type;
}
/**
* Generates a unique identifier for a particular configuration
- * @param Instance of HTMLPurifier_Config
+ * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config
+ * @return string
*/
- public function generateKey($config) {
+ public function generateKey($config)
+ {
return $config->version . ',' . // possibly replace with function calls
$config->getBatchSerial($this->type) . ',' .
$config->get($this->type . '.DefinitionRev');
@@ -34,30 +39,37 @@ abstract class HTMLPurifier_DefinitionCache
/**
* Tests whether or not a key is old with respect to the configuration's
* version and revision number.
- * @param $key Key to test
- * @param $config Instance of HTMLPurifier_Config to test against
+ * @param string $key Key to test
+ * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config to test against
+ * @return bool
*/
- public function isOld($key, $config) {
- if (substr_count($key, ',') < 2) return true;
+ public function isOld($key, $config)
+ {
+ if (substr_count($key, ',') < 2) {
+ return true;
+ }
list($version, $hash, $revision) = explode(',', $key, 3);
$compare = version_compare($version, $config->version);
// version mismatch, is always old
- if ($compare != 0) return true;
+ if ($compare != 0) {
+ return true;
+ }
// versions match, ids match, check revision number
- if (
- $hash == $config->getBatchSerial($this->type) &&
- $revision < $config->get($this->type . '.DefinitionRev')
- ) return true;
+ if ($hash == $config->getBatchSerial($this->type) &&
+ $revision < $config->get($this->type . '.DefinitionRev')) {
+ return true;
+ }
return false;
}
/**
* Checks if a definition's type jives with the cache's type
* @note Throws an error on failure
- * @param $def Definition object to check
- * @return Boolean true if good, false if not
+ * @param HTMLPurifier_Definition $def Definition object to check
+ * @return bool true if good, false if not
*/
- public function checkDefType($def) {
+ public function checkDefType($def)
+ {
if ($def->type !== $this->type) {
trigger_error("Cannot use definition of type {$def->type} in cache for {$this->type}");
return false;
@@ -67,31 +79,40 @@ abstract class HTMLPurifier_DefinitionCache
/**
* Adds a definition object to the cache
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
*/
abstract public function add($def, $config);
/**
* Unconditionally saves a definition object to the cache
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
*/
abstract public function set($def, $config);
/**
* Replace an object in the cache
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
*/
abstract public function replace($def, $config);
/**
* Retrieves a definition object from the cache
+ * @param HTMLPurifier_Config $config
*/
abstract public function get($config);
/**
* Removes a definition object to the cache
+ * @param HTMLPurifier_Config $config
*/
abstract public function remove($config);
/**
* Clears all objects from cache
+ * @param HTMLPurifier_Config $config
*/
abstract public function flush($config);
@@ -100,9 +121,9 @@ abstract class HTMLPurifier_DefinitionCache
* @note Be carefuly implementing this method as flush. Flush must
* not interfere with other Definition types, and cleanup()
* should not be repeatedly called by userland code.
+ * @param HTMLPurifier_Config $config
*/
abstract public function cleanup($config);
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/DefinitionCache/Decorator.php b/library/HTMLPurifier/DefinitionCache/Decorator.php
index b0fb6d0cd..b57a51b6c 100644
--- a/library/HTMLPurifier/DefinitionCache/Decorator.php
+++ b/library/HTMLPurifier/DefinitionCache/Decorator.php
@@ -5,58 +5,108 @@ class HTMLPurifier_DefinitionCache_Decorator extends HTMLPurifier_DefinitionCach
/**
* Cache object we are decorating
+ * @type HTMLPurifier_DefinitionCache
*/
public $cache;
- public function __construct() {}
+ /**
+ * The name of the decorator
+ * @var string
+ */
+ public $name;
+
+ public function __construct()
+ {
+ }
/**
* Lazy decorator function
- * @param $cache Reference to cache object to decorate
+ * @param HTMLPurifier_DefinitionCache $cache Reference to cache object to decorate
+ * @return HTMLPurifier_DefinitionCache_Decorator
*/
- public function decorate(&$cache) {
+ public function decorate(&$cache)
+ {
$decorator = $this->copy();
// reference is necessary for mocks in PHP 4
$decorator->cache =& $cache;
- $decorator->type = $cache->type;
+ $decorator->type = $cache->type;
return $decorator;
}
/**
* Cross-compatible clone substitute
+ * @return HTMLPurifier_DefinitionCache_Decorator
*/
- public function copy() {
+ public function copy()
+ {
return new HTMLPurifier_DefinitionCache_Decorator();
}
- public function add($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function add($def, $config)
+ {
return $this->cache->add($def, $config);
}
- public function set($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function set($def, $config)
+ {
return $this->cache->set($def, $config);
}
- public function replace($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function replace($def, $config)
+ {
return $this->cache->replace($def, $config);
}
- public function get($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function get($config)
+ {
return $this->cache->get($config);
}
- public function remove($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function remove($config)
+ {
return $this->cache->remove($config);
}
- public function flush($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function flush($config)
+ {
return $this->cache->flush($config);
}
- public function cleanup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function cleanup($config)
+ {
return $this->cache->cleanup($config);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php
index d4cc35c4b..4991777ce 100644
--- a/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php
+++ b/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php
@@ -4,40 +4,75 @@
* Definition cache decorator class that cleans up the cache
* whenever there is a cache miss.
*/
-class HTMLPurifier_DefinitionCache_Decorator_Cleanup extends
- HTMLPurifier_DefinitionCache_Decorator
+class HTMLPurifier_DefinitionCache_Decorator_Cleanup extends HTMLPurifier_DefinitionCache_Decorator
{
-
+ /**
+ * @type string
+ */
public $name = 'Cleanup';
- public function copy() {
+ /**
+ * @return HTMLPurifier_DefinitionCache_Decorator_Cleanup
+ */
+ public function copy()
+ {
return new HTMLPurifier_DefinitionCache_Decorator_Cleanup();
}
- public function add($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function add($def, $config)
+ {
$status = parent::add($def, $config);
- if (!$status) parent::cleanup($config);
+ if (!$status) {
+ parent::cleanup($config);
+ }
return $status;
}
- public function set($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function set($def, $config)
+ {
$status = parent::set($def, $config);
- if (!$status) parent::cleanup($config);
+ if (!$status) {
+ parent::cleanup($config);
+ }
return $status;
}
- public function replace($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function replace($def, $config)
+ {
$status = parent::replace($def, $config);
- if (!$status) parent::cleanup($config);
+ if (!$status) {
+ parent::cleanup($config);
+ }
return $status;
}
- public function get($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function get($config)
+ {
$ret = parent::get($config);
- if (!$ret) parent::cleanup($config);
+ if (!$ret) {
+ parent::cleanup($config);
+ }
return $ret;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php b/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php
index 18f16d32b..d529dce48 100644
--- a/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php
+++ b/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php
@@ -5,42 +5,81 @@
* to PHP's memory; good for unit tests or circumstances where
* there are lots of configuration objects floating around.
*/
-class HTMLPurifier_DefinitionCache_Decorator_Memory extends
- HTMLPurifier_DefinitionCache_Decorator
+class HTMLPurifier_DefinitionCache_Decorator_Memory extends HTMLPurifier_DefinitionCache_Decorator
{
-
+ /**
+ * @type array
+ */
protected $definitions;
+
+ /**
+ * @type string
+ */
public $name = 'Memory';
- public function copy() {
+ /**
+ * @return HTMLPurifier_DefinitionCache_Decorator_Memory
+ */
+ public function copy()
+ {
return new HTMLPurifier_DefinitionCache_Decorator_Memory();
}
- public function add($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function add($def, $config)
+ {
$status = parent::add($def, $config);
- if ($status) $this->definitions[$this->generateKey($config)] = $def;
+ if ($status) {
+ $this->definitions[$this->generateKey($config)] = $def;
+ }
return $status;
}
- public function set($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function set($def, $config)
+ {
$status = parent::set($def, $config);
- if ($status) $this->definitions[$this->generateKey($config)] = $def;
+ if ($status) {
+ $this->definitions[$this->generateKey($config)] = $def;
+ }
return $status;
}
- public function replace($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function replace($def, $config)
+ {
$status = parent::replace($def, $config);
- if ($status) $this->definitions[$this->generateKey($config)] = $def;
+ if ($status) {
+ $this->definitions[$this->generateKey($config)] = $def;
+ }
return $status;
}
- public function get($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function get($config)
+ {
$key = $this->generateKey($config);
- if (isset($this->definitions[$key])) return $this->definitions[$key];
+ if (isset($this->definitions[$key])) {
+ return $this->definitions[$key];
+ }
$this->definitions[$key] = parent::get($config);
return $this->definitions[$key];
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in
index 21a8fcfda..b1fec8d36 100644
--- a/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in
+++ b/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in
@@ -5,43 +5,78 @@ require_once 'HTMLPurifier/DefinitionCache/Decorator.php';
/**
* Definition cache decorator template.
*/
-class HTMLPurifier_DefinitionCache_Decorator_Template extends
- HTMLPurifier_DefinitionCache_Decorator
+class HTMLPurifier_DefinitionCache_Decorator_Template extends HTMLPurifier_DefinitionCache_Decorator
{
- var $name = 'Template'; // replace this
+ /**
+ * @type string
+ */
+ public $name = 'Template'; // replace this
- function copy() {
+ public function copy()
+ {
// replace class name with yours
return new HTMLPurifier_DefinitionCache_Decorator_Template();
}
// remove methods you don't need
- function add($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function add($def, $config)
+ {
return parent::add($def, $config);
}
- function set($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function set($def, $config)
+ {
return parent::set($def, $config);
}
- function replace($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function replace($def, $config)
+ {
return parent::replace($def, $config);
}
- function get($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function get($config)
+ {
return parent::get($config);
}
- function flush() {
- return parent::flush();
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function flush($config)
+ {
+ return parent::flush($config);
}
- function cleanup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return mixed
+ */
+ public function cleanup($config)
+ {
return parent::cleanup($config);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/DefinitionCache/Null.php b/library/HTMLPurifier/DefinitionCache/Null.php
index 41d97e734..d9a75ce22 100644
--- a/library/HTMLPurifier/DefinitionCache/Null.php
+++ b/library/HTMLPurifier/DefinitionCache/Null.php
@@ -6,34 +6,71 @@
class HTMLPurifier_DefinitionCache_Null extends HTMLPurifier_DefinitionCache
{
- public function add($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function add($def, $config)
+ {
return false;
}
- public function set($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function set($def, $config)
+ {
return false;
}
- public function replace($def, $config) {
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function replace($def, $config)
+ {
return false;
}
- public function remove($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function remove($config)
+ {
return false;
}
- public function get($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function get($config)
+ {
return false;
}
- public function flush($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function flush($config)
+ {
return false;
}
- public function cleanup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function cleanup($config)
+ {
return false;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/DefinitionCache/Serializer.php b/library/HTMLPurifier/DefinitionCache/Serializer.php
index 7a6aa93f0..ecacb88fe 100644
--- a/library/HTMLPurifier/DefinitionCache/Serializer.php
+++ b/library/HTMLPurifier/DefinitionCache/Serializer.php
@@ -1,83 +1,160 @@
<?php
-class HTMLPurifier_DefinitionCache_Serializer extends
- HTMLPurifier_DefinitionCache
+class HTMLPurifier_DefinitionCache_Serializer extends HTMLPurifier_DefinitionCache
{
- public function add($def, $config) {
- if (!$this->checkDefType($def)) return;
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return int|bool
+ */
+ public function add($def, $config)
+ {
+ if (!$this->checkDefType($def)) {
+ return;
+ }
$file = $this->generateFilePath($config);
- if (file_exists($file)) return false;
- if (!$this->_prepareDir($config)) return false;
- return $this->_write($file, serialize($def));
+ if (file_exists($file)) {
+ return false;
+ }
+ if (!$this->_prepareDir($config)) {
+ return false;
+ }
+ return $this->_write($file, serialize($def), $config);
}
- public function set($def, $config) {
- if (!$this->checkDefType($def)) return;
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return int|bool
+ */
+ public function set($def, $config)
+ {
+ if (!$this->checkDefType($def)) {
+ return;
+ }
$file = $this->generateFilePath($config);
- if (!$this->_prepareDir($config)) return false;
- return $this->_write($file, serialize($def));
+ if (!$this->_prepareDir($config)) {
+ return false;
+ }
+ return $this->_write($file, serialize($def), $config);
}
- public function replace($def, $config) {
- if (!$this->checkDefType($def)) return;
+ /**
+ * @param HTMLPurifier_Definition $def
+ * @param HTMLPurifier_Config $config
+ * @return int|bool
+ */
+ public function replace($def, $config)
+ {
+ if (!$this->checkDefType($def)) {
+ return;
+ }
$file = $this->generateFilePath($config);
- if (!file_exists($file)) return false;
- if (!$this->_prepareDir($config)) return false;
- return $this->_write($file, serialize($def));
+ if (!file_exists($file)) {
+ return false;
+ }
+ if (!$this->_prepareDir($config)) {
+ return false;
+ }
+ return $this->_write($file, serialize($def), $config);
}
- public function get($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool|HTMLPurifier_Config
+ */
+ public function get($config)
+ {
$file = $this->generateFilePath($config);
- if (!file_exists($file)) return false;
+ if (!file_exists($file)) {
+ return false;
+ }
return unserialize(file_get_contents($file));
}
- public function remove($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function remove($config)
+ {
$file = $this->generateFilePath($config);
- if (!file_exists($file)) return false;
+ if (!file_exists($file)) {
+ return false;
+ }
return unlink($file);
}
- public function flush($config) {
- if (!$this->_prepareDir($config)) return false;
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function flush($config)
+ {
+ if (!$this->_prepareDir($config)) {
+ return false;
+ }
$dir = $this->generateDirectoryPath($config);
- $dh = opendir($dir);
+ $dh = opendir($dir);
while (false !== ($filename = readdir($dh))) {
- if (empty($filename)) continue;
- if ($filename[0] === '.') continue;
+ if (empty($filename)) {
+ continue;
+ }
+ if ($filename[0] === '.') {
+ continue;
+ }
unlink($dir . '/' . $filename);
}
}
- public function cleanup($config) {
- if (!$this->_prepareDir($config)) return false;
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function cleanup($config)
+ {
+ if (!$this->_prepareDir($config)) {
+ return false;
+ }
$dir = $this->generateDirectoryPath($config);
- $dh = opendir($dir);
+ $dh = opendir($dir);
while (false !== ($filename = readdir($dh))) {
- if (empty($filename)) continue;
- if ($filename[0] === '.') continue;
+ if (empty($filename)) {
+ continue;
+ }
+ if ($filename[0] === '.') {
+ continue;
+ }
$key = substr($filename, 0, strlen($filename) - 4);
- if ($this->isOld($key, $config)) unlink($dir . '/' . $filename);
+ if ($this->isOld($key, $config)) {
+ unlink($dir . '/' . $filename);
+ }
}
}
/**
* Generates the file path to the serial file corresponding to
* the configuration and definition name
+ * @param HTMLPurifier_Config $config
+ * @return string
* @todo Make protected
*/
- public function generateFilePath($config) {
+ public function generateFilePath($config)
+ {
$key = $this->generateKey($config);
return $this->generateDirectoryPath($config) . '/' . $key . '.ser';
}
/**
* Generates the path to the directory contain this cache's serial files
+ * @param HTMLPurifier_Config $config
+ * @return string
* @note No trailing slash
* @todo Make protected
*/
- public function generateDirectoryPath($config) {
+ public function generateDirectoryPath($config)
+ {
$base = $this->generateBaseDirectoryPath($config);
return $base . '/' . $this->type;
}
@@ -85,9 +162,12 @@ class HTMLPurifier_DefinitionCache_Serializer extends
/**
* Generates path to base directory that contains all definition type
* serials
+ * @param HTMLPurifier_Config $config
+ * @return mixed|string
* @todo Make protected
*/
- public function generateBaseDirectoryPath($config) {
+ public function generateBaseDirectoryPath($config)
+ {
$base = $config->get('Cache.SerializerPath');
$base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base;
return $base;
@@ -95,34 +175,54 @@ class HTMLPurifier_DefinitionCache_Serializer extends
/**
* Convenience wrapper function for file_put_contents
- * @param $file File name to write to
- * @param $data Data to write into file
- * @return Number of bytes written if success, or false if failure.
+ * @param string $file File name to write to
+ * @param string $data Data to write into file
+ * @param HTMLPurifier_Config $config
+ * @return int|bool Number of bytes written if success, or false if failure.
*/
- private function _write($file, $data) {
- return file_put_contents($file, $data);
+ private function _write($file, $data, $config)
+ {
+ $result = file_put_contents($file, $data);
+ if ($result !== false) {
+ // set permissions of the new file (no execute)
+ $chmod = $config->get('Cache.SerializerPermissions');
+ if (!$chmod) {
+ $chmod = 0644; // invalid config or simpletest
+ }
+ $chmod = $chmod & 0666;
+ chmod($file, $chmod);
+ }
+ return $result;
}
/**
* Prepares the directory that this type stores the serials in
- * @return True if successful
+ * @param HTMLPurifier_Config $config
+ * @return bool True if successful
*/
- private function _prepareDir($config) {
+ private function _prepareDir($config)
+ {
$directory = $this->generateDirectoryPath($config);
+ $chmod = $config->get('Cache.SerializerPermissions');
+ if (!$chmod) {
+ $chmod = 0755; // invalid config or simpletest
+ }
if (!is_dir($directory)) {
$base = $this->generateBaseDirectoryPath($config);
if (!is_dir($base)) {
- trigger_error('Base directory '.$base.' does not exist,
+ trigger_error(
+ 'Base directory ' . $base . ' does not exist,
please create or change using %Cache.SerializerPath',
- E_USER_WARNING);
+ E_USER_WARNING
+ );
return false;
- } elseif (!$this->_testPermissions($base)) {
+ } elseif (!$this->_testPermissions($base, $chmod)) {
return false;
}
- $old = umask(0022); // disable group and world writes
- mkdir($directory);
+ $old = umask(0000);
+ mkdir($directory, $chmod);
umask($old);
- } elseif (!$this->_testPermissions($directory)) {
+ } elseif (!$this->_testPermissions($directory, $chmod)) {
return false;
}
return true;
@@ -131,42 +231,55 @@ class HTMLPurifier_DefinitionCache_Serializer extends
/**
* Tests permissions on a directory and throws out friendly
* error messages and attempts to chmod it itself if possible
+ * @param string $dir Directory path
+ * @param int $chmod Permissions
+ * @return bool True if directory is writable
*/
- private function _testPermissions($dir) {
+ private function _testPermissions($dir, $chmod)
+ {
// early abort, if it is writable, everything is hunky-dory
- if (is_writable($dir)) return true;
+ if (is_writable($dir)) {
+ return true;
+ }
if (!is_dir($dir)) {
// generally, you'll want to handle this beforehand
// so a more specific error message can be given
- trigger_error('Directory '.$dir.' does not exist',
- E_USER_WARNING);
+ trigger_error(
+ 'Directory ' . $dir . ' does not exist',
+ E_USER_WARNING
+ );
return false;
}
if (function_exists('posix_getuid')) {
// POSIX system, we can give more specific advice
if (fileowner($dir) === posix_getuid()) {
// we can chmod it ourselves
- chmod($dir, 0755);
- return true;
+ $chmod = $chmod | 0700;
+ if (chmod($dir, $chmod)) {
+ return true;
+ }
} elseif (filegroup($dir) === posix_getgid()) {
- $chmod = '775';
+ $chmod = $chmod | 0070;
} else {
// PHP's probably running as nobody, so we'll
// need to give global permissions
- $chmod = '777';
+ $chmod = $chmod | 0777;
}
- trigger_error('Directory '.$dir.' not writable, '.
- 'please chmod to ' . $chmod,
- E_USER_WARNING);
+ trigger_error(
+ 'Directory ' . $dir . ' not writable, ' .
+ 'please chmod to ' . decoct($chmod),
+ E_USER_WARNING
+ );
} else {
// generic error message
- trigger_error('Directory '.$dir.' not writable, '.
+ trigger_error(
+ 'Directory ' . $dir . ' not writable, ' .
'please alter file permissions',
- E_USER_WARNING);
+ E_USER_WARNING
+ );
}
return false;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/DefinitionCache/Serializer/README b/library/HTMLPurifier/DefinitionCache/Serializer/README
index 2e35c1c3d..2e35c1c3d 100644..100755
--- a/library/HTMLPurifier/DefinitionCache/Serializer/README
+++ b/library/HTMLPurifier/DefinitionCache/Serializer/README
diff --git a/library/HTMLPurifier/DefinitionCacheFactory.php b/library/HTMLPurifier/DefinitionCacheFactory.php
index a6ead6281..fd1cc9be4 100644
--- a/library/HTMLPurifier/DefinitionCacheFactory.php
+++ b/library/HTMLPurifier/DefinitionCacheFactory.php
@@ -5,22 +5,36 @@
*/
class HTMLPurifier_DefinitionCacheFactory
{
-
+ /**
+ * @type array
+ */
protected $caches = array('Serializer' => array());
+
+ /**
+ * @type array
+ */
protected $implementations = array();
+
+ /**
+ * @type HTMLPurifier_DefinitionCache_Decorator[]
+ */
protected $decorators = array();
/**
* Initialize default decorators
*/
- public function setup() {
+ public function setup()
+ {
$this->addDecorator('Cleanup');
}
/**
* Retrieves an instance of global definition cache factory.
+ * @param HTMLPurifier_DefinitionCacheFactory $prototype
+ * @return HTMLPurifier_DefinitionCacheFactory
*/
- public static function instance($prototype = null) {
+ public static function instance($prototype = null)
+ {
static $instance;
if ($prototype !== null) {
$instance = $prototype;
@@ -33,19 +47,22 @@ class HTMLPurifier_DefinitionCacheFactory
/**
* Registers a new definition cache object
- * @param $short Short name of cache object, for reference
- * @param $long Full class name of cache object, for construction
+ * @param string $short Short name of cache object, for reference
+ * @param string $long Full class name of cache object, for construction
*/
- public function register($short, $long) {
+ public function register($short, $long)
+ {
$this->implementations[$short] = $long;
}
/**
* Factory method that creates a cache object based on configuration
- * @param $name Name of definitions handled by cache
- * @param $config Instance of HTMLPurifier_Config
+ * @param string $type Name of definitions handled by cache
+ * @param HTMLPurifier_Config $config Config instance
+ * @return mixed
*/
- public function create($type, $config) {
+ public function create($type, $config)
+ {
$method = $config->get('Cache.DefinitionImpl');
if ($method === null) {
return new HTMLPurifier_DefinitionCache_Null($type);
@@ -53,10 +70,8 @@ class HTMLPurifier_DefinitionCacheFactory
if (!empty($this->caches[$method][$type])) {
return $this->caches[$method][$type];
}
- if (
- isset($this->implementations[$method]) &&
- class_exists($class = $this->implementations[$method], false)
- ) {
+ if (isset($this->implementations[$method]) &&
+ class_exists($class = $this->implementations[$method], false)) {
$cache = new $class($type);
} else {
if ($method != 'Serializer') {
@@ -76,16 +91,16 @@ class HTMLPurifier_DefinitionCacheFactory
/**
* Registers a decorator to add to all new cache objects
- * @param
+ * @param HTMLPurifier_DefinitionCache_Decorator|string $decorator An instance or the name of a decorator
*/
- public function addDecorator($decorator) {
+ public function addDecorator($decorator)
+ {
if (is_string($decorator)) {
$class = "HTMLPurifier_DefinitionCache_Decorator_$decorator";
$decorator = new $class;
}
$this->decorators[$decorator->name] = $decorator;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Doctype.php b/library/HTMLPurifier/Doctype.php
index 1e3c574c0..4acd06e5b 100644
--- a/library/HTMLPurifier/Doctype.php
+++ b/library/HTMLPurifier/Doctype.php
@@ -10,42 +10,55 @@ class HTMLPurifier_Doctype
{
/**
* Full name of doctype
+ * @type string
*/
public $name;
/**
* List of standard modules (string identifiers or literal objects)
* that this doctype uses
+ * @type array
*/
public $modules = array();
/**
* List of modules to use for tidying up code
+ * @type array
*/
public $tidyModules = array();
/**
* Is the language derived from XML (i.e. XHTML)?
+ * @type bool
*/
public $xml = true;
/**
* List of aliases for this doctype
+ * @type array
*/
public $aliases = array();
/**
* Public DTD identifier
+ * @type string
*/
public $dtdPublic;
/**
* System DTD identifier
+ * @type string
*/
public $dtdSystem;
- public function __construct($name = null, $xml = true, $modules = array(),
- $tidyModules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null
+ public function __construct(
+ $name = null,
+ $xml = true,
+ $modules = array(),
+ $tidyModules = array(),
+ $aliases = array(),
+ $dtd_public = null,
+ $dtd_system = null
) {
$this->name = $name;
$this->xml = $xml;
diff --git a/library/HTMLPurifier/DoctypeRegistry.php b/library/HTMLPurifier/DoctypeRegistry.php
index 86049e939..acc1d64a6 100644
--- a/library/HTMLPurifier/DoctypeRegistry.php
+++ b/library/HTMLPurifier/DoctypeRegistry.php
@@ -4,12 +4,14 @@ class HTMLPurifier_DoctypeRegistry
{
/**
- * Hash of doctype names to doctype objects
+ * Hash of doctype names to doctype objects.
+ * @type array
*/
protected $doctypes;
/**
- * Lookup table of aliases to real doctype names
+ * Lookup table of aliases to real doctype names.
+ * @type array
*/
protected $aliases;
@@ -17,32 +19,57 @@ class HTMLPurifier_DoctypeRegistry
* Registers a doctype to the registry
* @note Accepts a fully-formed doctype object, or the
* parameters for constructing a doctype object
- * @param $doctype Name of doctype or literal doctype object
- * @param $modules Modules doctype will load
- * @param $modules_for_modes Modules doctype will load for certain modes
- * @param $aliases Alias names for doctype
- * @return Editable registered doctype
+ * @param string $doctype Name of doctype or literal doctype object
+ * @param bool $xml
+ * @param array $modules Modules doctype will load
+ * @param array $tidy_modules Modules doctype will load for certain modes
+ * @param array $aliases Alias names for doctype
+ * @param string $dtd_public
+ * @param string $dtd_system
+ * @return HTMLPurifier_Doctype Editable registered doctype
*/
- public function register($doctype, $xml = true, $modules = array(),
- $tidy_modules = array(), $aliases = array(), $dtd_public = null, $dtd_system = null
+ public function register(
+ $doctype,
+ $xml = true,
+ $modules = array(),
+ $tidy_modules = array(),
+ $aliases = array(),
+ $dtd_public = null,
+ $dtd_system = null
) {
- if (!is_array($modules)) $modules = array($modules);
- if (!is_array($tidy_modules)) $tidy_modules = array($tidy_modules);
- if (!is_array($aliases)) $aliases = array($aliases);
+ if (!is_array($modules)) {
+ $modules = array($modules);
+ }
+ if (!is_array($tidy_modules)) {
+ $tidy_modules = array($tidy_modules);
+ }
+ if (!is_array($aliases)) {
+ $aliases = array($aliases);
+ }
if (!is_object($doctype)) {
$doctype = new HTMLPurifier_Doctype(
- $doctype, $xml, $modules, $tidy_modules, $aliases, $dtd_public, $dtd_system
+ $doctype,
+ $xml,
+ $modules,
+ $tidy_modules,
+ $aliases,
+ $dtd_public,
+ $dtd_system
);
}
$this->doctypes[$doctype->name] = $doctype;
$name = $doctype->name;
// hookup aliases
foreach ($doctype->aliases as $alias) {
- if (isset($this->doctypes[$alias])) continue;
+ if (isset($this->doctypes[$alias])) {
+ continue;
+ }
$this->aliases[$alias] = $name;
}
// remove old aliases
- if (isset($this->aliases[$name])) unset($this->aliases[$name]);
+ if (isset($this->aliases[$name])) {
+ unset($this->aliases[$name]);
+ }
return $doctype;
}
@@ -50,11 +77,14 @@ class HTMLPurifier_DoctypeRegistry
* Retrieves reference to a doctype of a certain name
* @note This function resolves aliases
* @note When possible, use the more fully-featured make()
- * @param $doctype Name of doctype
- * @return Editable doctype object
+ * @param string $doctype Name of doctype
+ * @return HTMLPurifier_Doctype Editable doctype object
*/
- public function get($doctype) {
- if (isset($this->aliases[$doctype])) $doctype = $this->aliases[$doctype];
+ public function get($doctype)
+ {
+ if (isset($this->aliases[$doctype])) {
+ $doctype = $this->aliases[$doctype];
+ }
if (!isset($this->doctypes[$doctype])) {
trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR);
$anon = new HTMLPurifier_Doctype($doctype);
@@ -70,20 +100,30 @@ class HTMLPurifier_DoctypeRegistry
* can hold on to (this is necessary in order to tell
* Generator whether or not the current document is XML
* based or not).
+ * @param HTMLPurifier_Config $config
+ * @return HTMLPurifier_Doctype
*/
- public function make($config) {
+ public function make($config)
+ {
return clone $this->get($this->getDoctypeFromConfig($config));
}
/**
* Retrieves the doctype from the configuration object
+ * @param HTMLPurifier_Config $config
+ * @return string
*/
- public function getDoctypeFromConfig($config) {
+ public function getDoctypeFromConfig($config)
+ {
// recommended test
$doctype = $config->get('HTML.Doctype');
- if (!empty($doctype)) return $doctype;
+ if (!empty($doctype)) {
+ return $doctype;
+ }
$doctype = $config->get('HTML.CustomDoctype');
- if (!empty($doctype)) return $doctype;
+ if (!empty($doctype)) {
+ return $doctype;
+ }
// backwards-compatibility
if ($config->get('HTML.XHTML')) {
$doctype = 'XHTML 1.0';
@@ -97,7 +137,6 @@ class HTMLPurifier_DoctypeRegistry
}
return $doctype;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ElementDef.php b/library/HTMLPurifier/ElementDef.php
index 5498d9567..d5311cedc 100644
--- a/library/HTMLPurifier/ElementDef.php
+++ b/library/HTMLPurifier/ElementDef.php
@@ -10,15 +10,16 @@
*/
class HTMLPurifier_ElementDef
{
-
/**
* Does the definition work by itself, or is it created solely
* for the purpose of merging into another definition?
+ * @type bool
*/
public $standalone = true;
/**
- * Associative array of attribute name to HTMLPurifier_AttrDef
+ * Associative array of attribute name to HTMLPurifier_AttrDef.
+ * @type array
* @note Before being processed by HTMLPurifier_AttrCollections
* when modules are finalized during
* HTMLPurifier_HTMLDefinition->setup(), this array may also
@@ -30,27 +31,43 @@ class HTMLPurifier_ElementDef
*/
public $attr = array();
+ // XXX: Design note: currently, it's not possible to override
+ // previously defined AttrTransforms without messing around with
+ // the final generated config. This is by design; a previous version
+ // used an associated list of attr_transform, but it was extremely
+ // easy to accidentally override other attribute transforms by
+ // forgetting to specify an index (and just using 0.) While we
+ // could check this by checking the index number and complaining,
+ // there is a second problem which is that it is not at all easy to
+ // tell when something is getting overridden. Combine this with a
+ // codebase where this isn't really being used, and it's perfect for
+ // nuking.
+
/**
- * Indexed list of tag's HTMLPurifier_AttrTransform to be done before validation
+ * List of tags HTMLPurifier_AttrTransform to be done before validation.
+ * @type array
*/
public $attr_transform_pre = array();
/**
- * Indexed list of tag's HTMLPurifier_AttrTransform to be done after validation
+ * List of tags HTMLPurifier_AttrTransform to be done after validation.
+ * @type array
*/
public $attr_transform_post = array();
/**
* HTMLPurifier_ChildDef of this tag.
+ * @type HTMLPurifier_ChildDef
*/
public $child;
/**
- * Abstract string representation of internal ChildDef rules. See
- * HTMLPurifier_ContentSets for how this is parsed and then transformed
+ * Abstract string representation of internal ChildDef rules.
+ * @see HTMLPurifier_ContentSets for how this is parsed and then transformed
* into an HTMLPurifier_ChildDef.
* @warning This is a temporary variable that is not available after
* being processed by HTMLDefinition
+ * @type string
*/
public $content_model;
@@ -60,27 +77,29 @@ class HTMLPurifier_ElementDef
* @warning This must be lowercase
* @warning This is a temporary variable that is not available after
* being processed by HTMLDefinition
+ * @type string
*/
public $content_model_type;
-
-
/**
* Does the element have a content model (#PCDATA | Inline)*? This
* is important for chameleon ins and del processing in
* HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't
* have to worry about this one.
+ * @type bool
*/
public $descendants_are_inline = false;
/**
- * List of the names of required attributes this element has. Dynamically
- * populated by HTMLPurifier_HTMLDefinition::getElement
+ * List of the names of required attributes this element has.
+ * Dynamically populated by HTMLPurifier_HTMLDefinition::getElement()
+ * @type array
*/
public $required_attr = array();
/**
* Lookup table of tags excluded from all descendants of this tag.
+ * @type array
* @note SGML permits exclusions for all descendants, but this is
* not possible with DTDs or XML Schemas. W3C has elected to
* use complicated compositions of content_models to simulate
@@ -94,6 +113,7 @@ class HTMLPurifier_ElementDef
/**
* This tag is explicitly auto-closed by the following tags.
+ * @type array
*/
public $autoclose = array();
@@ -101,19 +121,22 @@ class HTMLPurifier_ElementDef
* If a foreign element is found in this element, test if it is
* allowed by this sub-element; if it is, instead of closing the
* current element, place it inside this element.
+ * @type string
*/
public $wrap;
/**
* Whether or not this is a formatting element affected by the
* "Active Formatting Elements" algorithm.
+ * @type bool
*/
public $formatting;
/**
* Low-level factory constructor for creating new standalone element defs
*/
- public static function create($content_model, $content_model_type, $attr) {
+ public static function create($content_model, $content_model_type, $attr)
+ {
$def = new HTMLPurifier_ElementDef();
$def->content_model = $content_model;
$def->content_model_type = $content_model_type;
@@ -125,11 +148,12 @@ class HTMLPurifier_ElementDef
* Merges the values of another element definition into this one.
* Values from the new element def take precedence if a value is
* not mergeable.
+ * @param HTMLPurifier_ElementDef $def
*/
- public function mergeIn($def) {
-
+ public function mergeIn($def)
+ {
// later keys takes precedence
- foreach($def->attr as $k => $v) {
+ foreach ($def->attr as $k => $v) {
if ($k === 0) {
// merge in the includes
// sorry, no way to override an include
@@ -139,28 +163,35 @@ class HTMLPurifier_ElementDef
continue;
}
if ($v === false) {
- if (isset($this->attr[$k])) unset($this->attr[$k]);
+ if (isset($this->attr[$k])) {
+ unset($this->attr[$k]);
+ }
continue;
}
$this->attr[$k] = $v;
}
- $this->_mergeAssocArray($this->attr_transform_pre, $def->attr_transform_pre);
- $this->_mergeAssocArray($this->attr_transform_post, $def->attr_transform_post);
$this->_mergeAssocArray($this->excludes, $def->excludes);
+ $this->attr_transform_pre = array_merge($this->attr_transform_pre, $def->attr_transform_pre);
+ $this->attr_transform_post = array_merge($this->attr_transform_post, $def->attr_transform_post);
- if(!empty($def->content_model)) {
+ if (!empty($def->content_model)) {
$this->content_model =
str_replace("#SUPER", $this->content_model, $def->content_model);
$this->child = false;
}
- if(!empty($def->content_model_type)) {
+ if (!empty($def->content_model_type)) {
$this->content_model_type = $def->content_model_type;
$this->child = false;
}
- if(!is_null($def->child)) $this->child = $def->child;
- if(!is_null($def->formatting)) $this->formatting = $def->formatting;
- if($def->descendants_are_inline) $this->descendants_are_inline = $def->descendants_are_inline;
-
+ if (!is_null($def->child)) {
+ $this->child = $def->child;
+ }
+ if (!is_null($def->formatting)) {
+ $this->formatting = $def->formatting;
+ }
+ if ($def->descendants_are_inline) {
+ $this->descendants_are_inline = $def->descendants_are_inline;
+ }
}
/**
@@ -168,16 +199,18 @@ class HTMLPurifier_ElementDef
* @param $a1 Array by reference that is merged into
* @param $a2 Array that merges into $a1
*/
- private function _mergeAssocArray(&$a1, $a2) {
+ private function _mergeAssocArray(&$a1, $a2)
+ {
foreach ($a2 as $k => $v) {
if ($v === false) {
- if (isset($a1[$k])) unset($a1[$k]);
+ if (isset($a1[$k])) {
+ unset($a1[$k]);
+ }
continue;
}
$a1[$k] = $v;
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Encoder.php b/library/HTMLPurifier/Encoder.php
index 2b3140caa..fef9b5890 100644
--- a/library/HTMLPurifier/Encoder.php
+++ b/library/HTMLPurifier/Encoder.php
@@ -10,14 +10,90 @@ class HTMLPurifier_Encoder
/**
* Constructor throws fatal error if you attempt to instantiate class
*/
- private function __construct() {
+ private function __construct()
+ {
trigger_error('Cannot instantiate encoder, call methods statically', E_USER_ERROR);
}
/**
* Error-handler that mutes errors, alternative to shut-up operator.
*/
- public static function muteErrorHandler() {}
+ public static function muteErrorHandler()
+ {
+ }
+
+ /**
+ * iconv wrapper which mutes errors, but doesn't work around bugs.
+ * @param string $in Input encoding
+ * @param string $out Output encoding
+ * @param string $text The text to convert
+ * @return string
+ */
+ public static function unsafeIconv($in, $out, $text)
+ {
+ set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
+ $r = iconv($in, $out, $text);
+ restore_error_handler();
+ return $r;
+ }
+
+ /**
+ * iconv wrapper which mutes errors and works around bugs.
+ * @param string $in Input encoding
+ * @param string $out Output encoding
+ * @param string $text The text to convert
+ * @param int $max_chunk_size
+ * @return string
+ */
+ public static function iconv($in, $out, $text, $max_chunk_size = 8000)
+ {
+ $code = self::testIconvTruncateBug();
+ if ($code == self::ICONV_OK) {
+ return self::unsafeIconv($in, $out, $text);
+ } elseif ($code == self::ICONV_TRUNCATES) {
+ // we can only work around this if the input character set
+ // is utf-8
+ if ($in == 'utf-8') {
+ if ($max_chunk_size < 4) {
+ trigger_error('max_chunk_size is too small', E_USER_WARNING);
+ return false;
+ }
+ // split into 8000 byte chunks, but be careful to handle
+ // multibyte boundaries properly
+ if (($c = strlen($text)) <= $max_chunk_size) {
+ return self::unsafeIconv($in, $out, $text);
+ }
+ $r = '';
+ $i = 0;
+ while (true) {
+ if ($i + $max_chunk_size >= $c) {
+ $r .= self::unsafeIconv($in, $out, substr($text, $i));
+ break;
+ }
+ // wibble the boundary
+ if (0x80 != (0xC0 & ord($text[$i + $max_chunk_size]))) {
+ $chunk_size = $max_chunk_size;
+ } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 1]))) {
+ $chunk_size = $max_chunk_size - 1;
+ } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 2]))) {
+ $chunk_size = $max_chunk_size - 2;
+ } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 3]))) {
+ $chunk_size = $max_chunk_size - 3;
+ } else {
+ return false; // rather confusing UTF-8...
+ }
+ $chunk = substr($text, $i, $chunk_size); // substr doesn't mind overlong lengths
+ $r .= self::unsafeIconv($in, $out, $chunk);
+ $i += $chunk_size;
+ }
+ return $r;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
/**
* Cleans a UTF-8 string for well-formedness and SGML validity
@@ -25,6 +101,10 @@ class HTMLPurifier_Encoder
* It will parse according to UTF-8 and return a valid UTF8 string, with
* non-SGML codepoints excluded.
*
+ * @param string $str The string to clean
+ * @param bool $force_php
+ * @return string
+ *
* @note Just for reference, the non-SGML code points are 0 to 31 and
* 127 to 159, inclusive. However, we allow code points 9, 10
* and 13, which are the tab, line feed and carriage return
@@ -44,14 +124,17 @@ class HTMLPurifier_Encoder
* would need that, and I'm probably not going to implement them.
* Once again, PHP 6 should solve all our problems.
*/
- public static function cleanUTF8($str, $force_php = false) {
-
+ public static function cleanUTF8($str, $force_php = false)
+ {
// UTF-8 validity is checked since PHP 4.3.5
// This is an optimization: if the string is already valid UTF-8, no
// need to do PHP stuff. 99% of the time, this will be the case.
// The regexp matches the XML char production, as well as well as excluding
// non-SGML codepoints U+007F to U+009F
- if (preg_match('/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du', $str)) {
+ if (preg_match(
+ '/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du',
+ $str
+ )) {
return $str;
}
@@ -70,7 +153,7 @@ class HTMLPurifier_Encoder
$char = '';
$len = strlen($str);
- for($i = 0; $i < $len; $i++) {
+ for ($i = 0; $i < $len; $i++) {
$in = ord($str{$i});
$char .= $str[$i]; // append byte to char
if (0 == $mState) {
@@ -223,8 +306,9 @@ class HTMLPurifier_Encoder
// | 00000000 | 00010000 | 11111111 | 11111111 | Defined upper limit of legal scalar codes
// +----------+----------+----------+----------+
- public static function unichr($code) {
- if($code > 1114111 or $code < 0 or
+ public static function unichr($code)
+ {
+ if ($code > 1114111 or $code < 0 or
($code >= 55296 and $code <= 57343) ) {
// bits are set outside the "valid" range as defined
// by UNICODE 4.1.0
@@ -242,7 +326,7 @@ class HTMLPurifier_Encoder
$y = (($code & 2047) >> 6) | 192;
} else {
$y = (($code & 4032) >> 6) | 128;
- if($code < 65536) {
+ if ($code < 65536) {
$z = (($code >> 12) & 15) | 224;
} else {
$z = (($code >> 12) & 63) | 128;
@@ -252,84 +336,129 @@ class HTMLPurifier_Encoder
}
// set up the actual character
$ret = '';
- if($w) $ret .= chr($w);
- if($z) $ret .= chr($z);
- if($y) $ret .= chr($y);
+ if ($w) {
+ $ret .= chr($w);
+ }
+ if ($z) {
+ $ret .= chr($z);
+ }
+ if ($y) {
+ $ret .= chr($y);
+ }
$ret .= chr($x);
return $ret;
}
/**
- * Converts a string to UTF-8 based on configuration.
+ * @return bool
+ */
+ public static function iconvAvailable()
+ {
+ static $iconv = null;
+ if ($iconv === null) {
+ $iconv = function_exists('iconv') && self::testIconvTruncateBug() != self::ICONV_UNUSABLE;
+ }
+ return $iconv;
+ }
+
+ /**
+ * Convert a string to UTF-8 based on configuration.
+ * @param string $str The string to convert
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
*/
- public static function convertToUTF8($str, $config, $context) {
+ public static function convertToUTF8($str, $config, $context)
+ {
$encoding = $config->get('Core.Encoding');
- if ($encoding === 'utf-8') return $str;
+ if ($encoding === 'utf-8') {
+ return $str;
+ }
static $iconv = null;
- if ($iconv === null) $iconv = function_exists('iconv');
- set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
+ if ($iconv === null) {
+ $iconv = self::iconvAvailable();
+ }
if ($iconv && !$config->get('Test.ForceNoIconv')) {
- $str = iconv($encoding, 'utf-8//IGNORE', $str);
+ // unaffected by bugs, since UTF-8 support all characters
+ $str = self::unsafeIconv($encoding, 'utf-8//IGNORE', $str);
if ($str === false) {
// $encoding is not a valid encoding
- restore_error_handler();
trigger_error('Invalid encoding ' . $encoding, E_USER_ERROR);
return '';
}
// If the string is bjorked by Shift_JIS or a similar encoding
// that doesn't support all of ASCII, convert the naughty
// characters to their true byte-wise ASCII/UTF-8 equivalents.
- $str = strtr($str, HTMLPurifier_Encoder::testEncodingSupportsASCII($encoding));
- restore_error_handler();
+ $str = strtr($str, self::testEncodingSupportsASCII($encoding));
return $str;
} elseif ($encoding === 'iso-8859-1') {
$str = utf8_encode($str);
- restore_error_handler();
return $str;
}
- trigger_error('Encoding not supported, please install iconv', E_USER_ERROR);
+ $bug = HTMLPurifier_Encoder::testIconvTruncateBug();
+ if ($bug == self::ICONV_OK) {
+ trigger_error('Encoding not supported, please install iconv', E_USER_ERROR);
+ } else {
+ trigger_error(
+ 'You have a buggy version of iconv, see https://bugs.php.net/bug.php?id=48147 ' .
+ 'and http://sourceware.org/bugzilla/show_bug.cgi?id=13541',
+ E_USER_ERROR
+ );
+ }
}
/**
* Converts a string from UTF-8 based on configuration.
+ * @param string $str The string to convert
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
* @note Currently, this is a lossy conversion, with unexpressable
* characters being omitted.
*/
- public static function convertFromUTF8($str, $config, $context) {
+ public static function convertFromUTF8($str, $config, $context)
+ {
$encoding = $config->get('Core.Encoding');
- if ($encoding === 'utf-8') return $str;
- static $iconv = null;
- if ($iconv === null) $iconv = function_exists('iconv');
if ($escape = $config->get('Core.EscapeNonASCIICharacters')) {
- $str = HTMLPurifier_Encoder::convertToASCIIDumbLossless($str);
+ $str = self::convertToASCIIDumbLossless($str);
+ }
+ if ($encoding === 'utf-8') {
+ return $str;
+ }
+ static $iconv = null;
+ if ($iconv === null) {
+ $iconv = self::iconvAvailable();
}
- set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
if ($iconv && !$config->get('Test.ForceNoIconv')) {
// Undo our previous fix in convertToUTF8, otherwise iconv will barf
- $ascii_fix = HTMLPurifier_Encoder::testEncodingSupportsASCII($encoding);
+ $ascii_fix = self::testEncodingSupportsASCII($encoding);
if (!$escape && !empty($ascii_fix)) {
$clear_fix = array();
- foreach ($ascii_fix as $utf8 => $native) $clear_fix[$utf8] = '';
+ foreach ($ascii_fix as $utf8 => $native) {
+ $clear_fix[$utf8] = '';
+ }
$str = strtr($str, $clear_fix);
}
$str = strtr($str, array_flip($ascii_fix));
// Normal stuff
- $str = iconv('utf-8', $encoding . '//IGNORE', $str);
- restore_error_handler();
+ $str = self::iconv('utf-8', $encoding . '//IGNORE', $str);
return $str;
} elseif ($encoding === 'iso-8859-1') {
$str = utf8_decode($str);
- restore_error_handler();
return $str;
}
trigger_error('Encoding not supported', E_USER_ERROR);
+ // You might be tempted to assume that the ASCII representation
+ // might be OK, however, this is *not* universally true over all
+ // encodings. So we take the conservative route here, rather
+ // than forcibly turn on %Core.EscapeNonASCIICharacters
}
/**
* Lossless (character-wise) conversion of HTML to ASCII
- * @param $str UTF-8 string to be converted to ASCII
- * @returns ASCII encoded string with non-ASCII character entity-ized
+ * @param string $str UTF-8 string to be converted to ASCII
+ * @return string ASCII encoded string with non-ASCII character entity-ized
* @warning Adapted from MediaWiki, claiming fair use: this is a common
* algorithm. If you disagree with this license fudgery,
* implement it yourself.
@@ -342,27 +471,28 @@ class HTMLPurifier_Encoder
* @note Sort of with cleanUTF8() but it assumes that $str is
* well-formed UTF-8
*/
- public static function convertToASCIIDumbLossless($str) {
+ public static function convertToASCIIDumbLossless($str)
+ {
$bytesleft = 0;
$result = '';
$working = 0;
$len = strlen($str);
- for( $i = 0; $i < $len; $i++ ) {
- $bytevalue = ord( $str[$i] );
- if( $bytevalue <= 0x7F ) { //0xxx xxxx
- $result .= chr( $bytevalue );
+ for ($i = 0; $i < $len; $i++) {
+ $bytevalue = ord($str[$i]);
+ if ($bytevalue <= 0x7F) { //0xxx xxxx
+ $result .= chr($bytevalue);
$bytesleft = 0;
- } elseif( $bytevalue <= 0xBF ) { //10xx xxxx
+ } elseif ($bytevalue <= 0xBF) { //10xx xxxx
$working = $working << 6;
$working += ($bytevalue & 0x3F);
$bytesleft--;
- if( $bytesleft <= 0 ) {
+ if ($bytesleft <= 0) {
$result .= "&#" . $working . ";";
}
- } elseif( $bytevalue <= 0xDF ) { //110x xxxx
+ } elseif ($bytevalue <= 0xDF) { //110x xxxx
$working = $bytevalue & 0x1F;
$bytesleft = 1;
- } elseif( $bytevalue <= 0xEF ) { //1110 xxxx
+ } elseif ($bytevalue <= 0xEF) { //1110 xxxx
$working = $bytevalue & 0x0F;
$bytesleft = 2;
} else { //1111 0xxx
@@ -373,6 +503,54 @@ class HTMLPurifier_Encoder
return $result;
}
+ /** No bugs detected in iconv. */
+ const ICONV_OK = 0;
+
+ /** Iconv truncates output if converting from UTF-8 to another
+ * character set with //IGNORE, and a non-encodable character is found */
+ const ICONV_TRUNCATES = 1;
+
+ /** Iconv does not support //IGNORE, making it unusable for
+ * transcoding purposes */
+ const ICONV_UNUSABLE = 2;
+
+ /**
+ * glibc iconv has a known bug where it doesn't handle the magic
+ * //IGNORE stanza correctly. In particular, rather than ignore
+ * characters, it will return an EILSEQ after consuming some number
+ * of characters, and expect you to restart iconv as if it were
+ * an E2BIG. Old versions of PHP did not respect the errno, and
+ * returned the fragment, so as a result you would see iconv
+ * mysteriously truncating output. We can work around this by
+ * manually chopping our input into segments of about 8000
+ * characters, as long as PHP ignores the error code. If PHP starts
+ * paying attention to the error code, iconv becomes unusable.
+ *
+ * @return int Error code indicating severity of bug.
+ */
+ public static function testIconvTruncateBug()
+ {
+ static $code = null;
+ if ($code === null) {
+ // better not use iconv, otherwise infinite loop!
+ $r = self::unsafeIconv('utf-8', 'ascii//IGNORE', "\xCE\xB1" . str_repeat('a', 9000));
+ if ($r === false) {
+ $code = self::ICONV_UNUSABLE;
+ } elseif (($c = strlen($r)) < 9000) {
+ $code = self::ICONV_TRUNCATES;
+ } elseif ($c > 9000) {
+ trigger_error(
+ 'Your copy of iconv is extremely buggy. Please notify HTML Purifier maintainers: ' .
+ 'include your iconv version as per phpversion()',
+ E_USER_ERROR
+ );
+ } else {
+ $code = self::ICONV_OK;
+ }
+ }
+ return $code;
+ }
+
/**
* This expensive function tests whether or not a given character
* encoding supports ASCII. 7/8-bit encodings like Shift_JIS will
@@ -384,10 +562,18 @@ class HTMLPurifier_Encoder
* @return Array of UTF-8 characters to their corresponding ASCII,
* which can be used to "undo" any overzealous iconv action.
*/
- public static function testEncodingSupportsASCII($encoding, $bypass = false) {
+ public static function testEncodingSupportsASCII($encoding, $bypass = false)
+ {
+ // All calls to iconv here are unsafe, proof by case analysis:
+ // If ICONV_OK, no difference.
+ // If ICONV_TRUNCATE, all calls involve one character inputs,
+ // so bug is not triggered.
+ // If ICONV_UNUSABLE, this call is irrelevant
static $encodings = array();
if (!$bypass) {
- if (isset($encodings[$encoding])) return $encodings[$encoding];
+ if (isset($encodings[$encoding])) {
+ return $encodings[$encoding];
+ }
$lenc = strtolower($encoding);
switch ($lenc) {
case 'shift_jis':
@@ -395,32 +581,31 @@ class HTMLPurifier_Encoder
case 'johab':
return array("\xE2\x82\xA9" => '\\');
}
- if (strpos($lenc, 'iso-8859-') === 0) return array();
+ if (strpos($lenc, 'iso-8859-') === 0) {
+ return array();
+ }
}
$ret = array();
- set_error_handler(array('HTMLPurifier_Encoder', 'muteErrorHandler'));
- if (iconv('UTF-8', $encoding, 'a') === false) return false;
+ if (self::unsafeIconv('UTF-8', $encoding, 'a') === false) {
+ return false;
+ }
for ($i = 0x20; $i <= 0x7E; $i++) { // all printable ASCII chars
$c = chr($i); // UTF-8 char
- $r = iconv('UTF-8', "$encoding//IGNORE", $c); // initial conversion
- if (
- $r === '' ||
+ $r = self::unsafeIconv('UTF-8', "$encoding//IGNORE", $c); // initial conversion
+ if ($r === '' ||
// This line is needed for iconv implementations that do not
// omit characters that do not exist in the target character set
- ($r === $c && iconv($encoding, 'UTF-8//IGNORE', $r) !== $c)
+ ($r === $c && self::unsafeIconv($encoding, 'UTF-8//IGNORE', $r) !== $c)
) {
// Reverse engineer: what's the UTF-8 equiv of this byte
// sequence? This assumes that there's no variable width
// encoding that doesn't support ASCII.
- $ret[iconv($encoding, 'UTF-8//IGNORE', $c)] = $c;
+ $ret[self::unsafeIconv($encoding, 'UTF-8//IGNORE', $c)] = $c;
}
}
- restore_error_handler();
$encodings[$encoding] = $ret;
return $ret;
}
-
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/EntityLookup.php b/library/HTMLPurifier/EntityLookup.php
index b4dfce94c..f12ff13a3 100644
--- a/library/HTMLPurifier/EntityLookup.php
+++ b/library/HTMLPurifier/EntityLookup.php
@@ -3,20 +3,23 @@
/**
* Object that provides entity lookup table from entity name to character
*/
-class HTMLPurifier_EntityLookup {
-
+class HTMLPurifier_EntityLookup
+{
/**
* Assoc array of entity name to character represented.
+ * @type array
*/
public $table;
/**
* Sets up the entity lookup table from the serialized file contents.
+ * @param bool $file
* @note The serialized contents are versioned, but were generated
* using the maintenance script generate_entity_file.php
* @warning This is not in constructor to help enforce the Singleton
*/
- public function setup($file = false) {
+ public function setup($file = false)
+ {
if (!$file) {
$file = HTMLPURIFIER_PREFIX . '/HTMLPurifier/EntityLookup/entities.ser';
}
@@ -25,9 +28,11 @@ class HTMLPurifier_EntityLookup {
/**
* Retrieves sole instance of the object.
- * @param Optional prototype of custom lookup table to overload with.
+ * @param bool|HTMLPurifier_EntityLookup $prototype Optional prototype of custom lookup table to overload with.
+ * @return HTMLPurifier_EntityLookup
*/
- public static function instance($prototype = false) {
+ public static function instance($prototype = false)
+ {
// no references, since PHP doesn't copy unless modified
static $instance = null;
if ($prototype) {
@@ -38,7 +43,6 @@ class HTMLPurifier_EntityLookup {
}
return $instance;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/EntityLookup/entities.ser b/library/HTMLPurifier/EntityLookup/entities.ser
index f2b8b8f2d..e8b08128b 100644
--- a/library/HTMLPurifier/EntityLookup/entities.ser
+++ b/library/HTMLPurifier/EntityLookup/entities.ser
@@ -1 +1 @@
-a:246:{s:4:"nbsp";s:2:" ";s:5:"iexcl";s:2:"¡";s:4:"cent";s:2:"¢";s:5:"pound";s:2:"£";s:6:"curren";s:2:"¤";s:3:"yen";s:2:"¥";s:6:"brvbar";s:2:"¦";s:4:"sect";s:2:"§";s:3:"uml";s:2:"¨";s:4:"copy";s:2:"©";s:4:"ordf";s:2:"ª";s:5:"laquo";s:2:"«";s:3:"not";s:2:"¬";s:3:"shy";s:2:"­";s:3:"reg";s:2:"®";s:4:"macr";s:2:"¯";s:3:"deg";s:2:"°";s:6:"plusmn";s:2:"±";s:5:"acute";s:2:"´";s:5:"micro";s:2:"µ";s:4:"para";s:2:"¶";s:6:"middot";s:2:"·";s:5:"cedil";s:2:"¸";s:4:"ordm";s:2:"º";s:5:"raquo";s:2:"»";s:6:"iquest";s:2:"¿";s:6:"Agrave";s:2:"À";s:6:"Aacute";s:2:"Á";s:5:"Acirc";s:2:"Â";s:6:"Atilde";s:2:"Ã";s:4:"Auml";s:2:"Ä";s:5:"Aring";s:2:"Å";s:5:"AElig";s:2:"Æ";s:6:"Ccedil";s:2:"Ç";s:6:"Egrave";s:2:"È";s:6:"Eacute";s:2:"É";s:5:"Ecirc";s:2:"Ê";s:4:"Euml";s:2:"Ë";s:6:"Igrave";s:2:"Ì";s:6:"Iacute";s:2:"Í";s:5:"Icirc";s:2:"Î";s:4:"Iuml";s:2:"Ï";s:3:"ETH";s:2:"Ð";s:6:"Ntilde";s:2:"Ñ";s:6:"Ograve";s:2:"Ò";s:6:"Oacute";s:2:"Ó";s:5:"Ocirc";s:2:"Ô";s:6:"Otilde";s:2:"Õ";s:4:"Ouml";s:2:"Ö";s:5:"times";s:2:"×";s:6:"Oslash";s:2:"Ø";s:6:"Ugrave";s:2:"Ù";s:6:"Uacute";s:2:"Ú";s:5:"Ucirc";s:2:"Û";s:4:"Uuml";s:2:"Ü";s:6:"Yacute";s:2:"Ý";s:5:"THORN";s:2:"Þ";s:5:"szlig";s:2:"ß";s:6:"agrave";s:2:"à";s:6:"aacute";s:2:"á";s:5:"acirc";s:2:"â";s:6:"atilde";s:2:"ã";s:4:"auml";s:2:"ä";s:5:"aring";s:2:"å";s:5:"aelig";s:2:"æ";s:6:"ccedil";s:2:"ç";s:6:"egrave";s:2:"è";s:6:"eacute";s:2:"é";s:5:"ecirc";s:2:"ê";s:4:"euml";s:2:"ë";s:6:"igrave";s:2:"ì";s:6:"iacute";s:2:"í";s:5:"icirc";s:2:"î";s:4:"iuml";s:2:"ï";s:3:"eth";s:2:"ð";s:6:"ntilde";s:2:"ñ";s:6:"ograve";s:2:"ò";s:6:"oacute";s:2:"ó";s:5:"ocirc";s:2:"ô";s:6:"otilde";s:2:"õ";s:4:"ouml";s:2:"ö";s:6:"divide";s:2:"÷";s:6:"oslash";s:2:"ø";s:6:"ugrave";s:2:"ù";s:6:"uacute";s:2:"ú";s:5:"ucirc";s:2:"û";s:4:"uuml";s:2:"ü";s:6:"yacute";s:2:"ý";s:5:"thorn";s:2:"þ";s:4:"yuml";s:2:"ÿ";s:4:"quot";s:1:""";s:3:"amp";s:1:"&";s:2:"lt";s:1:"<";s:2:"gt";s:1:">";s:4:"apos";s:1:"'";s:5:"OElig";s:2:"Œ";s:5:"oelig";s:2:"œ";s:6:"Scaron";s:2:"Š";s:6:"scaron";s:2:"š";s:4:"Yuml";s:2:"Ÿ";s:4:"circ";s:2:"ˆ";s:5:"tilde";s:2:"˜";s:4:"ensp";s:3:" ";s:4:"emsp";s:3:" ";s:6:"thinsp";s:3:" ";s:4:"zwnj";s:3:"‌";s:3:"zwj";s:3:"‍";s:3:"lrm";s:3:"‎";s:3:"rlm";s:3:"‏";s:5:"ndash";s:3:"–";s:5:"mdash";s:3:"—";s:5:"lsquo";s:3:"‘";s:5:"rsquo";s:3:"’";s:5:"sbquo";s:3:"‚";s:5:"ldquo";s:3:"“";s:5:"rdquo";s:3:"”";s:5:"bdquo";s:3:"„";s:6:"dagger";s:3:"†";s:6:"Dagger";s:3:"‡";s:6:"permil";s:3:"‰";s:6:"lsaquo";s:3:"‹";s:6:"rsaquo";s:3:"›";s:4:"euro";s:3:"€";s:4:"fnof";s:2:"ƒ";s:5:"Alpha";s:2:"Α";s:4:"Beta";s:2:"Β";s:5:"Gamma";s:2:"Γ";s:5:"Delta";s:2:"Δ";s:7:"Epsilon";s:2:"Ε";s:4:"Zeta";s:2:"Ζ";s:3:"Eta";s:2:"Η";s:5:"Theta";s:2:"Θ";s:4:"Iota";s:2:"Ι";s:5:"Kappa";s:2:"Κ";s:6:"Lambda";s:2:"Λ";s:2:"Mu";s:2:"Μ";s:2:"Nu";s:2:"Ν";s:2:"Xi";s:2:"Ξ";s:7:"Omicron";s:2:"Ο";s:2:"Pi";s:2:"Π";s:3:"Rho";s:2:"Ρ";s:5:"Sigma";s:2:"Σ";s:3:"Tau";s:2:"Τ";s:7:"Upsilon";s:2:"Υ";s:3:"Phi";s:2:"Φ";s:3:"Chi";s:2:"Χ";s:3:"Psi";s:2:"Ψ";s:5:"Omega";s:2:"Ω";s:5:"alpha";s:2:"α";s:4:"beta";s:2:"β";s:5:"gamma";s:2:"γ";s:5:"delta";s:2:"δ";s:7:"epsilon";s:2:"ε";s:4:"zeta";s:2:"ζ";s:3:"eta";s:2:"η";s:5:"theta";s:2:"θ";s:4:"iota";s:2:"ι";s:5:"kappa";s:2:"κ";s:6:"lambda";s:2:"λ";s:2:"mu";s:2:"μ";s:2:"nu";s:2:"ν";s:2:"xi";s:2:"ξ";s:7:"omicron";s:2:"ο";s:2:"pi";s:2:"π";s:3:"rho";s:2:"ρ";s:6:"sigmaf";s:2:"ς";s:5:"sigma";s:2:"σ";s:3:"tau";s:2:"τ";s:7:"upsilon";s:2:"υ";s:3:"phi";s:2:"φ";s:3:"chi";s:2:"χ";s:3:"psi";s:2:"ψ";s:5:"omega";s:2:"ω";s:8:"thetasym";s:2:"ϑ";s:5:"upsih";s:2:"ϒ";s:3:"piv";s:2:"ϖ";s:4:"bull";s:3:"•";s:6:"hellip";s:3:"…";s:5:"prime";s:3:"′";s:5:"Prime";s:3:"″";s:5:"oline";s:3:"‾";s:5:"frasl";s:3:"⁄";s:6:"weierp";s:3:"℘";s:5:"image";s:3:"ℑ";s:4:"real";s:3:"ℜ";s:5:"trade";s:3:"™";s:7:"alefsym";s:3:"ℵ";s:4:"larr";s:3:"←";s:4:"uarr";s:3:"↑";s:4:"rarr";s:3:"→";s:4:"darr";s:3:"↓";s:4:"harr";s:3:"↔";s:5:"crarr";s:3:"↵";s:4:"lArr";s:3:"⇐";s:4:"uArr";s:3:"⇑";s:4:"rArr";s:3:"⇒";s:4:"dArr";s:3:"⇓";s:4:"hArr";s:3:"⇔";s:6:"forall";s:3:"∀";s:4:"part";s:3:"∂";s:5:"exist";s:3:"∃";s:5:"empty";s:3:"∅";s:5:"nabla";s:3:"∇";s:4:"isin";s:3:"∈";s:5:"notin";s:3:"∉";s:2:"ni";s:3:"∋";s:4:"prod";s:3:"∏";s:3:"sum";s:3:"∑";s:5:"minus";s:3:"−";s:6:"lowast";s:3:"∗";s:5:"radic";s:3:"√";s:4:"prop";s:3:"∝";s:5:"infin";s:3:"∞";s:3:"ang";s:3:"∠";s:3:"and";s:3:"∧";s:2:"or";s:3:"∨";s:3:"cap";s:3:"∩";s:3:"cup";s:3:"∪";s:3:"int";s:3:"∫";s:3:"sim";s:3:"∼";s:4:"cong";s:3:"≅";s:5:"asymp";s:3:"≈";s:2:"ne";s:3:"≠";s:5:"equiv";s:3:"≡";s:2:"le";s:3:"≤";s:2:"ge";s:3:"≥";s:3:"sub";s:3:"⊂";s:3:"sup";s:3:"⊃";s:4:"nsub";s:3:"⊄";s:4:"sube";s:3:"⊆";s:4:"supe";s:3:"⊇";s:5:"oplus";s:3:"⊕";s:6:"otimes";s:3:"⊗";s:4:"perp";s:3:"⊥";s:4:"sdot";s:3:"⋅";s:5:"lceil";s:3:"⌈";s:5:"rceil";s:3:"⌉";s:6:"lfloor";s:3:"⌊";s:6:"rfloor";s:3:"⌋";s:4:"lang";s:3:"〈";s:4:"rang";s:3:"〉";s:3:"loz";s:3:"◊";s:6:"spades";s:3:"♠";s:5:"clubs";s:3:"♣";s:6:"hearts";s:3:"♥";s:5:"diams";s:3:"♦";} \ No newline at end of file
+a:253:{s:4:"fnof";s:2:"ƒ";s:5:"Alpha";s:2:"Α";s:4:"Beta";s:2:"Β";s:5:"Gamma";s:2:"Γ";s:5:"Delta";s:2:"Δ";s:7:"Epsilon";s:2:"Ε";s:4:"Zeta";s:2:"Ζ";s:3:"Eta";s:2:"Η";s:5:"Theta";s:2:"Θ";s:4:"Iota";s:2:"Ι";s:5:"Kappa";s:2:"Κ";s:6:"Lambda";s:2:"Λ";s:2:"Mu";s:2:"Μ";s:2:"Nu";s:2:"Ν";s:2:"Xi";s:2:"Ξ";s:7:"Omicron";s:2:"Ο";s:2:"Pi";s:2:"Π";s:3:"Rho";s:2:"Ρ";s:5:"Sigma";s:2:"Σ";s:3:"Tau";s:2:"Τ";s:7:"Upsilon";s:2:"Υ";s:3:"Phi";s:2:"Φ";s:3:"Chi";s:2:"Χ";s:3:"Psi";s:2:"Ψ";s:5:"Omega";s:2:"Ω";s:5:"alpha";s:2:"α";s:4:"beta";s:2:"β";s:5:"gamma";s:2:"γ";s:5:"delta";s:2:"δ";s:7:"epsilon";s:2:"ε";s:4:"zeta";s:2:"ζ";s:3:"eta";s:2:"η";s:5:"theta";s:2:"θ";s:4:"iota";s:2:"ι";s:5:"kappa";s:2:"κ";s:6:"lambda";s:2:"λ";s:2:"mu";s:2:"μ";s:2:"nu";s:2:"ν";s:2:"xi";s:2:"ξ";s:7:"omicron";s:2:"ο";s:2:"pi";s:2:"π";s:3:"rho";s:2:"ρ";s:6:"sigmaf";s:2:"ς";s:5:"sigma";s:2:"σ";s:3:"tau";s:2:"τ";s:7:"upsilon";s:2:"υ";s:3:"phi";s:2:"φ";s:3:"chi";s:2:"χ";s:3:"psi";s:2:"ψ";s:5:"omega";s:2:"ω";s:8:"thetasym";s:2:"ϑ";s:5:"upsih";s:2:"ϒ";s:3:"piv";s:2:"ϖ";s:4:"bull";s:3:"•";s:6:"hellip";s:3:"…";s:5:"prime";s:3:"′";s:5:"Prime";s:3:"″";s:5:"oline";s:3:"‾";s:5:"frasl";s:3:"⁄";s:6:"weierp";s:3:"℘";s:5:"image";s:3:"ℑ";s:4:"real";s:3:"ℜ";s:5:"trade";s:3:"™";s:7:"alefsym";s:3:"ℵ";s:4:"larr";s:3:"←";s:4:"uarr";s:3:"↑";s:4:"rarr";s:3:"→";s:4:"darr";s:3:"↓";s:4:"harr";s:3:"↔";s:5:"crarr";s:3:"↵";s:4:"lArr";s:3:"⇐";s:4:"uArr";s:3:"⇑";s:4:"rArr";s:3:"⇒";s:4:"dArr";s:3:"⇓";s:4:"hArr";s:3:"⇔";s:6:"forall";s:3:"∀";s:4:"part";s:3:"∂";s:5:"exist";s:3:"∃";s:5:"empty";s:3:"∅";s:5:"nabla";s:3:"∇";s:4:"isin";s:3:"∈";s:5:"notin";s:3:"∉";s:2:"ni";s:3:"∋";s:4:"prod";s:3:"∏";s:3:"sum";s:3:"∑";s:5:"minus";s:3:"−";s:6:"lowast";s:3:"∗";s:5:"radic";s:3:"√";s:4:"prop";s:3:"∝";s:5:"infin";s:3:"∞";s:3:"ang";s:3:"∠";s:3:"and";s:3:"∧";s:2:"or";s:3:"∨";s:3:"cap";s:3:"∩";s:3:"cup";s:3:"∪";s:3:"int";s:3:"∫";s:6:"there4";s:3:"∴";s:3:"sim";s:3:"∼";s:4:"cong";s:3:"≅";s:5:"asymp";s:3:"≈";s:2:"ne";s:3:"≠";s:5:"equiv";s:3:"≡";s:2:"le";s:3:"≤";s:2:"ge";s:3:"≥";s:3:"sub";s:3:"⊂";s:3:"sup";s:3:"⊃";s:4:"nsub";s:3:"⊄";s:4:"sube";s:3:"⊆";s:4:"supe";s:3:"⊇";s:5:"oplus";s:3:"⊕";s:6:"otimes";s:3:"⊗";s:4:"perp";s:3:"⊥";s:4:"sdot";s:3:"⋅";s:5:"lceil";s:3:"⌈";s:5:"rceil";s:3:"⌉";s:6:"lfloor";s:3:"⌊";s:6:"rfloor";s:3:"⌋";s:4:"lang";s:3:"〈";s:4:"rang";s:3:"〉";s:3:"loz";s:3:"◊";s:6:"spades";s:3:"♠";s:5:"clubs";s:3:"♣";s:6:"hearts";s:3:"♥";s:5:"diams";s:3:"♦";s:4:"quot";s:1:""";s:3:"amp";s:1:"&";s:2:"lt";s:1:"<";s:2:"gt";s:1:">";s:4:"apos";s:1:"'";s:5:"OElig";s:2:"Œ";s:5:"oelig";s:2:"œ";s:6:"Scaron";s:2:"Š";s:6:"scaron";s:2:"š";s:4:"Yuml";s:2:"Ÿ";s:4:"circ";s:2:"ˆ";s:5:"tilde";s:2:"˜";s:4:"ensp";s:3:" ";s:4:"emsp";s:3:" ";s:6:"thinsp";s:3:" ";s:4:"zwnj";s:3:"‌";s:3:"zwj";s:3:"‍";s:3:"lrm";s:3:"‎";s:3:"rlm";s:3:"‏";s:5:"ndash";s:3:"–";s:5:"mdash";s:3:"—";s:5:"lsquo";s:3:"‘";s:5:"rsquo";s:3:"’";s:5:"sbquo";s:3:"‚";s:5:"ldquo";s:3:"“";s:5:"rdquo";s:3:"”";s:5:"bdquo";s:3:"„";s:6:"dagger";s:3:"†";s:6:"Dagger";s:3:"‡";s:6:"permil";s:3:"‰";s:6:"lsaquo";s:3:"‹";s:6:"rsaquo";s:3:"›";s:4:"euro";s:3:"€";s:4:"nbsp";s:2:" ";s:5:"iexcl";s:2:"¡";s:4:"cent";s:2:"¢";s:5:"pound";s:2:"£";s:6:"curren";s:2:"¤";s:3:"yen";s:2:"¥";s:6:"brvbar";s:2:"¦";s:4:"sect";s:2:"§";s:3:"uml";s:2:"¨";s:4:"copy";s:2:"©";s:4:"ordf";s:2:"ª";s:5:"laquo";s:2:"«";s:3:"not";s:2:"¬";s:3:"shy";s:2:"­";s:3:"reg";s:2:"®";s:4:"macr";s:2:"¯";s:3:"deg";s:2:"°";s:6:"plusmn";s:2:"±";s:4:"sup2";s:2:"²";s:4:"sup3";s:2:"³";s:5:"acute";s:2:"´";s:5:"micro";s:2:"µ";s:4:"para";s:2:"¶";s:6:"middot";s:2:"·";s:5:"cedil";s:2:"¸";s:4:"sup1";s:2:"¹";s:4:"ordm";s:2:"º";s:5:"raquo";s:2:"»";s:6:"frac14";s:2:"¼";s:6:"frac12";s:2:"½";s:6:"frac34";s:2:"¾";s:6:"iquest";s:2:"¿";s:6:"Agrave";s:2:"À";s:6:"Aacute";s:2:"Á";s:5:"Acirc";s:2:"Â";s:6:"Atilde";s:2:"Ã";s:4:"Auml";s:2:"Ä";s:5:"Aring";s:2:"Å";s:5:"AElig";s:2:"Æ";s:6:"Ccedil";s:2:"Ç";s:6:"Egrave";s:2:"È";s:6:"Eacute";s:2:"É";s:5:"Ecirc";s:2:"Ê";s:4:"Euml";s:2:"Ë";s:6:"Igrave";s:2:"Ì";s:6:"Iacute";s:2:"Í";s:5:"Icirc";s:2:"Î";s:4:"Iuml";s:2:"Ï";s:3:"ETH";s:2:"Ð";s:6:"Ntilde";s:2:"Ñ";s:6:"Ograve";s:2:"Ò";s:6:"Oacute";s:2:"Ó";s:5:"Ocirc";s:2:"Ô";s:6:"Otilde";s:2:"Õ";s:4:"Ouml";s:2:"Ö";s:5:"times";s:2:"×";s:6:"Oslash";s:2:"Ø";s:6:"Ugrave";s:2:"Ù";s:6:"Uacute";s:2:"Ú";s:5:"Ucirc";s:2:"Û";s:4:"Uuml";s:2:"Ü";s:6:"Yacute";s:2:"Ý";s:5:"THORN";s:2:"Þ";s:5:"szlig";s:2:"ß";s:6:"agrave";s:2:"à";s:6:"aacute";s:2:"á";s:5:"acirc";s:2:"â";s:6:"atilde";s:2:"ã";s:4:"auml";s:2:"ä";s:5:"aring";s:2:"å";s:5:"aelig";s:2:"æ";s:6:"ccedil";s:2:"ç";s:6:"egrave";s:2:"è";s:6:"eacute";s:2:"é";s:5:"ecirc";s:2:"ê";s:4:"euml";s:2:"ë";s:6:"igrave";s:2:"ì";s:6:"iacute";s:2:"í";s:5:"icirc";s:2:"î";s:4:"iuml";s:2:"ï";s:3:"eth";s:2:"ð";s:6:"ntilde";s:2:"ñ";s:6:"ograve";s:2:"ò";s:6:"oacute";s:2:"ó";s:5:"ocirc";s:2:"ô";s:6:"otilde";s:2:"õ";s:4:"ouml";s:2:"ö";s:6:"divide";s:2:"÷";s:6:"oslash";s:2:"ø";s:6:"ugrave";s:2:"ù";s:6:"uacute";s:2:"ú";s:5:"ucirc";s:2:"û";s:4:"uuml";s:2:"ü";s:6:"yacute";s:2:"ý";s:5:"thorn";s:2:"þ";s:4:"yuml";s:2:"ÿ";} \ No newline at end of file
diff --git a/library/HTMLPurifier/EntityParser.php b/library/HTMLPurifier/EntityParser.php
index 8c384472d..61529dcd9 100644
--- a/library/HTMLPurifier/EntityParser.php
+++ b/library/HTMLPurifier/EntityParser.php
@@ -12,19 +12,21 @@ class HTMLPurifier_EntityParser
/**
* Reference to entity lookup table.
+ * @type HTMLPurifier_EntityLookup
*/
protected $_entity_lookup;
/**
* Callback regex string for parsing entities.
+ * @type string
*/
protected $_substituteEntitiesRegex =
-'/&(?:[#]x([a-fA-F0-9]+)|[#]0*(\d+)|([A-Za-z_:][A-Za-z0-9.\-_:]*));?/';
-// 1. hex 2. dec 3. string (XML style)
-
+ '/&(?:[#]x([a-fA-F0-9]+)|[#]0*(\d+)|([A-Za-z_:][A-Za-z0-9.\-_:]*));?/';
+ // 1. hex 2. dec 3. string (XML style)
/**
* Decimal to parsed string conversion table for special entities.
+ * @type array
*/
protected $_special_dec2str =
array(
@@ -37,6 +39,7 @@ class HTMLPurifier_EntityParser
/**
* Stripped entity names to decimal conversion table for special entities.
+ * @type array
*/
protected $_special_ent2dec =
array(
@@ -51,41 +54,45 @@ class HTMLPurifier_EntityParser
* running this whenever you have parsed character is t3h 5uck, we run
* it before everything else.
*
- * @param $string String to have non-special entities parsed.
- * @returns Parsed string.
+ * @param string $string String to have non-special entities parsed.
+ * @return string Parsed string.
*/
- public function substituteNonSpecialEntities($string) {
+ public function substituteNonSpecialEntities($string)
+ {
// it will try to detect missing semicolons, but don't rely on it
return preg_replace_callback(
$this->_substituteEntitiesRegex,
array($this, 'nonSpecialEntityCallback'),
$string
- );
+ );
}
/**
* Callback function for substituteNonSpecialEntities() that does the work.
*
- * @param $matches PCRE matches array, with 0 the entire match, and
+ * @param array $matches PCRE matches array, with 0 the entire match, and
* either index 1, 2 or 3 set with a hex value, dec value,
* or string (respectively).
- * @returns Replacement string.
+ * @return string Replacement string.
*/
- protected function nonSpecialEntityCallback($matches) {
+ protected function nonSpecialEntityCallback($matches)
+ {
// replaces all but big five
$entity = $matches[0];
$is_num = (@$matches[0][1] === '#');
if ($is_num) {
$is_hex = (@$entity[2] === 'x');
$code = $is_hex ? hexdec($matches[1]) : (int) $matches[2];
-
// abort for special characters
- if (isset($this->_special_dec2str[$code])) return $entity;
-
+ if (isset($this->_special_dec2str[$code])) {
+ return $entity;
+ }
return HTMLPurifier_Encoder::unichr($code);
} else {
- if (isset($this->_special_ent2dec[$matches[3]])) return $entity;
+ if (isset($this->_special_ent2dec[$matches[3]])) {
+ return $entity;
+ }
if (!$this->_entity_lookup) {
$this->_entity_lookup = HTMLPurifier_EntityLookup::instance();
}
@@ -103,14 +110,16 @@ class HTMLPurifier_EntityParser
* @notice We try to avoid calling this function because otherwise, it
* would have to be called a lot (for every parsed section).
*
- * @param $string String to have non-special entities parsed.
- * @returns Parsed string.
+ * @param string $string String to have non-special entities parsed.
+ * @return string Parsed string.
*/
- public function substituteSpecialEntities($string) {
+ public function substituteSpecialEntities($string)
+ {
return preg_replace_callback(
$this->_substituteEntitiesRegex,
array($this, 'specialEntityCallback'),
- $string);
+ $string
+ );
}
/**
@@ -118,12 +127,13 @@ class HTMLPurifier_EntityParser
*
* This callback has same syntax as nonSpecialEntityCallback().
*
- * @param $matches PCRE-style matches array, with 0 the entire match, and
+ * @param array $matches PCRE-style matches array, with 0 the entire match, and
* either index 1, 2 or 3 set with a hex value, dec value,
* or string (respectively).
- * @returns Replacement string.
+ * @return string Replacement string.
*/
- protected function specialEntityCallback($matches) {
+ protected function specialEntityCallback($matches)
+ {
$entity = $matches[0];
$is_num = (@$matches[0][1] === '#');
if ($is_num) {
@@ -138,7 +148,6 @@ class HTMLPurifier_EntityParser
$entity;
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ErrorCollector.php b/library/HTMLPurifier/ErrorCollector.php
index 6713eaf77..d47e3f2e2 100644
--- a/library/HTMLPurifier/ErrorCollector.php
+++ b/library/HTMLPurifier/ErrorCollector.php
@@ -16,16 +16,46 @@ class HTMLPurifier_ErrorCollector
const MESSAGE = 2;
const CHILDREN = 3;
+ /**
+ * @type array
+ */
protected $errors;
+
+ /**
+ * @type array
+ */
protected $_current;
+
+ /**
+ * @type array
+ */
protected $_stacks = array(array());
+
+ /**
+ * @type HTMLPurifier_Language
+ */
protected $locale;
+
+ /**
+ * @type HTMLPurifier_Generator
+ */
protected $generator;
+
+ /**
+ * @type HTMLPurifier_Context
+ */
protected $context;
+ /**
+ * @type array
+ */
protected $lines = array();
- public function __construct($context) {
+ /**
+ * @param HTMLPurifier_Context $context
+ */
+ public function __construct($context)
+ {
$this->locale =& $context->get('Locale');
$this->context = $context;
$this->_current =& $this->_stacks[0];
@@ -34,13 +64,11 @@ class HTMLPurifier_ErrorCollector
/**
* Sends an error message to the collector for later use
- * @param $severity int Error severity, PHP error style (don't use E_USER_)
- * @param $msg string Error message text
- * @param $subst1 string First substitution for $msg
- * @param $subst2 string ...
+ * @param int $severity Error severity, PHP error style (don't use E_USER_)
+ * @param string $msg Error message text
*/
- public function send($severity, $msg) {
-
+ public function send($severity, $msg)
+ {
$args = array();
if (func_num_args() > 2) {
$args = func_get_args();
@@ -50,7 +78,7 @@ class HTMLPurifier_ErrorCollector
$token = $this->context->get('CurrentToken', true);
$line = $token ? $token->line : $this->context->get('CurrentLine', true);
- $col = $token ? $token->col : $this->context->get('CurrentCol', true);
+ $col = $token ? $token->col : $this->context->get('CurrentCol', true);
$attr = $this->context->get('CurrentAttr', true);
// perform special substitutions, also add custom parameters
@@ -60,7 +88,9 @@ class HTMLPurifier_ErrorCollector
}
if (!is_null($attr)) {
$subst['$CurrentAttr.Name'] = $attr;
- if (isset($token->attr[$attr])) $subst['$CurrentAttr.Value'] = $token->attr[$attr];
+ if (isset($token->attr[$attr])) {
+ $subst['$CurrentAttr.Value'] = $token->attr[$attr];
+ }
}
if (empty($args)) {
@@ -69,7 +99,9 @@ class HTMLPurifier_ErrorCollector
$msg = $this->locale->formatMessage($msg, $args);
}
- if (!empty($subst)) $msg = strtr($msg, $subst);
+ if (!empty($subst)) {
+ $msg = strtr($msg, $subst);
+ }
// (numerically indexed)
$error = array(
@@ -80,16 +112,15 @@ class HTMLPurifier_ErrorCollector
);
$this->_current[] = $error;
-
// NEW CODE BELOW ...
-
- $struct = null;
// Top-level errors are either:
// TOKEN type, if $value is set appropriately, or
// "syntax" type, if $value is null
$new_struct = new HTMLPurifier_ErrorStruct();
$new_struct->type = HTMLPurifier_ErrorStruct::TOKEN;
- if ($token) $new_struct->value = clone $token;
+ if ($token) {
+ $new_struct->value = clone $token;
+ }
if (is_int($line) && is_int($col)) {
if (isset($this->lines[$line][$col])) {
$struct = $this->lines[$line][$col];
@@ -128,30 +159,34 @@ class HTMLPurifier_ErrorCollector
/**
* Retrieves raw error data for custom formatter to use
- * @param List of arrays in format of array(line of error,
- * error severity, error message,
- * recursive sub-errors array)
*/
- public function getRaw() {
+ public function getRaw()
+ {
return $this->errors;
}
/**
* Default HTML formatting implementation for error messages
- * @param $config Configuration array, vital for HTML output nature
- * @param $errors Errors array to display; used for recursion.
+ * @param HTMLPurifier_Config $config Configuration, vital for HTML output nature
+ * @param array $errors Errors array to display; used for recursion.
+ * @return string
*/
- public function getHTMLFormatted($config, $errors = null) {
+ public function getHTMLFormatted($config, $errors = null)
+ {
$ret = array();
$this->generator = new HTMLPurifier_Generator($config, $this->context);
- if ($errors === null) $errors = $this->errors;
+ if ($errors === null) {
+ $errors = $this->errors;
+ }
// 'At line' message needs to be removed
// generation code for new structure goes here. It needs to be recursive.
foreach ($this->lines as $line => $col_array) {
- if ($line == -1) continue;
+ if ($line == -1) {
+ continue;
+ }
foreach ($col_array as $col => $struct) {
$this->_renderStruct($ret, $struct, $line, $col);
}
@@ -168,7 +203,8 @@ class HTMLPurifier_ErrorCollector
}
- private function _renderStruct(&$ret, $struct, $line = null, $col = null) {
+ private function _renderStruct(&$ret, $struct, $line = null, $col = null)
+ {
$stack = array($struct);
$context_stack = array(array());
while ($current = array_pop($stack)) {
@@ -194,7 +230,7 @@ class HTMLPurifier_ErrorCollector
//$string .= '</pre>';
$ret[] = $string;
}
- foreach ($current->children as $type => $array) {
+ foreach ($current->children as $array) {
$context[] = $current;
$stack = array_merge($stack, array_reverse($array, true));
for ($i = count($array); $i > 0; $i--) {
@@ -203,7 +239,6 @@ class HTMLPurifier_ErrorCollector
}
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/ErrorStruct.php b/library/HTMLPurifier/ErrorStruct.php
index 9bc8996ec..cf869d321 100644
--- a/library/HTMLPurifier/ErrorStruct.php
+++ b/library/HTMLPurifier/ErrorStruct.php
@@ -19,6 +19,7 @@ class HTMLPurifier_ErrorStruct
/**
* Type of this struct.
+ * @type string
*/
public $type;
@@ -28,11 +29,13 @@ class HTMLPurifier_ErrorStruct
* - TOKEN: Instance of HTMLPurifier_Token
* - ATTR: array('attr-name', 'value')
* - CSSPROP: array('prop-name', 'value')
+ * @type mixed
*/
public $value;
/**
* Errors registered for this structure.
+ * @type array
*/
public $errors = array();
@@ -40,10 +43,17 @@ class HTMLPurifier_ErrorStruct
* Child ErrorStructs that are from this structure. For example, a TOKEN
* ErrorStruct would contain ATTR ErrorStructs. This is a multi-dimensional
* array in structure: [TYPE]['identifier']
+ * @type array
*/
public $children = array();
- public function getChild($type, $id) {
+ /**
+ * @param string $type
+ * @param string $id
+ * @return mixed
+ */
+ public function getChild($type, $id)
+ {
if (!isset($this->children[$type][$id])) {
$this->children[$type][$id] = new HTMLPurifier_ErrorStruct();
$this->children[$type][$id]->type = $type;
@@ -51,10 +61,14 @@ class HTMLPurifier_ErrorStruct
return $this->children[$type][$id];
}
- public function addError($severity, $message) {
+ /**
+ * @param int $severity
+ * @param string $message
+ */
+ public function addError($severity, $message)
+ {
$this->errors[] = array($severity, $message);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Filter.php b/library/HTMLPurifier/Filter.php
index 9a0e7b09f..c1f41ee16 100644
--- a/library/HTMLPurifier/Filter.php
+++ b/library/HTMLPurifier/Filter.php
@@ -23,24 +23,34 @@ class HTMLPurifier_Filter
{
/**
- * Name of the filter for identification purposes
+ * Name of the filter for identification purposes.
+ * @type string
*/
public $name;
/**
* Pre-processor function, handles HTML before HTML Purifier
+ * @param string $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
*/
- public function preFilter($html, $config, $context) {
+ public function preFilter($html, $config, $context)
+ {
return $html;
}
/**
* Post-processor function, handles HTML after HTML Purifier
+ * @param string $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
*/
- public function postFilter($html, $config, $context) {
+ public function postFilter($html, $config, $context)
+ {
return $html;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Filter/ExtractStyleBlocks.php b/library/HTMLPurifier/Filter/ExtractStyleBlocks.php
index bbf78a663..08e62c16b 100644
--- a/library/HTMLPurifier/Filter/ExtractStyleBlocks.php
+++ b/library/HTMLPurifier/Filter/ExtractStyleBlocks.php
@@ -1,5 +1,13 @@
<?php
+// why is this a top level function? Because PHP 5.2.0 doesn't seem to
+// understand how to interpret this filter if it's a static method.
+// It's all really silly, but if we go this route it might be reasonable
+// to coalesce all of these methods into one.
+function htmlpurifier_filter_extractstyleblocks_muteerrorhandler()
+{
+}
+
/**
* This filter extracts <style> blocks from input HTML, cleans them up
* using CSSTidy, and then places them in $purifier->context->get('StyleBlocks')
@@ -16,30 +24,77 @@
*/
class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
{
-
+ /**
+ * @type string
+ */
public $name = 'ExtractStyleBlocks';
+
+ /**
+ * @type array
+ */
private $_styleMatches = array();
+
+ /**
+ * @type csstidy
+ */
private $_tidy;
- public function __construct() {
+ /**
+ * @type HTMLPurifier_AttrDef_HTML_ID
+ */
+ private $_id_attrdef;
+
+ /**
+ * @type HTMLPurifier_AttrDef_CSS_Ident
+ */
+ private $_class_attrdef;
+
+ /**
+ * @type HTMLPurifier_AttrDef_Enum
+ */
+ private $_enum_attrdef;
+
+ public function __construct()
+ {
$this->_tidy = new csstidy();
+ $this->_tidy->set_cfg('lowercase_s', false);
+ $this->_id_attrdef = new HTMLPurifier_AttrDef_HTML_ID(true);
+ $this->_class_attrdef = new HTMLPurifier_AttrDef_CSS_Ident();
+ $this->_enum_attrdef = new HTMLPurifier_AttrDef_Enum(
+ array(
+ 'first-child',
+ 'link',
+ 'visited',
+ 'active',
+ 'hover',
+ 'focus'
+ )
+ );
}
/**
* Save the contents of CSS blocks to style matches
- * @param $matches preg_replace style $matches array
+ * @param array $matches preg_replace style $matches array
*/
- protected function styleCallback($matches) {
+ protected function styleCallback($matches)
+ {
$this->_styleMatches[] = $matches[1];
}
/**
* Removes inline <style> tags from HTML, saves them for later use
+ * @param string $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
* @todo Extend to indicate non-text/css style blocks
*/
- public function preFilter($html, $config, $context) {
+ public function preFilter($html, $config, $context)
+ {
$tidy = $config->get('Filter.ExtractStyleBlocks.TidyImpl');
- if ($tidy !== null) $this->_tidy = $tidy;
+ if ($tidy !== null) {
+ $this->_tidy = $tidy;
+ }
$html = preg_replace_callback('#<style(?:\s.*)?>(.+)</style>#isU', array($this, 'styleCallback'), $html);
$style_blocks = $this->_styleMatches;
$this->_styleMatches = array(); // reset
@@ -55,12 +110,14 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
/**
* Takes CSS (the stuff found in <style>) and cleans it.
* @warning Requires CSSTidy <http://csstidy.sourceforge.net/>
- * @param $css CSS styling to clean
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
- * @return Cleaned CSS
+ * @param string $css CSS styling to clean
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @throws HTMLPurifier_Exception
+ * @return string Cleaned CSS
*/
- public function cleanCSS($css, $config, $context) {
+ public function cleanCSS($css, $config, $context)
+ {
// prepare scope
$scope = $config->get('Filter.ExtractStyleBlocks.Scope');
if ($scope !== null) {
@@ -77,27 +134,170 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
$css = substr($css, 0, -3);
}
$css = trim($css);
+ set_error_handler('htmlpurifier_filter_extractstyleblocks_muteerrorhandler');
$this->_tidy->parse($css);
+ restore_error_handler();
$css_definition = $config->getDefinition('CSS');
+ $html_definition = $config->getDefinition('HTML');
+ $new_css = array();
foreach ($this->_tidy->css as $k => $decls) {
// $decls are all CSS declarations inside an @ selector
$new_decls = array();
foreach ($decls as $selector => $style) {
$selector = trim($selector);
- if ($selector === '') continue; // should not happen
- if ($selector[0] === '+') {
- if ($selector !== '' && $selector[0] === '+') continue;
- }
- if (!empty($scopes)) {
- $new_selector = array(); // because multiple ones are possible
- $selectors = array_map('trim', explode(',', $selector));
- foreach ($scopes as $s1) {
- foreach ($selectors as $s2) {
- $new_selector[] = "$s1 $s2";
+ if ($selector === '') {
+ continue;
+ } // should not happen
+ // Parse the selector
+ // Here is the relevant part of the CSS grammar:
+ //
+ // ruleset
+ // : selector [ ',' S* selector ]* '{' ...
+ // selector
+ // : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
+ // combinator
+ // : '+' S*
+ // : '>' S*
+ // simple_selector
+ // : element_name [ HASH | class | attrib | pseudo ]*
+ // | [ HASH | class | attrib | pseudo ]+
+ // element_name
+ // : IDENT | '*'
+ // ;
+ // class
+ // : '.' IDENT
+ // ;
+ // attrib
+ // : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
+ // [ IDENT | STRING ] S* ]? ']'
+ // ;
+ // pseudo
+ // : ':' [ IDENT | FUNCTION S* [IDENT S*]? ')' ]
+ // ;
+ //
+ // For reference, here are the relevant tokens:
+ //
+ // HASH #{name}
+ // IDENT {ident}
+ // INCLUDES ==
+ // DASHMATCH |=
+ // STRING {string}
+ // FUNCTION {ident}\(
+ //
+ // And the lexical scanner tokens
+ //
+ // name {nmchar}+
+ // nmchar [_a-z0-9-]|{nonascii}|{escape}
+ // nonascii [\240-\377]
+ // escape {unicode}|\\[^\r\n\f0-9a-f]
+ // unicode \\{h}}{1,6}(\r\n|[ \t\r\n\f])?
+ // ident -?{nmstart}{nmchar*}
+ // nmstart [_a-z]|{nonascii}|{escape}
+ // string {string1}|{string2}
+ // string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\"
+ // string2 \'([^\n\r\f\\"]|\\{nl}|{escape})*\'
+ //
+ // We'll implement a subset (in order to reduce attack
+ // surface); in particular:
+ //
+ // - No Unicode support
+ // - No escapes support
+ // - No string support (by proxy no attrib support)
+ // - element_name is matched against allowed
+ // elements (some people might find this
+ // annoying...)
+ // - Pseudo-elements one of :first-child, :link,
+ // :visited, :active, :hover, :focus
+
+ // handle ruleset
+ $selectors = array_map('trim', explode(',', $selector));
+ $new_selectors = array();
+ foreach ($selectors as $sel) {
+ // split on +, > and spaces
+ $basic_selectors = preg_split('/\s*([+> ])\s*/', $sel, -1, PREG_SPLIT_DELIM_CAPTURE);
+ // even indices are chunks, odd indices are
+ // delimiters
+ $nsel = null;
+ $delim = null; // guaranteed to be non-null after
+ // two loop iterations
+ for ($i = 0, $c = count($basic_selectors); $i < $c; $i++) {
+ $x = $basic_selectors[$i];
+ if ($i % 2) {
+ // delimiter
+ if ($x === ' ') {
+ $delim = ' ';
+ } else {
+ $delim = ' ' . $x . ' ';
+ }
+ } else {
+ // simple selector
+ $components = preg_split('/([#.:])/', $x, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $sdelim = null;
+ $nx = null;
+ for ($j = 0, $cc = count($components); $j < $cc; $j++) {
+ $y = $components[$j];
+ if ($j === 0) {
+ if ($y === '*' || isset($html_definition->info[$y = strtolower($y)])) {
+ $nx = $y;
+ } else {
+ // $nx stays null; this matters
+ // if we don't manage to find
+ // any valid selector content,
+ // in which case we ignore the
+ // outer $delim
+ }
+ } elseif ($j % 2) {
+ // set delimiter
+ $sdelim = $y;
+ } else {
+ $attrdef = null;
+ if ($sdelim === '#') {
+ $attrdef = $this->_id_attrdef;
+ } elseif ($sdelim === '.') {
+ $attrdef = $this->_class_attrdef;
+ } elseif ($sdelim === ':') {
+ $attrdef = $this->_enum_attrdef;
+ } else {
+ throw new HTMLPurifier_Exception('broken invariant sdelim and preg_split');
+ }
+ $r = $attrdef->validate($y, $config, $context);
+ if ($r !== false) {
+ if ($r !== true) {
+ $y = $r;
+ }
+ if ($nx === null) {
+ $nx = '';
+ }
+ $nx .= $sdelim . $y;
+ }
+ }
+ }
+ if ($nx !== null) {
+ if ($nsel === null) {
+ $nsel = $nx;
+ } else {
+ $nsel .= $delim . $nx;
+ }
+ } else {
+ // delimiters to the left of invalid
+ // basic selector ignored
+ }
+ }
+ }
+ if ($nsel !== null) {
+ if (!empty($scopes)) {
+ foreach ($scopes as $s) {
+ $new_selectors[] = "$s $nsel";
+ }
+ } else {
+ $new_selectors[] = $nsel;
}
}
- $selector = implode(', ', $new_selector); // now it's a string
}
+ if (empty($new_selectors)) {
+ continue;
+ }
+ $selector = implode(', ', $new_selectors);
foreach ($style as $name => $value) {
if (!isset($css_definition->info[$name])) {
unset($style[$name]);
@@ -105,15 +305,19 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
}
$def = $css_definition->info[$name];
$ret = $def->validate($value, $config, $context);
- if ($ret === false) unset($style[$name]);
- else $style[$name] = $ret;
+ if ($ret === false) {
+ unset($style[$name]);
+ } else {
+ $style[$name] = $ret;
+ }
}
$new_decls[$selector] = $style;
}
- $this->_tidy->css[$k] = $new_decls;
+ $new_css[$k] = $new_decls;
}
// remove stuff that shouldn't be used, could be reenabled
// after security risks are analyzed
+ $this->_tidy->css = $new_css;
$this->_tidy->import = array();
$this->_tidy->charset = null;
$this->_tidy->namespace = null;
@@ -122,14 +326,13 @@ class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter
// that no funny business occurs (i.e. </style> in a font-family prop).
if ($config->get('Filter.ExtractStyleBlocks.Escaping')) {
$css = str_replace(
- array('<', '>', '&'),
+ array('<', '>', '&'),
array('\3C ', '\3E ', '\26 '),
$css
);
}
return $css;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Filter/YouTube.php b/library/HTMLPurifier/Filter/YouTube.php
index 23df221ea..411519ad6 100644
--- a/library/HTMLPurifier/Filter/YouTube.php
+++ b/library/HTMLPurifier/Filter/YouTube.php
@@ -3,36 +3,62 @@
class HTMLPurifier_Filter_YouTube extends HTMLPurifier_Filter
{
+ /**
+ * @type string
+ */
public $name = 'YouTube';
- public function preFilter($html, $config, $context) {
- $pre_regex = '#<object[^>]+>.+?'.
+ /**
+ * @param string $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
+ */
+ public function preFilter($html, $config, $context)
+ {
+ $pre_regex = '#<object[^>]+>.+?' .
'http://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?</object>#s';
$pre_replace = '<span class="youtube-embed">\1</span>';
return preg_replace($pre_regex, $pre_replace, $html);
}
- public function postFilter($html, $config, $context) {
+ /**
+ * @param string $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
+ */
+ public function postFilter($html, $config, $context)
+ {
$post_regex = '#<span class="youtube-embed">((?:v|cp)/[A-Za-z0-9\-_=]+)</span>#';
return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html);
}
- protected function armorUrl($url) {
+ /**
+ * @param $url
+ * @return string
+ */
+ protected function armorUrl($url)
+ {
return str_replace('--', '-&#45;', $url);
}
- protected function postFilterCallback($matches) {
+ /**
+ * @param array $matches
+ * @return string
+ */
+ protected function postFilterCallback($matches)
+ {
$url = $this->armorUrl($matches[1]);
- return '<object width="425" height="350" type="application/x-shockwave-flash" '.
- 'data="http://www.youtube.com/'.$url.'">'.
- '<param name="movie" value="http://www.youtube.com/'.$url.'"></param>'.
- '<!--[if IE]>'.
- '<embed src="http://www.youtube.com/'.$url.'"'.
- 'type="application/x-shockwave-flash"'.
- 'wmode="transparent" width="425" height="350" />'.
- '<![endif]-->'.
- '</object>';
-
+ return '<object width="425" height="350" type="application/x-shockwave-flash" ' .
+ 'data="http://www.youtube.com/' . $url . '">' .
+ '<param name="movie" value="http://www.youtube.com/' . $url . '"></param>' .
+ '<!--[if IE]>' .
+ '<embed src="http://www.youtube.com/' . $url . '"' .
+ 'type="application/x-shockwave-flash"' .
+ 'wmode="transparent" width="425" height="350" />' .
+ '<![endif]-->' .
+ '</object>';
}
}
diff --git a/library/HTMLPurifier/Generator.php b/library/HTMLPurifier/Generator.php
index 4a6241727..6fb568714 100644
--- a/library/HTMLPurifier/Generator.php
+++ b/library/HTMLPurifier/Generator.php
@@ -11,49 +11,64 @@ class HTMLPurifier_Generator
{
/**
- * Whether or not generator should produce XML output
+ * Whether or not generator should produce XML output.
+ * @type bool
*/
private $_xhtml = true;
/**
- * :HACK: Whether or not generator should comment the insides of <script> tags
+ * :HACK: Whether or not generator should comment the insides of <script> tags.
+ * @type bool
*/
private $_scriptFix = false;
/**
* Cache of HTMLDefinition during HTML output to determine whether or
* not attributes should be minimized.
+ * @type HTMLPurifier_HTMLDefinition
*/
private $_def;
/**
- * Cache of %Output.SortAttr
+ * Cache of %Output.SortAttr.
+ * @type bool
*/
private $_sortAttr;
/**
- * Cache of %Output.FlashCompat
+ * Cache of %Output.FlashCompat.
+ * @type bool
*/
private $_flashCompat;
/**
+ * Cache of %Output.FixInnerHTML.
+ * @type bool
+ */
+ private $_innerHTMLFix;
+
+ /**
* Stack for keeping track of object information when outputting IE
* compatibility code.
+ * @type array
*/
private $_flashStack = array();
/**
* Configuration for the generator
+ * @type HTMLPurifier_Config
*/
protected $config;
/**
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
*/
- public function __construct($config, $context) {
+ public function __construct($config, $context)
+ {
$this->config = $config;
$this->_scriptFix = $config->get('Output.CommentScriptContents');
+ $this->_innerHTMLFix = $config->get('Output.FixInnerHTML');
$this->_sortAttr = $config->get('Output.SortAttr');
$this->_flashCompat = $config->get('Output.FlashCompat');
$this->_def = $config->getHTMLDefinition();
@@ -62,12 +77,14 @@ class HTMLPurifier_Generator
/**
* Generates HTML from an array of tokens.
- * @param $tokens Array of HTMLPurifier_Token
- * @param $config HTMLPurifier_Config object
- * @return Generated HTML
+ * @param HTMLPurifier_Token[] $tokens Array of HTMLPurifier_Token
+ * @return string Generated HTML
*/
- public function generateFromTokens($tokens) {
- if (!$tokens) return '';
+ public function generateFromTokens($tokens)
+ {
+ if (!$tokens) {
+ return '';
+ }
// Basic algorithm
$html = '';
@@ -86,30 +103,41 @@ class HTMLPurifier_Generator
// Tidy cleanup
if (extension_loaded('tidy') && $this->config->get('Output.TidyFormat')) {
$tidy = new Tidy;
- $tidy->parseString($html, array(
- 'indent'=> true,
- 'output-xhtml' => $this->_xhtml,
- 'show-body-only' => true,
- 'indent-spaces' => 2,
- 'wrap' => 68,
- ), 'utf8');
+ $tidy->parseString(
+ $html,
+ array(
+ 'indent'=> true,
+ 'output-xhtml' => $this->_xhtml,
+ 'show-body-only' => true,
+ 'indent-spaces' => 2,
+ 'wrap' => 68,
+ ),
+ 'utf8'
+ );
$tidy->cleanRepair();
$html = (string) $tidy; // explicit cast necessary
}
// Normalize newlines to system defined value
- $nl = $this->config->get('Output.Newline');
- if ($nl === null) $nl = PHP_EOL;
- if ($nl !== "\n") $html = str_replace("\n", $nl, $html);
+ if ($this->config->get('Core.NormalizeNewlines')) {
+ $nl = $this->config->get('Output.Newline');
+ if ($nl === null) {
+ $nl = PHP_EOL;
+ }
+ if ($nl !== "\n") {
+ $html = str_replace("\n", $nl, $html);
+ }
+ }
return $html;
}
/**
* Generates HTML from a single token.
- * @param $token HTMLPurifier_Token object.
- * @return Generated HTML
+ * @param HTMLPurifier_Token $token HTMLPurifier_Token object.
+ * @return string Generated HTML
*/
- public function generateFromToken($token) {
+ public function generateFromToken($token)
+ {
if (!$token instanceof HTMLPurifier_Token) {
trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING);
return '';
@@ -130,19 +158,7 @@ class HTMLPurifier_Generator
$_extra = '';
if ($this->_flashCompat) {
if ($token->name == "object" && !empty($this->_flashStack)) {
- $flash = array_pop($this->_flashStack);
- $compat_token = new HTMLPurifier_Token_Empty("embed");
- foreach ($flash->attr as $name => $val) {
- if ($name == "classid") continue;
- if ($name == "type") continue;
- if ($name == "data") $name = "src";
- $compat_token->attr[$name] = $val;
- }
- foreach ($flash->param as $name => $val) {
- if ($name == "movie") $name = "src";
- $compat_token->attr[$name] = $val;
- }
- $_extra = "<!--[if IE]>".$this->generateFromToken($compat_token)."<![endif]-->";
+ // doesn't do anything for now
}
}
return $_extra . '</' . $token->name . '>';
@@ -169,11 +185,16 @@ class HTMLPurifier_Generator
/**
* Special case processor for the contents of script tags
+ * @param HTMLPurifier_Token $token HTMLPurifier_Token object.
+ * @return string
* @warning This runs into problems if there's already a literal
* --> somewhere inside the script contents.
*/
- public function generateScriptFromToken($token) {
- if (!$token instanceof HTMLPurifier_Token_Text) return $this->generateFromToken($token);
+ public function generateScriptFromToken($token)
+ {
+ if (!$token instanceof HTMLPurifier_Token_Text) {
+ return $this->generateFromToken($token);
+ }
// Thanks <http://lachy.id.au/log/2005/05/script-comments>
$data = preg_replace('#//\s*$#', '', $token->data);
return '<!--//--><![CDATA[//><!--' . "\n" . trim($data) . "\n" . '//--><!]]>';
@@ -182,24 +203,60 @@ class HTMLPurifier_Generator
/**
* Generates attribute declarations from attribute array.
* @note This does not include the leading or trailing space.
- * @param $assoc_array_of_attributes Attribute array
- * @param $element Name of element attributes are for, used to check
+ * @param array $assoc_array_of_attributes Attribute array
+ * @param string $element Name of element attributes are for, used to check
* attribute minimization.
- * @return Generate HTML fragment for insertion.
+ * @return string Generated HTML fragment for insertion.
*/
- public function generateAttributes($assoc_array_of_attributes, $element = false) {
+ public function generateAttributes($assoc_array_of_attributes, $element = '')
+ {
$html = '';
- if ($this->_sortAttr) ksort($assoc_array_of_attributes);
+ if ($this->_sortAttr) {
+ ksort($assoc_array_of_attributes);
+ }
foreach ($assoc_array_of_attributes as $key => $value) {
if (!$this->_xhtml) {
// Remove namespaced attributes
- if (strpos($key, ':') !== false) continue;
+ if (strpos($key, ':') !== false) {
+ continue;
+ }
// Check if we should minimize the attribute: val="val" -> val
if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) {
$html .= $key . ' ';
continue;
}
}
+ // Workaround for Internet Explorer innerHTML bug.
+ // Essentially, Internet Explorer, when calculating
+ // innerHTML, omits quotes if there are no instances of
+ // angled brackets, quotes or spaces. However, when parsing
+ // HTML (for example, when you assign to innerHTML), it
+ // treats backticks as quotes. Thus,
+ // <img alt="``" />
+ // becomes
+ // <img alt=`` />
+ // becomes
+ // <img alt='' />
+ // Fortunately, all we need to do is trigger an appropriate
+ // quoting style, which we do by adding an extra space.
+ // This also is consistent with the W3C spec, which states
+ // that user agents may ignore leading or trailing
+ // whitespace (in fact, most don't, at least for attributes
+ // like alt, but an extra space at the end is barely
+ // noticeable). Still, we have a configuration knob for
+ // this, since this transformation is not necesary if you
+ // don't process user input with innerHTML or you don't plan
+ // on supporting Internet Explorer.
+ if ($this->_innerHTMLFix) {
+ if (strpos($value, '`') !== false) {
+ // check if correct quoting style would not already be
+ // triggered
+ if (strcspn($value, '"\' <>') === strlen($value)) {
+ // protect!
+ $value .= ' ';
+ }
+ }
+ }
$html .= $key.'="'.$this->escape($value).'" ';
}
return rtrim($html);
@@ -210,15 +267,20 @@ class HTMLPurifier_Generator
* @todo This really ought to be protected, but until we have a facility
* for properly generating HTML here w/o using tokens, it stays
* public.
- * @param $string String data to escape for HTML.
- * @param $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is
+ * @param string $string String data to escape for HTML.
+ * @param int $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is
* permissible for non-attribute output.
- * @return String escaped data.
+ * @return string escaped data.
*/
- public function escape($string, $quote = ENT_COMPAT) {
+ public function escape($string, $quote = null)
+ {
+ // Workaround for APC bug on Mac Leopard reported by sidepodcast
+ // http://htmlpurifier.org/phorum/read.php?3,4823,4846
+ if ($quote === null) {
+ $quote = ENT_COMPAT;
+ }
return htmlspecialchars($string, $quote, 'UTF-8');
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLDefinition.php b/library/HTMLPurifier/HTMLDefinition.php
index c99ac11eb..9b7b334dd 100644
--- a/library/HTMLPurifier/HTMLDefinition.php
+++ b/library/HTMLPurifier/HTMLDefinition.php
@@ -29,60 +29,71 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
// FULLY-PUBLIC VARIABLES ---------------------------------------------
/**
- * Associative array of element names to HTMLPurifier_ElementDef
+ * Associative array of element names to HTMLPurifier_ElementDef.
+ * @type HTMLPurifier_ElementDef[]
*/
public $info = array();
/**
* Associative array of global attribute name to attribute definition.
+ * @type array
*/
public $info_global_attr = array();
/**
* String name of parent element HTML will be going into.
+ * @type string
*/
public $info_parent = 'div';
/**
* Definition for parent element, allows parent element to be a
* tag that's not allowed inside the HTML fragment.
+ * @type HTMLPurifier_ElementDef
*/
public $info_parent_def;
/**
- * String name of element used to wrap inline elements in block context
+ * String name of element used to wrap inline elements in block context.
+ * @type string
* @note This is rarely used except for BLOCKQUOTEs in strict mode
*/
public $info_block_wrapper = 'p';
/**
- * Associative array of deprecated tag name to HTMLPurifier_TagTransform
+ * Associative array of deprecated tag name to HTMLPurifier_TagTransform.
+ * @type array
*/
public $info_tag_transform = array();
/**
* Indexed list of HTMLPurifier_AttrTransform to be performed before validation.
+ * @type HTMLPurifier_AttrTransform[]
*/
public $info_attr_transform_pre = array();
/**
* Indexed list of HTMLPurifier_AttrTransform to be performed after validation.
+ * @type HTMLPurifier_AttrTransform[]
*/
public $info_attr_transform_post = array();
/**
* Nested lookup array of content set name (Block, Inline) to
* element name to whether or not it belongs in that content set.
+ * @type array
*/
public $info_content_sets = array();
/**
* Indexed list of HTMLPurifier_Injector to be used.
+ * @type HTMLPurifier_Injector[]
*/
public $info_injector = array();
/**
* Doctype object
+ * @type HTMLPurifier_Doctype
*/
public $doctype;
@@ -94,12 +105,13 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
* Adds a custom attribute to a pre-existing element
* @note This is strictly convenience, and does not have a corresponding
* method in HTMLPurifier_HTMLModule
- * @param $element_name String element name to add attribute to
- * @param $attr_name String name of attribute
- * @param $def Attribute definition, can be string or object, see
+ * @param string $element_name Element name to add attribute to
+ * @param string $attr_name Name of attribute
+ * @param mixed $def Attribute definition, can be string or object, see
* HTMLPurifier_AttrTypes for details
*/
- public function addAttribute($element_name, $attr_name, $def) {
+ public function addAttribute($element_name, $attr_name, $def)
+ {
$module = $this->getAnonymousModule();
if (!isset($module->info[$element_name])) {
$element = $module->addBlankElement($element_name);
@@ -111,10 +123,11 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
/**
* Adds a custom element to your HTML definition
- * @note See HTMLPurifier_HTMLModule::addElement for detailed
+ * @see HTMLPurifier_HTMLModule::addElement() for detailed
* parameter and return value descriptions.
*/
- public function addElement($element_name, $type, $contents, $attr_collections, $attributes = array()) {
+ public function addElement($element_name, $type, $contents, $attr_collections, $attributes = array())
+ {
$module = $this->getAnonymousModule();
// assume that if the user is calling this, the element
// is safe. This may not be a good idea
@@ -125,10 +138,13 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
/**
* Adds a blank element to your HTML definition, for overriding
* existing behavior
- * @note See HTMLPurifier_HTMLModule::addBlankElement for detailed
+ * @param string $element_name
+ * @return HTMLPurifier_ElementDef
+ * @see HTMLPurifier_HTMLModule::addBlankElement() for detailed
* parameter and return value descriptions.
*/
- public function addBlankElement($element_name) {
+ public function addBlankElement($element_name)
+ {
$module = $this->getAnonymousModule();
$element = $module->addBlankElement($element_name);
return $element;
@@ -138,8 +154,10 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
* Retrieves a reference to the anonymous module, so you can
* bust out advanced features without having to make your own
* module.
+ * @return HTMLPurifier_HTMLModule
*/
- public function getAnonymousModule() {
+ public function getAnonymousModule()
+ {
if (!$this->_anonModule) {
$this->_anonModule = new HTMLPurifier_HTMLModule();
$this->_anonModule->name = 'Anonymous';
@@ -147,22 +165,33 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
return $this->_anonModule;
}
- private $_anonModule;
-
+ private $_anonModule = null;
// PUBLIC BUT INTERNAL VARIABLES --------------------------------------
+ /**
+ * @type string
+ */
public $type = 'HTML';
- public $manager; /**< Instance of HTMLPurifier_HTMLModuleManager */
+
+ /**
+ * @type HTMLPurifier_HTMLModuleManager
+ */
+ public $manager;
/**
* Performs low-cost, preliminary initialization.
*/
- public function __construct() {
+ public function __construct()
+ {
$this->manager = new HTMLPurifier_HTMLModuleManager();
}
- protected function doSetup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ protected function doSetup($config)
+ {
$this->processModules($config);
$this->setupConfigStuff($config);
unset($this->manager);
@@ -176,9 +205,10 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
/**
* Extract out the information from the manager
+ * @param HTMLPurifier_Config $config
*/
- protected function processModules($config) {
-
+ protected function processModules($config)
+ {
if ($this->_anonModule) {
// for user specific changes
// this is late-loaded so we don't have to deal with PHP4
@@ -191,40 +221,53 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
$this->doctype = $this->manager->doctype;
foreach ($this->manager->modules as $module) {
- foreach($module->info_tag_transform as $k => $v) {
- if ($v === false) unset($this->info_tag_transform[$k]);
- else $this->info_tag_transform[$k] = $v;
+ foreach ($module->info_tag_transform as $k => $v) {
+ if ($v === false) {
+ unset($this->info_tag_transform[$k]);
+ } else {
+ $this->info_tag_transform[$k] = $v;
+ }
}
- foreach($module->info_attr_transform_pre as $k => $v) {
- if ($v === false) unset($this->info_attr_transform_pre[$k]);
- else $this->info_attr_transform_pre[$k] = $v;
+ foreach ($module->info_attr_transform_pre as $k => $v) {
+ if ($v === false) {
+ unset($this->info_attr_transform_pre[$k]);
+ } else {
+ $this->info_attr_transform_pre[$k] = $v;
+ }
}
- foreach($module->info_attr_transform_post as $k => $v) {
- if ($v === false) unset($this->info_attr_transform_post[$k]);
- else $this->info_attr_transform_post[$k] = $v;
+ foreach ($module->info_attr_transform_post as $k => $v) {
+ if ($v === false) {
+ unset($this->info_attr_transform_post[$k]);
+ } else {
+ $this->info_attr_transform_post[$k] = $v;
+ }
}
foreach ($module->info_injector as $k => $v) {
- if ($v === false) unset($this->info_injector[$k]);
- else $this->info_injector[$k] = $v;
+ if ($v === false) {
+ unset($this->info_injector[$k]);
+ } else {
+ $this->info_injector[$k] = $v;
+ }
}
}
-
$this->info = $this->manager->getElements();
$this->info_content_sets = $this->manager->contentSets->lookup;
-
}
/**
* Sets up stuff based on config. We need a better way of doing this.
+ * @param HTMLPurifier_Config $config
*/
- protected function setupConfigStuff($config) {
-
+ protected function setupConfigStuff($config)
+ {
$block_wrapper = $config->get('HTML.BlockWrapper');
if (isset($this->info_content_sets['Block'][$block_wrapper])) {
$this->info_block_wrapper = $block_wrapper;
} else {
- trigger_error('Cannot use non-block element as block wrapper',
- E_USER_ERROR);
+ trigger_error(
+ 'Cannot use non-block element as block wrapper',
+ E_USER_ERROR
+ );
}
$parent = $config->get('HTML.Parent');
@@ -233,14 +276,15 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
$this->info_parent = $parent;
$this->info_parent_def = $def;
} else {
- trigger_error('Cannot use unrecognized element as parent',
- E_USER_ERROR);
+ trigger_error(
+ 'Cannot use unrecognized element as parent',
+ E_USER_ERROR
+ );
$this->info_parent_def = $this->manager->getElement($this->info_parent, true);
}
// support template text
- $support = "(for information on implementing this, see the ".
- "support forums) ";
+ $support = "(for information on implementing this, see the support forums) ";
// setup allowed elements -----------------------------------------
@@ -256,7 +300,9 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
if (is_array($allowed_elements)) {
foreach ($this->info as $name => $d) {
- if(!isset($allowed_elements[$name])) unset($this->info[$name]);
+ if (!isset($allowed_elements[$name])) {
+ unset($this->info[$name]);
+ }
unset($allowed_elements[$name]);
}
// emit errors
@@ -270,7 +316,6 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
$allowed_attributes_mutable = $allowed_attributes; // by copy!
if (is_array($allowed_attributes)) {
-
// This actually doesn't do anything, since we went away from
// global attributes. It's possible that userland code uses
// it, but HTMLModuleManager doesn't!
@@ -285,7 +330,9 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
unset($allowed_attributes_mutable[$key]);
}
}
- if ($delete) unset($this->info_global_attr[$attr]);
+ if ($delete) {
+ unset($this->info_global_attr[$attr]);
+ }
}
foreach ($this->info as $tag => $info) {
@@ -300,7 +347,16 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
unset($allowed_attributes_mutable[$key]);
}
}
- if ($delete) unset($this->info[$tag]->attr[$attr]);
+ if ($delete) {
+ if ($this->info[$tag]->attr[$attr]->required) {
+ trigger_error(
+ "Required attribute '$attr' in element '$tag' " .
+ "was not allowed, which means '$tag' will not be allowed either",
+ E_USER_WARNING
+ );
+ }
+ unset($this->info[$tag]->attr[$attr]);
+ }
}
}
// emit errors
@@ -313,23 +369,29 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
$element = htmlspecialchars($bits[0]);
$attribute = htmlspecialchars($bits[1]);
if (!isset($this->info[$element])) {
- trigger_error("Cannot allow attribute '$attribute' if element '$element' is not allowed/supported $support");
+ trigger_error(
+ "Cannot allow attribute '$attribute' if element " .
+ "'$element' is not allowed/supported $support"
+ );
} else {
- trigger_error("Attribute '$attribute' in element '$element' not supported $support",
- E_USER_WARNING);
+ trigger_error(
+ "Attribute '$attribute' in element '$element' not supported $support",
+ E_USER_WARNING
+ );
}
break;
}
// otherwise fall through
case 1:
$attribute = htmlspecialchars($bits[0]);
- trigger_error("Global attribute '$attribute' is not ".
+ trigger_error(
+ "Global attribute '$attribute' is not ".
"supported in any elements $support",
- E_USER_WARNING);
+ E_USER_WARNING
+ );
break;
}
}
-
}
// setup forbidden elements ---------------------------------------
@@ -343,25 +405,34 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
continue;
}
foreach ($info->attr as $attr => $x) {
- if (
- isset($forbidden_attributes["$tag@$attr"]) ||
+ if (isset($forbidden_attributes["$tag@$attr"]) ||
isset($forbidden_attributes["*@$attr"]) ||
isset($forbidden_attributes[$attr])
) {
unset($this->info[$tag]->attr[$attr]);
continue;
- } // this segment might get removed eventually
- elseif (isset($forbidden_attributes["$tag.$attr"])) {
+ } elseif (isset($forbidden_attributes["$tag.$attr"])) { // this segment might get removed eventually
// $tag.$attr are not user supplied, so no worries!
- trigger_error("Error with $tag.$attr: tag.attr syntax not supported for HTML.ForbiddenAttributes; use tag@attr instead", E_USER_WARNING);
+ trigger_error(
+ "Error with $tag.$attr: tag.attr syntax not supported for " .
+ "HTML.ForbiddenAttributes; use tag@attr instead",
+ E_USER_WARNING
+ );
}
}
}
foreach ($forbidden_attributes as $key => $v) {
- if (strlen($key) < 2) continue;
- if ($key[0] != '*') continue;
+ if (strlen($key) < 2) {
+ continue;
+ }
+ if ($key[0] != '*') {
+ continue;
+ }
if ($key[1] == '.') {
- trigger_error("Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead", E_USER_WARNING);
+ trigger_error(
+ "Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead",
+ E_USER_WARNING
+ );
}
}
@@ -380,12 +451,12 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
* separate lists for processing. Format is element[attr1|attr2],element2...
* @warning Although it's largely drawn from TinyMCE's implementation,
* it is different, and you'll probably have to modify your lists
- * @param $list String list to parse
- * @param array($allowed_elements, $allowed_attributes)
+ * @param array $list String list to parse
+ * @return array
* @todo Give this its own class, probably static interface
*/
- public function parseTinyMCEAllowedList($list) {
-
+ public function parseTinyMCEAllowedList($list)
+ {
$list = str_replace(array(' ', "\t"), '', $list);
$elements = array();
@@ -393,7 +464,9 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
$chunks = preg_split('/(,|[\n\r]+)/', $list);
foreach ($chunks as $chunk) {
- if (empty($chunk)) continue;
+ if (empty($chunk)) {
+ continue;
+ }
// remove TinyMCE element control characters
if (!strpos($chunk, '[')) {
$element = $chunk;
@@ -401,20 +474,20 @@ class HTMLPurifier_HTMLDefinition extends HTMLPurifier_Definition
} else {
list($element, $attr) = explode('[', $chunk);
}
- if ($element !== '*') $elements[$element] = true;
- if (!$attr) continue;
+ if ($element !== '*') {
+ $elements[$element] = true;
+ }
+ if (!$attr) {
+ continue;
+ }
$attr = substr($attr, 0, strlen($attr) - 1); // remove trailing ]
$attr = explode('|', $attr);
foreach ($attr as $key) {
$attributes["$element.$key"] = true;
}
}
-
return array($elements, $attributes);
-
}
-
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule.php b/library/HTMLPurifier/HTMLModule.php
index 072cf6808..bb3a9230b 100644
--- a/library/HTMLPurifier/HTMLModule.php
+++ b/library/HTMLPurifier/HTMLModule.php
@@ -21,13 +21,15 @@ class HTMLPurifier_HTMLModule
// -- Overloadable ----------------------------------------------------
/**
- * Short unique string identifier of the module
+ * Short unique string identifier of the module.
+ * @type string
*/
public $name;
/**
- * Informally, a list of elements this module changes. Not used in
- * any significant way.
+ * Informally, a list of elements this module changes.
+ * Not used in any significant way.
+ * @type array
*/
public $elements = array();
@@ -35,6 +37,7 @@ class HTMLPurifier_HTMLModule
* Associative array of element names to element definitions.
* Some definitions may be incomplete, to be merged in later
* with the full definition.
+ * @type array
*/
public $info = array();
@@ -43,6 +46,7 @@ class HTMLPurifier_HTMLModule
* This is commonly used to, say, add an A element to the Inline
* content set. This corresponds to an internal variable $content_sets
* and NOT info_content_sets member variable of HTMLDefinition.
+ * @type array
*/
public $content_sets = array();
@@ -53,21 +57,25 @@ class HTMLPurifier_HTMLModule
* the style attribute to the Core. Corresponds to HTMLDefinition's
* attr_collections->info, since the object's data is only info,
* with extra behavior associated with it.
+ * @type array
*/
public $attr_collections = array();
/**
- * Associative array of deprecated tag name to HTMLPurifier_TagTransform
+ * Associative array of deprecated tag name to HTMLPurifier_TagTransform.
+ * @type array
*/
public $info_tag_transform = array();
/**
* List of HTMLPurifier_AttrTransform to be performed before validation.
+ * @type array
*/
public $info_attr_transform_pre = array();
/**
* List of HTMLPurifier_AttrTransform to be performed after validation.
+ * @type array
*/
public $info_attr_transform_post = array();
@@ -76,6 +84,7 @@ class HTMLPurifier_HTMLModule
* An injector will only be invoked if all of it's pre-requisites are met;
* if an injector fails setup, there will be no error; it will simply be
* silently disabled.
+ * @type array
*/
public $info_injector = array();
@@ -84,6 +93,7 @@ class HTMLPurifier_HTMLModule
* For optimization reasons: may save a call to a function. Be sure
* to set it if you do implement getChildDef(), otherwise it will have
* no effect!
+ * @type bool
*/
public $defines_child_def = false;
@@ -94,6 +104,7 @@ class HTMLPurifier_HTMLModule
* which is based off of safe HTML, to explicitly say, "This is safe," even
* though there are modules which are "unsafe")
*
+ * @type bool
* @note Previously, safety could be applied at an element level granularity.
* We've removed this ability, so in order to add "unsafe" elements
* or attributes, a dedicated module with this property set to false
@@ -106,51 +117,62 @@ class HTMLPurifier_HTMLModule
* content_model and content_model_type member variables of
* the HTMLPurifier_ElementDef class. There is a similar function
* in HTMLPurifier_HTMLDefinition.
- * @param $def HTMLPurifier_ElementDef instance
+ * @param HTMLPurifier_ElementDef $def
* @return HTMLPurifier_ChildDef subclass
*/
- public function getChildDef($def) {return false;}
+ public function getChildDef($def)
+ {
+ return false;
+ }
// -- Convenience -----------------------------------------------------
/**
* Convenience function that sets up a new element
- * @param $element Name of element to add
- * @param $type What content set should element be registered to?
+ * @param string $element Name of element to add
+ * @param string|bool $type What content set should element be registered to?
* Set as false to skip this step.
- * @param $contents Allowed children in form of:
+ * @param string $contents Allowed children in form of:
* "$content_model_type: $content_model"
- * @param $attr_includes What attribute collections to register to
+ * @param array $attr_includes What attribute collections to register to
* element?
- * @param $attr What unique attributes does the element define?
- * @note See ElementDef for in-depth descriptions of these parameters.
- * @return Created element definition object, so you
+ * @param array $attr What unique attributes does the element define?
+ * @see HTMLPurifier_ElementDef:: for in-depth descriptions of these parameters.
+ * @return HTMLPurifier_ElementDef Created element definition object, so you
* can set advanced parameters
*/
- public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) {
+ public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array())
+ {
$this->elements[] = $element;
// parse content_model
list($content_model_type, $content_model) = $this->parseContents($contents);
// merge in attribute inclusions
$this->mergeInAttrIncludes($attr, $attr_includes);
// add element to content sets
- if ($type) $this->addElementToContentSet($element, $type);
+ if ($type) {
+ $this->addElementToContentSet($element, $type);
+ }
// create element
$this->info[$element] = HTMLPurifier_ElementDef::create(
- $content_model, $content_model_type, $attr
+ $content_model,
+ $content_model_type,
+ $attr
);
// literal object $contents means direct child manipulation
- if (!is_string($contents)) $this->info[$element]->child = $contents;
+ if (!is_string($contents)) {
+ $this->info[$element]->child = $contents;
+ }
return $this->info[$element];
}
/**
* Convenience function that creates a totally blank, non-standalone
* element.
- * @param $element Name of element to create
- * @return Created element
+ * @param string $element Name of element to create
+ * @return HTMLPurifier_ElementDef Created element
*/
- public function addBlankElement($element) {
+ public function addBlankElement($element)
+ {
if (!isset($this->info[$element])) {
$this->elements[] = $element;
$this->info[$element] = new HTMLPurifier_ElementDef();
@@ -163,27 +185,35 @@ class HTMLPurifier_HTMLModule
/**
* Convenience function that registers an element to a content set
- * @param Element to register
- * @param Name content set (warning: case sensitive, usually upper-case
+ * @param string $element Element to register
+ * @param string $type Name content set (warning: case sensitive, usually upper-case
* first letter)
*/
- public function addElementToContentSet($element, $type) {
- if (!isset($this->content_sets[$type])) $this->content_sets[$type] = '';
- else $this->content_sets[$type] .= ' | ';
+ public function addElementToContentSet($element, $type)
+ {
+ if (!isset($this->content_sets[$type])) {
+ $this->content_sets[$type] = '';
+ } else {
+ $this->content_sets[$type] .= ' | ';
+ }
$this->content_sets[$type] .= $element;
}
/**
* Convenience function that transforms single-string contents
* into separate content model and content model type
- * @param $contents Allowed children in form of:
+ * @param string $contents Allowed children in form of:
* "$content_model_type: $content_model"
+ * @return array
* @note If contents is an object, an array of two nulls will be
* returned, and the callee needs to take the original $contents
* and use it directly.
*/
- public function parseContents($contents) {
- if (!is_string($contents)) return array(null, null); // defer
+ public function parseContents($contents)
+ {
+ if (!is_string($contents)) {
+ return array(null, null);
+ } // defer
switch ($contents) {
// check for shorthand content model forms
case 'Empty':
@@ -202,13 +232,17 @@ class HTMLPurifier_HTMLModule
/**
* Convenience function that merges a list of attribute includes into
* an attribute array.
- * @param $attr Reference to attr array to modify
- * @param $attr_includes Array of includes / string include to merge in
+ * @param array $attr Reference to attr array to modify
+ * @param array $attr_includes Array of includes / string include to merge in
*/
- public function mergeInAttrIncludes(&$attr, $attr_includes) {
+ public function mergeInAttrIncludes(&$attr, $attr_includes)
+ {
if (!is_array($attr_includes)) {
- if (empty($attr_includes)) $attr_includes = array();
- else $attr_includes = array($attr_includes);
+ if (empty($attr_includes)) {
+ $attr_includes = array();
+ } else {
+ $attr_includes = array($attr_includes);
+ }
}
$attr[0] = $attr_includes;
}
@@ -216,16 +250,21 @@ class HTMLPurifier_HTMLModule
/**
* Convenience function that generates a lookup table with boolean
* true as value.
- * @param $list List of values to turn into a lookup
+ * @param string $list List of values to turn into a lookup
* @note You can also pass an arbitrary number of arguments in
* place of the regular argument
- * @return Lookup array equivalent of list
+ * @return array array equivalent of list
*/
- public function makeLookup($list) {
- if (is_string($list)) $list = func_get_args();
+ public function makeLookup($list)
+ {
+ if (is_string($list)) {
+ $list = func_get_args();
+ }
$ret = array();
foreach ($list as $value) {
- if (is_null($value)) continue;
+ if (is_null($value)) {
+ continue;
+ }
$ret[$value] = true;
}
return $ret;
@@ -235,10 +274,11 @@ class HTMLPurifier_HTMLModule
* Lazy load construction of the module after determining whether
* or not it's needed, and also when a finalized configuration object
* is available.
- * @param $config Instance of HTMLPurifier_Config
+ * @param HTMLPurifier_Config $config
*/
- public function setup($config) {}
-
+ public function setup($config)
+ {
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Bdo.php b/library/HTMLPurifier/HTMLModule/Bdo.php
index 3d66f1b4e..1e67c790d 100644
--- a/library/HTMLPurifier/HTMLModule/Bdo.php
+++ b/library/HTMLPurifier/HTMLModule/Bdo.php
@@ -7,25 +7,38 @@
class HTMLPurifier_HTMLModule_Bdo extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'Bdo';
+
+ /**
+ * @type array
+ */
public $attr_collections = array(
'I18N' => array('dir' => false)
);
- public function setup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$bdo = $this->addElement(
- 'bdo', 'Inline', 'Inline', array('Core', 'Lang'),
+ 'bdo',
+ 'Inline',
+ 'Inline',
+ array('Core', 'Lang'),
array(
'dir' => 'Enum#ltr,rtl', // required
// The Abstract Module specification has the attribute
// inclusions wrong for bdo: bdo allows Lang
)
);
- $bdo->attr_transform_post['required-dir'] = new HTMLPurifier_AttrTransform_BdoDir();
+ $bdo->attr_transform_post[] = new HTMLPurifier_AttrTransform_BdoDir();
$this->attr_collections['I18N']['dir'] = 'Enum#ltr,rtl';
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/CommonAttributes.php b/library/HTMLPurifier/HTMLModule/CommonAttributes.php
index 7c15da84f..a96ab1bef 100644
--- a/library/HTMLPurifier/HTMLModule/CommonAttributes.php
+++ b/library/HTMLPurifier/HTMLModule/CommonAttributes.php
@@ -2,8 +2,14 @@
class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'CommonAttributes';
+ /**
+ * @type array
+ */
public $attr_collections = array(
'Core' => array(
0 => array('Style'),
@@ -20,7 +26,6 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
0 => array('Core', 'I18N')
)
);
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Edit.php b/library/HTMLPurifier/HTMLModule/Edit.php
index ff9369055..a9042a357 100644
--- a/library/HTMLPurifier/HTMLModule/Edit.php
+++ b/library/HTMLPurifier/HTMLModule/Edit.php
@@ -7,9 +7,16 @@
class HTMLPurifier_HTMLModule_Edit extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'Edit';
- public function setup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$contents = 'Chameleon: #PCDATA | Inline ! #PCDATA | Flow';
$attr = array(
'cite' => 'URI',
@@ -26,13 +33,23 @@ class HTMLPurifier_HTMLModule_Edit extends HTMLPurifier_HTMLModule
// Inline context ! Block context (exclamation mark is
// separator, see getChildDef for parsing)
+ /**
+ * @type bool
+ */
public $defines_child_def = true;
- public function getChildDef($def) {
- if ($def->content_model_type != 'chameleon') return false;
+
+ /**
+ * @param HTMLPurifier_ElementDef $def
+ * @return HTMLPurifier_ChildDef_Chameleon
+ */
+ public function getChildDef($def)
+ {
+ if ($def->content_model_type != 'chameleon') {
+ return false;
+ }
$value = explode('!', $def->content_model);
return new HTMLPurifier_ChildDef_Chameleon($value[0], $value[1]);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Forms.php b/library/HTMLPurifier/HTMLModule/Forms.php
index 44c22f6f8..6f7ddbc05 100644
--- a/library/HTMLPurifier/HTMLModule/Forms.php
+++ b/library/HTMLPurifier/HTMLModule/Forms.php
@@ -5,86 +5,142 @@
*/
class HTMLPurifier_HTMLModule_Forms extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'Forms';
+
+ /**
+ * @type bool
+ */
public $safe = false;
+ /**
+ * @type array
+ */
public $content_sets = array(
'Block' => 'Form',
'Inline' => 'Formctrl',
);
- public function setup($config) {
- $form = $this->addElement('form', 'Form',
- 'Required: Heading | List | Block | fieldset', 'Common', array(
- 'accept' => 'ContentTypes',
- 'accept-charset' => 'Charsets',
- 'action*' => 'URI',
- 'method' => 'Enum#get,post',
- // really ContentType, but these two are the only ones used today
- 'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data',
- ));
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $form = $this->addElement(
+ 'form',
+ 'Form',
+ 'Required: Heading | List | Block | fieldset',
+ 'Common',
+ array(
+ 'accept' => 'ContentTypes',
+ 'accept-charset' => 'Charsets',
+ 'action*' => 'URI',
+ 'method' => 'Enum#get,post',
+ // really ContentType, but these two are the only ones used today
+ 'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data',
+ )
+ );
$form->excludes = array('form' => true);
- $input = $this->addElement('input', 'Formctrl', 'Empty', 'Common', array(
- 'accept' => 'ContentTypes',
- 'accesskey' => 'Character',
- 'alt' => 'Text',
- 'checked' => 'Bool#checked',
- 'disabled' => 'Bool#disabled',
- 'maxlength' => 'Number',
- 'name' => 'CDATA',
- 'readonly' => 'Bool#readonly',
- 'size' => 'Number',
- 'src' => 'URI#embeds',
- 'tabindex' => 'Number',
- 'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image',
- 'value' => 'CDATA',
- ));
+ $input = $this->addElement(
+ 'input',
+ 'Formctrl',
+ 'Empty',
+ 'Common',
+ array(
+ 'accept' => 'ContentTypes',
+ 'accesskey' => 'Character',
+ 'alt' => 'Text',
+ 'checked' => 'Bool#checked',
+ 'disabled' => 'Bool#disabled',
+ 'maxlength' => 'Number',
+ 'name' => 'CDATA',
+ 'readonly' => 'Bool#readonly',
+ 'size' => 'Number',
+ 'src' => 'URI#embedded',
+ 'tabindex' => 'Number',
+ 'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image',
+ 'value' => 'CDATA',
+ )
+ );
$input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input();
- $this->addElement('select', 'Formctrl', 'Required: optgroup | option', 'Common', array(
- 'disabled' => 'Bool#disabled',
- 'multiple' => 'Bool#multiple',
- 'name' => 'CDATA',
- 'size' => 'Number',
- 'tabindex' => 'Number',
- ));
-
- $this->addElement('option', false, 'Optional: #PCDATA', 'Common', array(
- 'disabled' => 'Bool#disabled',
- 'label' => 'Text',
- 'selected' => 'Bool#selected',
- 'value' => 'CDATA',
- ));
+ $this->addElement(
+ 'select',
+ 'Formctrl',
+ 'Required: optgroup | option',
+ 'Common',
+ array(
+ 'disabled' => 'Bool#disabled',
+ 'multiple' => 'Bool#multiple',
+ 'name' => 'CDATA',
+ 'size' => 'Number',
+ 'tabindex' => 'Number',
+ )
+ );
+
+ $this->addElement(
+ 'option',
+ false,
+ 'Optional: #PCDATA',
+ 'Common',
+ array(
+ 'disabled' => 'Bool#disabled',
+ 'label' => 'Text',
+ 'selected' => 'Bool#selected',
+ 'value' => 'CDATA',
+ )
+ );
// It's illegal for there to be more than one selected, but not
// be multiple. Also, no selected means undefined behavior. This might
// be difficult to implement; perhaps an injector, or a context variable.
- $textarea = $this->addElement('textarea', 'Formctrl', 'Optional: #PCDATA', 'Common', array(
- 'accesskey' => 'Character',
- 'cols*' => 'Number',
- 'disabled' => 'Bool#disabled',
- 'name' => 'CDATA',
- 'readonly' => 'Bool#readonly',
- 'rows*' => 'Number',
- 'tabindex' => 'Number',
- ));
+ $textarea = $this->addElement(
+ 'textarea',
+ 'Formctrl',
+ 'Optional: #PCDATA',
+ 'Common',
+ array(
+ 'accesskey' => 'Character',
+ 'cols*' => 'Number',
+ 'disabled' => 'Bool#disabled',
+ 'name' => 'CDATA',
+ 'readonly' => 'Bool#readonly',
+ 'rows*' => 'Number',
+ 'tabindex' => 'Number',
+ )
+ );
$textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea();
- $button = $this->addElement('button', 'Formctrl', 'Optional: #PCDATA | Heading | List | Block | Inline', 'Common', array(
- 'accesskey' => 'Character',
- 'disabled' => 'Bool#disabled',
- 'name' => 'CDATA',
- 'tabindex' => 'Number',
- 'type' => 'Enum#button,submit,reset',
- 'value' => 'CDATA',
- ));
+ $button = $this->addElement(
+ 'button',
+ 'Formctrl',
+ 'Optional: #PCDATA | Heading | List | Block | Inline',
+ 'Common',
+ array(
+ 'accesskey' => 'Character',
+ 'disabled' => 'Bool#disabled',
+ 'name' => 'CDATA',
+ 'tabindex' => 'Number',
+ 'type' => 'Enum#button,submit,reset',
+ 'value' => 'CDATA',
+ )
+ );
// For exclusions, ideally we'd specify content sets, not literal elements
$button->excludes = $this->makeLookup(
- 'form', 'fieldset', // Form
- 'input', 'select', 'textarea', 'label', 'button', // Formctrl
- 'a' // as per HTML 4.01 spec, this is omitted by modularization
+ 'form',
+ 'fieldset', // Form
+ 'input',
+ 'select',
+ 'textarea',
+ 'label',
+ 'button', // Formctrl
+ 'a', // as per HTML 4.01 spec, this is omitted by modularization
+ 'isindex',
+ 'iframe' // legacy items
);
// Extra exclusion: img usemap="" is not permitted within this element.
@@ -94,24 +150,40 @@ class HTMLPurifier_HTMLModule_Forms extends HTMLPurifier_HTMLModule
// This is HIGHLY user-unfriendly; we need a custom child-def for this
$this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common');
- $label = $this->addElement('label', 'Formctrl', 'Optional: #PCDATA | Inline', 'Common', array(
- 'accesskey' => 'Character',
- // 'for' => 'IDREF', // IDREF not implemented, cannot allow
- ));
+ $label = $this->addElement(
+ 'label',
+ 'Formctrl',
+ 'Optional: #PCDATA | Inline',
+ 'Common',
+ array(
+ 'accesskey' => 'Character',
+ // 'for' => 'IDREF', // IDREF not implemented, cannot allow
+ )
+ );
$label->excludes = array('label' => true);
- $this->addElement('legend', false, 'Optional: #PCDATA | Inline', 'Common', array(
- 'accesskey' => 'Character',
- ));
-
- $this->addElement('optgroup', false, 'Required: option', 'Common', array(
- 'disabled' => 'Bool#disabled',
- 'label*' => 'Text',
- ));
+ $this->addElement(
+ 'legend',
+ false,
+ 'Optional: #PCDATA | Inline',
+ 'Common',
+ array(
+ 'accesskey' => 'Character',
+ )
+ );
+ $this->addElement(
+ 'optgroup',
+ false,
+ 'Required: option',
+ 'Common',
+ array(
+ 'disabled' => 'Bool#disabled',
+ 'label*' => 'Text',
+ )
+ );
// Don't forget an injector for <isindex>. This one's a little complex
// because it maps to multiple elements.
-
}
}
diff --git a/library/HTMLPurifier/HTMLModule/Hypertext.php b/library/HTMLPurifier/HTMLModule/Hypertext.php
index d7e9bdd27..72d7a31e6 100644
--- a/library/HTMLPurifier/HTMLModule/Hypertext.php
+++ b/library/HTMLPurifier/HTMLModule/Hypertext.php
@@ -6,11 +6,21 @@
class HTMLPurifier_HTMLModule_Hypertext extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'Hypertext';
- public function setup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$a = $this->addElement(
- 'a', 'Inline', 'Inline', 'Common',
+ 'a',
+ 'Inline',
+ 'Inline',
+ 'Common',
array(
// 'accesskey' => 'Character',
// 'charset' => 'Charset',
@@ -25,7 +35,6 @@ class HTMLPurifier_HTMLModule_Hypertext extends HTMLPurifier_HTMLModule
$a->formatting = true;
$a->excludes = array('a' => true);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Iframe.php b/library/HTMLPurifier/HTMLModule/Iframe.php
new file mode 100644
index 000000000..f7e7c91c0
--- /dev/null
+++ b/library/HTMLPurifier/HTMLModule/Iframe.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * XHTML 1.1 Iframe Module provides inline frames.
+ *
+ * @note This module is not considered safe unless an Iframe
+ * whitelisting mechanism is specified. Currently, the only
+ * such mechanism is %URL.SafeIframeRegexp
+ */
+class HTMLPurifier_HTMLModule_Iframe extends HTMLPurifier_HTMLModule
+{
+
+ /**
+ * @type string
+ */
+ public $name = 'Iframe';
+
+ /**
+ * @type bool
+ */
+ public $safe = false;
+
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ if ($config->get('HTML.SafeIframe')) {
+ $this->safe = true;
+ }
+ $this->addElement(
+ 'iframe',
+ 'Inline',
+ 'Flow',
+ 'Common',
+ array(
+ 'src' => 'URI#embedded',
+ 'width' => 'Length',
+ 'height' => 'Length',
+ 'name' => 'ID',
+ 'scrolling' => 'Enum#yes,no,auto',
+ 'frameborder' => 'Enum#0,1',
+ 'longdesc' => 'URI',
+ 'marginheight' => 'Pixels',
+ 'marginwidth' => 'Pixels',
+ )
+ );
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Image.php b/library/HTMLPurifier/HTMLModule/Image.php
index 948d435bc..0f5fdb3ba 100644
--- a/library/HTMLPurifier/HTMLModule/Image.php
+++ b/library/HTMLPurifier/HTMLModule/Image.php
@@ -8,18 +8,28 @@
class HTMLPurifier_HTMLModule_Image extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'Image';
- public function setup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$max = $config->get('HTML.MaxImgLength');
$img = $this->addElement(
- 'img', 'Inline', 'Empty', 'Common',
+ 'img',
+ 'Inline',
+ 'Empty',
+ 'Common',
array(
'alt*' => 'Text',
// According to the spec, it's Length, but percents can
// be abused, so we allow only Pixels.
'height' => 'Pixels#' . $max,
- 'width' => 'Pixels#' . $max,
+ 'width' => 'Pixels#' . $max,
'longdesc' => 'URI',
'src*' => new HTMLPurifier_AttrDef_URI(true), // embedded
)
@@ -34,7 +44,6 @@ class HTMLPurifier_HTMLModule_Image extends HTMLPurifier_HTMLModule
$img->attr_transform_post[] =
new HTMLPurifier_AttrTransform_ImgRequired();
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Legacy.php b/library/HTMLPurifier/HTMLModule/Legacy.php
index df33927ba..86b529957 100644
--- a/library/HTMLPurifier/HTMLModule/Legacy.php
+++ b/library/HTMLPurifier/HTMLModule/Legacy.php
@@ -18,29 +18,58 @@
class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'Legacy';
- public function setup($config) {
-
- $this->addElement('basefont', 'Inline', 'Empty', false, array(
- 'color' => 'Color',
- 'face' => 'Text', // extremely broad, we should
- 'size' => 'Text', // tighten it
- 'id' => 'ID'
- ));
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $this->addElement(
+ 'basefont',
+ 'Inline',
+ 'Empty',
+ null,
+ array(
+ 'color' => 'Color',
+ 'face' => 'Text', // extremely broad, we should
+ 'size' => 'Text', // tighten it
+ 'id' => 'ID'
+ )
+ );
$this->addElement('center', 'Block', 'Flow', 'Common');
- $this->addElement('dir', 'Block', 'Required: li', 'Common', array(
- 'compact' => 'Bool#compact'
- ));
- $this->addElement('font', 'Inline', 'Inline', array('Core', 'I18N'), array(
- 'color' => 'Color',
- 'face' => 'Text', // extremely broad, we should
- 'size' => 'Text', // tighten it
- ));
- $this->addElement('menu', 'Block', 'Required: li', 'Common', array(
- 'compact' => 'Bool#compact'
- ));
+ $this->addElement(
+ 'dir',
+ 'Block',
+ 'Required: li',
+ 'Common',
+ array(
+ 'compact' => 'Bool#compact'
+ )
+ );
+ $this->addElement(
+ 'font',
+ 'Inline',
+ 'Inline',
+ array('Core', 'I18N'),
+ array(
+ 'color' => 'Color',
+ 'face' => 'Text', // extremely broad, we should
+ 'size' => 'Text', // tighten it
+ )
+ );
+ $this->addElement(
+ 'menu',
+ 'Block',
+ 'Required: li',
+ 'Common',
+ array(
+ 'compact' => 'Bool#compact'
+ )
+ );
$s = $this->addElement('s', 'Inline', 'Inline', 'Common');
$s->formatting = true;
@@ -89,7 +118,7 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
$hr->attr['width'] = 'Length';
$img = $this->addBlankElement('img');
- $img->attr['align'] = 'Enum#top,middle,bottom,left,right';
+ $img->attr['align'] = 'IAlign';
$img->attr['border'] = 'Pixels';
$img->attr['hspace'] = 'Pixels';
$img->attr['vspace'] = 'Pixels';
@@ -98,7 +127,7 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
$li = $this->addBlankElement('li');
$li->attr['value'] = new HTMLPurifier_AttrDef_Integer();
- $li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle';
+ $li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle';
$ol = $this->addBlankElement('ol');
$ol->attr['compact'] = 'Bool#compact';
@@ -136,8 +165,22 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
$ul->attr['compact'] = 'Bool#compact';
$ul->attr['type'] = 'Enum#square,disc,circle';
- }
+ // "safe" modifications to "unsafe" elements
+ // WARNING: If you want to add support for an unsafe, legacy
+ // attribute, make a new TrustedLegacy module with the trusted
+ // bit set appropriately
+ $form = $this->addBlankElement('form');
+ $form->content_model = 'Flow | #PCDATA';
+ $form->content_model_type = 'optional';
+ $form->attr['target'] = 'FrameTarget';
+
+ $input = $this->addBlankElement('input');
+ $input->attr['align'] = 'IAlign';
+
+ $legend = $this->addBlankElement('legend');
+ $legend->attr['align'] = 'LAlign';
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/List.php b/library/HTMLPurifier/HTMLModule/List.php
index 74d4522f4..7a20ff701 100644
--- a/library/HTMLPurifier/HTMLModule/List.php
+++ b/library/HTMLPurifier/HTMLModule/List.php
@@ -5,7 +5,9 @@
*/
class HTMLPurifier_HTMLModule_List extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'List';
// According to the abstract schema, the List content set is a fully formed
@@ -17,13 +19,26 @@ class HTMLPurifier_HTMLModule_List extends HTMLPurifier_HTMLModule
// we don't have support for such nested expressions without using
// the incredibly inefficient and draconic Custom ChildDef.
+ /**
+ * @type array
+ */
public $content_sets = array('Flow' => 'List');
- public function setup($config) {
- $ol = $this->addElement('ol', 'List', 'Required: li', 'Common');
- $ol->wrap = "li";
- $ul = $this->addElement('ul', 'List', 'Required: li', 'Common');
- $ul->wrap = "li";
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $ol = $this->addElement('ol', 'List', new HTMLPurifier_ChildDef_List(), 'Common');
+ $ul = $this->addElement('ul', 'List', new HTMLPurifier_ChildDef_List(), 'Common');
+ // XXX The wrap attribute is handled by MakeWellFormed. This is all
+ // quite unsatisfactory, because we generated this
+ // *specifically* for lists, and now a big chunk of the handling
+ // is done properly by the List ChildDef. So actually, we just
+ // want enough information to make autoclosing work properly,
+ // and then hand off the tricky stuff to the ChildDef.
+ $ol->wrap = 'li';
+ $ul->wrap = 'li';
$this->addElement('dl', 'List', 'Required: dt | dd', 'Common');
$this->addElement('li', false, 'Flow', 'Common');
@@ -31,7 +46,6 @@ class HTMLPurifier_HTMLModule_List extends HTMLPurifier_HTMLModule
$this->addElement('dd', false, 'Flow', 'Common');
$this->addElement('dt', false, 'Inline', 'Common');
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Name.php b/library/HTMLPurifier/HTMLModule/Name.php
index 05694b450..60c054515 100644
--- a/library/HTMLPurifier/HTMLModule/Name.php
+++ b/library/HTMLPurifier/HTMLModule/Name.php
@@ -2,20 +2,25 @@
class HTMLPurifier_HTMLModule_Name extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'Name';
- public function setup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$elements = array('a', 'applet', 'form', 'frame', 'iframe', 'img', 'map');
foreach ($elements as $name) {
$element = $this->addBlankElement($name);
$element->attr['name'] = 'CDATA';
if (!$config->get('HTML.Attr.Name.UseCDATA')) {
- $element->attr_transform_post['NameSync'] = new HTMLPurifier_AttrTransform_NameSync();
+ $element->attr_transform_post[] = new HTMLPurifier_AttrTransform_NameSync();
}
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Nofollow.php b/library/HTMLPurifier/HTMLModule/Nofollow.php
new file mode 100644
index 000000000..dc9410a89
--- /dev/null
+++ b/library/HTMLPurifier/HTMLModule/Nofollow.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * Module adds the nofollow attribute transformation to a tags. It
+ * is enabled by HTML.Nofollow
+ */
+class HTMLPurifier_HTMLModule_Nofollow extends HTMLPurifier_HTMLModule
+{
+
+ /**
+ * @type string
+ */
+ public $name = 'Nofollow';
+
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $a = $this->addBlankElement('a');
+ $a->attr_transform_post[] = new HTMLPurifier_AttrTransform_Nofollow();
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php b/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php
index 5f1b14abb..da722253a 100644
--- a/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php
+++ b/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php
@@ -2,8 +2,14 @@
class HTMLPurifier_HTMLModule_NonXMLCommonAttributes extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'NonXMLCommonAttributes';
+ /**
+ * @type array
+ */
public $attr_collections = array(
'Lang' => array(
'lang' => 'LanguageCode',
diff --git a/library/HTMLPurifier/HTMLModule/Object.php b/library/HTMLPurifier/HTMLModule/Object.php
index 193c1011f..2f9efc5c8 100644
--- a/library/HTMLPurifier/HTMLModule/Object.php
+++ b/library/HTMLPurifier/HTMLModule/Object.php
@@ -7,13 +7,26 @@
*/
class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'Object';
- public $safe = false;
- public function setup($config) {
+ /**
+ * @type bool
+ */
+ public $safe = false;
- $this->addElement('object', 'Inline', 'Optional: #PCDATA | Flow | param', 'Common',
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $this->addElement(
+ 'object',
+ 'Inline',
+ 'Optional: #PCDATA | Flow | param',
+ 'Common',
array(
'archive' => 'URI',
'classid' => 'URI',
@@ -30,18 +43,20 @@ class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule
)
);
- $this->addElement('param', false, 'Empty', false,
+ $this->addElement(
+ 'param',
+ false,
+ 'Empty',
+ null,
array(
'id' => 'ID',
'name*' => 'Text',
'type' => 'Text',
'value' => 'Text',
'valuetype' => 'Enum#data,ref,object'
- )
+ )
);
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Presentation.php b/library/HTMLPurifier/HTMLModule/Presentation.php
index 8ff0b5ed7..6458ce9d8 100644
--- a/library/HTMLPurifier/HTMLModule/Presentation.php
+++ b/library/HTMLPurifier/HTMLModule/Presentation.php
@@ -13,24 +13,30 @@
class HTMLPurifier_HTMLModule_Presentation extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'Presentation';
- public function setup($config) {
- $this->addElement('hr', 'Block', 'Empty', 'Common');
- $this->addElement('sub', 'Inline', 'Inline', 'Common');
- $this->addElement('sup', 'Inline', 'Inline', 'Common');
- $b = $this->addElement('b', 'Inline', 'Inline', 'Common');
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $this->addElement('hr', 'Block', 'Empty', 'Common');
+ $this->addElement('sub', 'Inline', 'Inline', 'Common');
+ $this->addElement('sup', 'Inline', 'Inline', 'Common');
+ $b = $this->addElement('b', 'Inline', 'Inline', 'Common');
$b->formatting = true;
- $big = $this->addElement('big', 'Inline', 'Inline', 'Common');
+ $big = $this->addElement('big', 'Inline', 'Inline', 'Common');
$big->formatting = true;
- $i = $this->addElement('i', 'Inline', 'Inline', 'Common');
+ $i = $this->addElement('i', 'Inline', 'Inline', 'Common');
$i->formatting = true;
- $small = $this->addElement('small', 'Inline', 'Inline', 'Common');
+ $small = $this->addElement('small', 'Inline', 'Inline', 'Common');
$small->formatting = true;
- $tt = $this->addElement('tt', 'Inline', 'Inline', 'Common');
+ $tt = $this->addElement('tt', 'Inline', 'Inline', 'Common');
$tt->formatting = true;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Proprietary.php b/library/HTMLPurifier/HTMLModule/Proprietary.php
index dd36a3de0..5ee3c8e67 100644
--- a/library/HTMLPurifier/HTMLModule/Proprietary.php
+++ b/library/HTMLPurifier/HTMLModule/Proprietary.php
@@ -6,12 +6,21 @@
*/
class HTMLPurifier_HTMLModule_Proprietary extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'Proprietary';
- public function setup($config) {
-
- $this->addElement('marquee', 'Inline', 'Flow', 'Common',
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $this->addElement(
+ 'marquee',
+ 'Inline',
+ 'Flow',
+ 'Common',
array(
'direction' => 'Enum#left,right,up,down',
'behavior' => 'Enum#alternate',
@@ -25,9 +34,7 @@ class HTMLPurifier_HTMLModule_Proprietary extends HTMLPurifier_HTMLModule
'vspace' => 'Pixels',
)
);
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Ruby.php b/library/HTMLPurifier/HTMLModule/Ruby.php
index b26a0a30a..a0d48924d 100644
--- a/library/HTMLPurifier/HTMLModule/Ruby.php
+++ b/library/HTMLPurifier/HTMLModule/Ruby.php
@@ -7,12 +7,22 @@
class HTMLPurifier_HTMLModule_Ruby extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'Ruby';
- public function setup($config) {
- $this->addElement('ruby', 'Inline',
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $this->addElement(
+ 'ruby',
+ 'Inline',
'Custom: ((rb, (rt | (rp, rt, rp))) | (rbc, rtc, rtc?))',
- 'Common');
+ 'Common'
+ );
$this->addElement('rbc', false, 'Required: rb', 'Common');
$this->addElement('rtc', false, 'Required: rt', 'Common');
$rb = $this->addElement('rb', false, 'Inline', 'Common');
@@ -21,7 +31,6 @@ class HTMLPurifier_HTMLModule_Ruby extends HTMLPurifier_HTMLModule
$rt->excludes = array('ruby' => true);
$this->addElement('rp', false, 'Optional: #PCDATA', 'Common');
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/SafeEmbed.php b/library/HTMLPurifier/HTMLModule/SafeEmbed.php
index ea256716b..04e6689ea 100644
--- a/library/HTMLPurifier/HTMLModule/SafeEmbed.php
+++ b/library/HTMLPurifier/HTMLModule/SafeEmbed.php
@@ -5,14 +5,22 @@
*/
class HTMLPurifier_HTMLModule_SafeEmbed extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'SafeEmbed';
- public function setup($config) {
-
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$max = $config->get('HTML.MaxImgLength');
$embed = $this->addElement(
- 'embed', 'Inline', 'Empty', 'Common',
+ 'embed',
+ 'Inline',
+ 'Empty',
+ 'Common',
array(
'src*' => 'URI#embedded',
'type' => 'Enum#application/x-shockwave-flash',
@@ -21,14 +29,12 @@ class HTMLPurifier_HTMLModule_SafeEmbed extends HTMLPurifier_HTMLModule
'allowscriptaccess' => 'Enum#never',
'allownetworking' => 'Enum#internal',
'flashvars' => 'Text',
- 'wmode' => 'Enum#window',
+ 'wmode' => 'Enum#window,transparent,opaque',
'name' => 'ID',
)
);
$embed->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeEmbed();
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/SafeObject.php b/library/HTMLPurifier/HTMLModule/SafeObject.php
index 64ab8c070..1297f80a3 100644
--- a/library/HTMLPurifier/HTMLModule/SafeObject.php
+++ b/library/HTMLPurifier/HTMLModule/SafeObject.php
@@ -8,11 +8,16 @@
*/
class HTMLPurifier_HTMLModule_SafeObject extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'SafeObject';
- public function setup($config) {
-
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
// These definitions are not intrinsically safe: the attribute transforms
// are a vital part of ensuring safety.
@@ -25,18 +30,24 @@ class HTMLPurifier_HTMLModule_SafeObject extends HTMLPurifier_HTMLModule
array(
// While technically not required by the spec, we're forcing
// it to this value.
- 'type' => 'Enum#application/x-shockwave-flash',
- 'width' => 'Pixels#' . $max,
+ 'type' => 'Enum#application/x-shockwave-flash',
+ 'width' => 'Pixels#' . $max,
'height' => 'Pixels#' . $max,
- 'data' => 'URI#embedded',
- 'classid' => 'Enum#clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
- 'codebase' => new HTMLPurifier_AttrDef_Enum(array(
- 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0')),
+ 'data' => 'URI#embedded',
+ 'codebase' => new HTMLPurifier_AttrDef_Enum(
+ array(
+ 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0'
+ )
+ ),
)
);
$object->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeObject();
- $param = $this->addElement('param', false, 'Empty', false,
+ $param = $this->addElement(
+ 'param',
+ false,
+ 'Empty',
+ false,
array(
'id' => 'ID',
'name*' => 'Text',
@@ -45,9 +56,7 @@ class HTMLPurifier_HTMLModule_SafeObject extends HTMLPurifier_HTMLModule
);
$param->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeParam();
$this->info_injector[] = 'SafeObject';
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/SafeScripting.php b/library/HTMLPurifier/HTMLModule/SafeScripting.php
new file mode 100644
index 000000000..0330cd97f
--- /dev/null
+++ b/library/HTMLPurifier/HTMLModule/SafeScripting.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * A "safe" script module. No inline JS is allowed, and pointed to JS
+ * files must match whitelist.
+ */
+class HTMLPurifier_HTMLModule_SafeScripting extends HTMLPurifier_HTMLModule
+{
+ /**
+ * @type string
+ */
+ public $name = 'SafeScripting';
+
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ // These definitions are not intrinsically safe: the attribute transforms
+ // are a vital part of ensuring safety.
+
+ $allowed = $config->get('HTML.SafeScripting');
+ $script = $this->addElement(
+ 'script',
+ 'Inline',
+ 'Empty',
+ null,
+ array(
+ // While technically not required by the spec, we're forcing
+ // it to this value.
+ 'type' => 'Enum#text/javascript',
+ 'src*' => new HTMLPurifier_AttrDef_Enum(array_keys($allowed))
+ )
+ );
+ $script->attr_transform_pre[] =
+ $script->attr_transform_post[] = new HTMLPurifier_AttrTransform_ScriptRequired();
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Scripting.php b/library/HTMLPurifier/HTMLModule/Scripting.php
index cecdea6c3..8b28a7b7e 100644
--- a/library/HTMLPurifier/HTMLModule/Scripting.php
+++ b/library/HTMLPurifier/HTMLModule/Scripting.php
@@ -15,12 +15,31 @@ INSIDE HTML PURIFIER DOCUMENTS. USE ONLY WITH TRUSTED USER INPUT!!!
*/
class HTMLPurifier_HTMLModule_Scripting extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'Scripting';
+
+ /**
+ * @type array
+ */
public $elements = array('script', 'noscript');
+
+ /**
+ * @type array
+ */
public $content_sets = array('Block' => 'script | noscript', 'Inline' => 'script | noscript');
+
+ /**
+ * @type bool
+ */
public $safe = false;
- public function setup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
// TODO: create custom child-definition for noscript that
// auto-wraps stray #PCDATA in a similar manner to
// blockquote's custom definition (we would use it but
@@ -33,20 +52,20 @@ class HTMLPurifier_HTMLModule_Scripting extends HTMLPurifier_HTMLModule
// In theory, this could be safe, but I don't see any reason to
// allow it.
$this->info['noscript'] = new HTMLPurifier_ElementDef();
- $this->info['noscript']->attr = array( 0 => array('Common') );
+ $this->info['noscript']->attr = array(0 => array('Common'));
$this->info['noscript']->content_model = 'Heading | List | Block';
$this->info['noscript']->content_model_type = 'required';
$this->info['script'] = new HTMLPurifier_ElementDef();
$this->info['script']->attr = array(
'defer' => new HTMLPurifier_AttrDef_Enum(array('defer')),
- 'src' => new HTMLPurifier_AttrDef_URI(true),
- 'type' => new HTMLPurifier_AttrDef_Enum(array('text/javascript'))
+ 'src' => new HTMLPurifier_AttrDef_URI(true),
+ 'type' => new HTMLPurifier_AttrDef_Enum(array('text/javascript'))
);
$this->info['script']->content_model = '#PCDATA';
$this->info['script']->content_model_type = 'optional';
- $this->info['script']->attr_transform_pre['type'] =
- $this->info['script']->attr_transform_post['type'] =
+ $this->info['script']->attr_transform_pre[] =
+ $this->info['script']->attr_transform_post[] =
new HTMLPurifier_AttrTransform_ScriptRequired();
}
}
diff --git a/library/HTMLPurifier/HTMLModule/StyleAttribute.php b/library/HTMLPurifier/HTMLModule/StyleAttribute.php
index eb78464cc..497b832ae 100644
--- a/library/HTMLPurifier/HTMLModule/StyleAttribute.php
+++ b/library/HTMLPurifier/HTMLModule/StyleAttribute.php
@@ -6,8 +6,14 @@
*/
class HTMLPurifier_HTMLModule_StyleAttribute extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'StyleAttribute';
+
+ /**
+ * @type array
+ */
public $attr_collections = array(
// The inclusion routine differs from the Abstract Modules but
// is in line with the DTD and XML Schemas.
@@ -15,10 +21,13 @@ class HTMLPurifier_HTMLModule_StyleAttribute extends HTMLPurifier_HTMLModule
'Core' => array(0 => array('Style'))
);
- public function setup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$this->attr_collections['Style']['style'] = new HTMLPurifier_AttrDef_CSS();
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Tables.php b/library/HTMLPurifier/HTMLModule/Tables.php
index f314ced3f..8a0b3b461 100644
--- a/library/HTMLPurifier/HTMLModule/Tables.php
+++ b/library/HTMLPurifier/HTMLModule/Tables.php
@@ -5,15 +5,23 @@
*/
class HTMLPurifier_HTMLModule_Tables extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'Tables';
- public function setup($config) {
-
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$this->addElement('caption', false, 'Inline', 'Common');
- $this->addElement('table', 'Block',
- new HTMLPurifier_ChildDef_Table(), 'Common',
+ $this->addElement(
+ 'table',
+ 'Block',
+ new HTMLPurifier_ChildDef_Table(),
+ 'Common',
array(
'border' => 'Pixels',
'cellpadding' => 'Length',
@@ -34,9 +42,12 @@ class HTMLPurifier_HTMLModule_Tables extends HTMLPurifier_HTMLModule
$cell_t = array_merge(
array(
- 'abbr' => 'Text',
+ 'abbr' => 'Text',
'colspan' => 'Number',
'rowspan' => 'Number',
+ // Apparently, as of HTML5 this attribute only applies
+ // to 'th' elements.
+ 'scope' => 'Enum#row,col,rowgroup,colgroup',
),
$cell_align
);
@@ -47,20 +58,18 @@ class HTMLPurifier_HTMLModule_Tables extends HTMLPurifier_HTMLModule
$cell_col = array_merge(
array(
- 'span' => 'Number',
+ 'span' => 'Number',
'width' => 'MultiLength',
),
$cell_align
);
- $this->addElement('col', false, 'Empty', 'Common', $cell_col);
+ $this->addElement('col', false, 'Empty', 'Common', $cell_col);
$this->addElement('colgroup', false, 'Optional: col', 'Common', $cell_col);
$this->addElement('tbody', false, 'Required: tr', 'Common', $cell_align);
$this->addElement('thead', false, 'Required: tr', 'Common', $cell_align);
$this->addElement('tfoot', false, 'Required: tr', 'Common', $cell_align);
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Target.php b/library/HTMLPurifier/HTMLModule/Target.php
index 2b844ecc4..b188ac936 100644
--- a/library/HTMLPurifier/HTMLModule/Target.php
+++ b/library/HTMLPurifier/HTMLModule/Target.php
@@ -5,10 +5,16 @@
*/
class HTMLPurifier_HTMLModule_Target extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'Target';
- public function setup($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
$elements = array('a');
foreach ($elements as $name) {
$e = $this->addBlankElement($name);
@@ -17,7 +23,6 @@ class HTMLPurifier_HTMLModule_Target extends HTMLPurifier_HTMLModule
);
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/TargetBlank.php b/library/HTMLPurifier/HTMLModule/TargetBlank.php
new file mode 100644
index 000000000..58ccc6894
--- /dev/null
+++ b/library/HTMLPurifier/HTMLModule/TargetBlank.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * Module adds the target=blank attribute transformation to a tags. It
+ * is enabled by HTML.TargetBlank
+ */
+class HTMLPurifier_HTMLModule_TargetBlank extends HTMLPurifier_HTMLModule
+{
+ /**
+ * @type string
+ */
+ public $name = 'TargetBlank';
+
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
+ $a = $this->addBlankElement('a');
+ $a->attr_transform_post[] = new HTMLPurifier_AttrTransform_TargetBlank();
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Text.php b/library/HTMLPurifier/HTMLModule/Text.php
index ae77c7188..7a65e0048 100644
--- a/library/HTMLPurifier/HTMLModule/Text.php
+++ b/library/HTMLPurifier/HTMLModule/Text.php
@@ -14,43 +14,59 @@
*/
class HTMLPurifier_HTMLModule_Text extends HTMLPurifier_HTMLModule
{
-
+ /**
+ * @type string
+ */
public $name = 'Text';
+
+ /**
+ * @type array
+ */
public $content_sets = array(
'Flow' => 'Heading | Block | Inline'
);
- public function setup($config) {
-
+ /**
+ * @param HTMLPurifier_Config $config
+ */
+ public function setup($config)
+ {
// Inline Phrasal -------------------------------------------------
- $this->addElement('abbr', 'Inline', 'Inline', 'Common');
+ $this->addElement('abbr', 'Inline', 'Inline', 'Common');
$this->addElement('acronym', 'Inline', 'Inline', 'Common');
- $this->addElement('cite', 'Inline', 'Inline', 'Common');
- $this->addElement('dfn', 'Inline', 'Inline', 'Common');
- $this->addElement('kbd', 'Inline', 'Inline', 'Common');
- $this->addElement('q', 'Inline', 'Inline', 'Common', array('cite' => 'URI'));
- $this->addElement('samp', 'Inline', 'Inline', 'Common');
- $this->addElement('var', 'Inline', 'Inline', 'Common');
+ $this->addElement('cite', 'Inline', 'Inline', 'Common');
+ $this->addElement('dfn', 'Inline', 'Inline', 'Common');
+ $this->addElement('kbd', 'Inline', 'Inline', 'Common');
+ $this->addElement('q', 'Inline', 'Inline', 'Common', array('cite' => 'URI'));
+ $this->addElement('samp', 'Inline', 'Inline', 'Common');
+ $this->addElement('var', 'Inline', 'Inline', 'Common');
- $em = $this->addElement('em', 'Inline', 'Inline', 'Common');
+ $em = $this->addElement('em', 'Inline', 'Inline', 'Common');
$em->formatting = true;
- $strong = $this->addElement('strong', 'Inline', 'Inline', 'Common');
+ $strong = $this->addElement('strong', 'Inline', 'Inline', 'Common');
$strong->formatting = true;
- $code = $this->addElement('code', 'Inline', 'Inline', 'Common');
+ $code = $this->addElement('code', 'Inline', 'Inline', 'Common');
$code->formatting = true;
// Inline Structural ----------------------------------------------
$this->addElement('span', 'Inline', 'Inline', 'Common');
- $this->addElement('br', 'Inline', 'Empty', 'Core');
+ $this->addElement('br', 'Inline', 'Empty', 'Core');
// Block Phrasal --------------------------------------------------
- $this->addElement('address', 'Block', 'Inline', 'Common');
- $this->addElement('blockquote', 'Block', 'Optional: Heading | Block | List', 'Common', array('cite' => 'URI') );
+ $this->addElement('address', 'Block', 'Inline', 'Common');
+ $this->addElement('blockquote', 'Block', 'Optional: Heading | Block | List', 'Common', array('cite' => 'URI'));
$pre = $this->addElement('pre', 'Block', 'Inline', 'Common');
$pre->excludes = $this->makeLookup(
- 'img', 'big', 'small', 'object', 'applet', 'font', 'basefont' );
+ 'img',
+ 'big',
+ 'small',
+ 'object',
+ 'applet',
+ 'font',
+ 'basefont'
+ );
$this->addElement('h1', 'Heading', 'Inline', 'Common');
$this->addElement('h2', 'Heading', 'Inline', 'Common');
$this->addElement('h3', 'Heading', 'Inline', 'Common');
@@ -60,12 +76,12 @@ class HTMLPurifier_HTMLModule_Text extends HTMLPurifier_HTMLModule
// Block Structural -----------------------------------------------
$p = $this->addElement('p', 'Block', 'Inline', 'Common');
- $p->autoclose = array_flip(array("address", "blockquote", "center", "dir", "div", "dl", "fieldset", "ol", "p", "ul"));
+ $p->autoclose = array_flip(
+ array("address", "blockquote", "center", "dir", "div", "dl", "fieldset", "ol", "p", "ul")
+ );
$this->addElement('div', 'Block', 'Flow', 'Common');
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Tidy.php b/library/HTMLPurifier/HTMLModule/Tidy.php
index 21783f18e..08aa23247 100644
--- a/library/HTMLPurifier/HTMLModule/Tidy.php
+++ b/library/HTMLPurifier/HTMLModule/Tidy.php
@@ -7,36 +7,41 @@
*/
class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
{
-
/**
- * List of supported levels. Index zero is a special case "no fixes"
- * level.
+ * List of supported levels.
+ * Index zero is a special case "no fixes" level.
+ * @type array
*/
public $levels = array(0 => 'none', 'light', 'medium', 'heavy');
/**
- * Default level to place all fixes in. Disabled by default
+ * Default level to place all fixes in.
+ * Disabled by default.
+ * @type string
*/
public $defaultLevel = null;
/**
- * Lists of fixes used by getFixesForLevel(). Format is:
+ * Lists of fixes used by getFixesForLevel().
+ * Format is:
* HTMLModule_Tidy->fixesForLevel[$level] = array('fix-1', 'fix-2');
+ * @type array
*/
public $fixesForLevel = array(
- 'light' => array(),
+ 'light' => array(),
'medium' => array(),
- 'heavy' => array()
+ 'heavy' => array()
);
/**
* Lazy load constructs the module by determining the necessary
* fixes to create and then delegating to the populate() function.
+ * @param HTMLPurifier_Config $config
* @todo Wildcard matching and error reporting when an added or
* subtracted fix has no effect.
*/
- public function setup($config) {
-
+ public function setup($config)
+ {
// create fixes, initialize fixesForLevel
$fixes = $this->makeFixes();
$this->makeFixesForLevel($fixes);
@@ -46,38 +51,38 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
$fixes_lookup = $this->getFixesForLevel($level);
// get custom fix declarations: these need namespace processing
- $add_fixes = $config->get('HTML.TidyAdd');
+ $add_fixes = $config->get('HTML.TidyAdd');
$remove_fixes = $config->get('HTML.TidyRemove');
foreach ($fixes as $name => $fix) {
// needs to be refactored a little to implement globbing
- if (
- isset($remove_fixes[$name]) ||
- (!isset($add_fixes[$name]) && !isset($fixes_lookup[$name]))
- ) {
+ if (isset($remove_fixes[$name]) ||
+ (!isset($add_fixes[$name]) && !isset($fixes_lookup[$name]))) {
unset($fixes[$name]);
}
}
// populate this module with necessary fixes
$this->populate($fixes);
-
}
/**
* Retrieves all fixes per a level, returning fixes for that specific
* level as well as all levels below it.
- * @param $level String level identifier, see $levels for valid values
- * @return Lookup up table of fixes
+ * @param string $level level identifier, see $levels for valid values
+ * @return array Lookup up table of fixes
*/
- public function getFixesForLevel($level) {
+ public function getFixesForLevel($level)
+ {
if ($level == $this->levels[0]) {
return array();
}
$activated_levels = array();
for ($i = 1, $c = count($this->levels); $i < $c; $i++) {
$activated_levels[] = $this->levels[$i];
- if ($this->levels[$i] == $level) break;
+ if ($this->levels[$i] == $level) {
+ break;
+ }
}
if ($i == $c) {
trigger_error(
@@ -99,9 +104,13 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
* Dynamically populates the $fixesForLevel member variable using
* the fixes array. It may be custom overloaded, used in conjunction
* with $defaultLevel, or not used at all.
+ * @param array $fixes
*/
- public function makeFixesForLevel($fixes) {
- if (!isset($this->defaultLevel)) return;
+ public function makeFixesForLevel($fixes)
+ {
+ if (!isset($this->defaultLevel)) {
+ return;
+ }
if (!isset($this->fixesForLevel[$this->defaultLevel])) {
trigger_error(
'Default level ' . $this->defaultLevel . ' does not exist',
@@ -115,9 +124,10 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
/**
* Populates the module with transforms and other special-case code
* based on a list of fixes passed to it
- * @param $lookup Lookup table of fixes to activate
+ * @param array $fixes Lookup table of fixes to activate
*/
- public function populate($fixes) {
+ public function populate($fixes)
+ {
foreach ($fixes as $name => $fix) {
// determine what the fix is for
list($type, $params) = $this->getFixType($name);
@@ -169,20 +179,31 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
* @note $fix_parameters is type dependant, see populate() for usage
* of these parameters
*/
- public function getFixType($name) {
+ public function getFixType($name)
+ {
// parse it
$property = $attr = null;
- if (strpos($name, '#') !== false) list($name, $property) = explode('#', $name);
- if (strpos($name, '@') !== false) list($name, $attr) = explode('@', $name);
+ if (strpos($name, '#') !== false) {
+ list($name, $property) = explode('#', $name);
+ }
+ if (strpos($name, '@') !== false) {
+ list($name, $attr) = explode('@', $name);
+ }
// figure out the parameters
$params = array();
- if ($name !== '') $params['element'] = $name;
- if (!is_null($attr)) $params['attr'] = $attr;
+ if ($name !== '') {
+ $params['element'] = $name;
+ }
+ if (!is_null($attr)) {
+ $params['attr'] = $attr;
+ }
// special case: attribute transform
if (!is_null($attr)) {
- if (is_null($property)) $property = 'pre';
+ if (is_null($property)) {
+ $property = 'pre';
+ }
$type = 'attr_transform_' . $property;
return array($type, $params);
}
@@ -199,9 +220,11 @@ class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
/**
* Defines all fixes the module will perform in a compact
* associative array of fix name to fix implementation.
+ * @return array
*/
- public function makeFixes() {}
-
+ public function makeFixes()
+ {
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Tidy/Name.php b/library/HTMLPurifier/HTMLModule/Tidy/Name.php
index 61ff85ce2..a995161b2 100644
--- a/library/HTMLPurifier/HTMLModule/Tidy/Name.php
+++ b/library/HTMLPurifier/HTMLModule/Tidy/Name.php
@@ -5,18 +5,27 @@
*/
class HTMLPurifier_HTMLModule_Tidy_Name extends HTMLPurifier_HTMLModule_Tidy
{
+ /**
+ * @type string
+ */
public $name = 'Tidy_Name';
+
+ /**
+ * @type string
+ */
public $defaultLevel = 'heavy';
- public function makeFixes() {
+ /**
+ * @return array
+ */
+ public function makeFixes()
+ {
$r = array();
-
// @name for img, a -----------------------------------------------
// Technically, it's allowed even on strict, so we allow authors to use
// it. However, it's deprecated in future versions of XHTML.
$r['img@name'] =
$r['a@name'] = new HTMLPurifier_AttrTransform_Name();
-
return $r;
}
}
diff --git a/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php b/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php
index 14c15c4a0..332643821 100644
--- a/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php
+++ b/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php
@@ -3,10 +3,21 @@
class HTMLPurifier_HTMLModule_Tidy_Proprietary extends HTMLPurifier_HTMLModule_Tidy
{
+ /**
+ * @type string
+ */
public $name = 'Tidy_Proprietary';
+
+ /**
+ * @type string
+ */
public $defaultLevel = 'light';
- public function makeFixes() {
+ /**
+ * @return array
+ */
+ public function makeFixes()
+ {
$r = array();
$r['table@background'] = new HTMLPurifier_AttrTransform_Background();
$r['td@background'] = new HTMLPurifier_AttrTransform_Background();
@@ -18,7 +29,6 @@ class HTMLPurifier_HTMLModule_Tidy_Proprietary extends HTMLPurifier_HTMLModule_T
$r['table@height'] = new HTMLPurifier_AttrTransform_Length('height');
return $r;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Tidy/Strict.php b/library/HTMLPurifier/HTMLModule/Tidy/Strict.php
index c73dc3c4d..803c44fab 100644
--- a/library/HTMLPurifier/HTMLModule/Tidy/Strict.php
+++ b/library/HTMLPurifier/HTMLModule/Tidy/Strict.php
@@ -2,18 +2,40 @@
class HTMLPurifier_HTMLModule_Tidy_Strict extends HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4
{
+ /**
+ * @type string
+ */
public $name = 'Tidy_Strict';
+
+ /**
+ * @type string
+ */
public $defaultLevel = 'light';
- public function makeFixes() {
+ /**
+ * @return array
+ */
+ public function makeFixes()
+ {
$r = parent::makeFixes();
$r['blockquote#content_model_type'] = 'strictblockquote';
return $r;
}
+ /**
+ * @type bool
+ */
public $defines_child_def = true;
- public function getChildDef($def) {
- if ($def->content_model_type != 'strictblockquote') return parent::getChildDef($def);
+
+ /**
+ * @param HTMLPurifier_ElementDef $def
+ * @return HTMLPurifier_ChildDef_StrictBlockquote
+ */
+ public function getChildDef($def)
+ {
+ if ($def->content_model_type != 'strictblockquote') {
+ return parent::getChildDef($def);
+ }
return new HTMLPurifier_ChildDef_StrictBlockquote($def->content_model);
}
}
diff --git a/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php b/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php
index 9960b1dd1..c095ad974 100644
--- a/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php
+++ b/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php
@@ -2,7 +2,14 @@
class HTMLPurifier_HTMLModule_Tidy_Transitional extends HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4
{
+ /**
+ * @type string
+ */
public $name = 'Tidy_Transitional';
+
+ /**
+ * @type string
+ */
public $defaultLevel = 'heavy';
}
diff --git a/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php b/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php
index db5a378e5..3ecddc434 100644
--- a/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php
+++ b/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php
@@ -2,16 +2,25 @@
class HTMLPurifier_HTMLModule_Tidy_XHTML extends HTMLPurifier_HTMLModule_Tidy
{
-
+ /**
+ * @type string
+ */
public $name = 'Tidy_XHTML';
+
+ /**
+ * @type string
+ */
public $defaultLevel = 'medium';
- public function makeFixes() {
+ /**
+ * @return array
+ */
+ public function makeFixes()
+ {
$r = array();
$r['@lang'] = new HTMLPurifier_AttrTransform_Lang();
return $r;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php b/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php
index 02e943813..c4f16a4dc 100644
--- a/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php
+++ b/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php
@@ -3,69 +3,86 @@
class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends HTMLPurifier_HTMLModule_Tidy
{
- public function makeFixes() {
-
+ /**
+ * @return array
+ */
+ public function makeFixes()
+ {
$r = array();
// == deprecated tag transforms ===================================
- $r['font'] = new HTMLPurifier_TagTransform_Font();
- $r['menu'] = new HTMLPurifier_TagTransform_Simple('ul');
- $r['dir'] = new HTMLPurifier_TagTransform_Simple('ul');
- $r['center'] = new HTMLPurifier_TagTransform_Simple('div', 'text-align:center;');
- $r['u'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration:underline;');
- $r['s'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration:line-through;');
+ $r['font'] = new HTMLPurifier_TagTransform_Font();
+ $r['menu'] = new HTMLPurifier_TagTransform_Simple('ul');
+ $r['dir'] = new HTMLPurifier_TagTransform_Simple('ul');
+ $r['center'] = new HTMLPurifier_TagTransform_Simple('div', 'text-align:center;');
+ $r['u'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration:underline;');
+ $r['s'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration:line-through;');
$r['strike'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration:line-through;');
// == deprecated attribute transforms =============================
$r['caption@align'] =
- new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
- // we're following IE's behavior, not Firefox's, due
- // to the fact that no one supports caption-side:right,
- // W3C included (with CSS 2.1). This is a slightly
- // unreasonable attribute!
- 'left' => 'text-align:left;',
- 'right' => 'text-align:right;',
- 'top' => 'caption-side:top;',
- 'bottom' => 'caption-side:bottom;' // not supported by IE
- ));
+ new HTMLPurifier_AttrTransform_EnumToCSS(
+ 'align',
+ array(
+ // we're following IE's behavior, not Firefox's, due
+ // to the fact that no one supports caption-side:right,
+ // W3C included (with CSS 2.1). This is a slightly
+ // unreasonable attribute!
+ 'left' => 'text-align:left;',
+ 'right' => 'text-align:right;',
+ 'top' => 'caption-side:top;',
+ 'bottom' => 'caption-side:bottom;' // not supported by IE
+ )
+ );
// @align for img -------------------------------------------------
$r['img@align'] =
- new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
- 'left' => 'float:left;',
- 'right' => 'float:right;',
- 'top' => 'vertical-align:top;',
- 'middle' => 'vertical-align:middle;',
- 'bottom' => 'vertical-align:baseline;',
- ));
+ new HTMLPurifier_AttrTransform_EnumToCSS(
+ 'align',
+ array(
+ 'left' => 'float:left;',
+ 'right' => 'float:right;',
+ 'top' => 'vertical-align:top;',
+ 'middle' => 'vertical-align:middle;',
+ 'bottom' => 'vertical-align:baseline;',
+ )
+ );
// @align for table -----------------------------------------------
$r['table@align'] =
- new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
- 'left' => 'float:left;',
- 'center' => 'margin-left:auto;margin-right:auto;',
- 'right' => 'float:right;'
- ));
+ new HTMLPurifier_AttrTransform_EnumToCSS(
+ 'align',
+ array(
+ 'left' => 'float:left;',
+ 'center' => 'margin-left:auto;margin-right:auto;',
+ 'right' => 'float:right;'
+ )
+ );
// @align for hr -----------------------------------------------
$r['hr@align'] =
- new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
- // we use both text-align and margin because these work
- // for different browsers (IE and Firefox, respectively)
- // and the melange makes for a pretty cross-compatible
- // solution
- 'left' => 'margin-left:0;margin-right:auto;text-align:left;',
- 'center' => 'margin-left:auto;margin-right:auto;text-align:center;',
- 'right' => 'margin-left:auto;margin-right:0;text-align:right;'
- ));
+ new HTMLPurifier_AttrTransform_EnumToCSS(
+ 'align',
+ array(
+ // we use both text-align and margin because these work
+ // for different browsers (IE and Firefox, respectively)
+ // and the melange makes for a pretty cross-compatible
+ // solution
+ 'left' => 'margin-left:0;margin-right:auto;text-align:left;',
+ 'center' => 'margin-left:auto;margin-right:auto;text-align:center;',
+ 'right' => 'margin-left:auto;margin-right:0;text-align:right;'
+ )
+ );
// @align for h1, h2, h3, h4, h5, h6, p, div ----------------------
// {{{
- $align_lookup = array();
- $align_values = array('left', 'right', 'center', 'justify');
- foreach ($align_values as $v) $align_lookup[$v] = "text-align:$v;";
+ $align_lookup = array();
+ $align_values = array('left', 'right', 'center', 'justify');
+ foreach ($align_values as $v) {
+ $align_lookup[$v] = "text-align:$v;";
+ }
// }}}
$r['h1@align'] =
$r['h2@align'] =
@@ -73,7 +90,7 @@ class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends HTMLPurifier_HTMLModule
$r['h4@align'] =
$r['h5@align'] =
$r['h6@align'] =
- $r['p@align'] =
+ $r['p@align'] =
$r['div@align'] =
new HTMLPurifier_AttrTransform_EnumToCSS('align', $align_lookup);
@@ -88,12 +105,15 @@ class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends HTMLPurifier_HTMLModule
// @clear for br --------------------------------------------------
$r['br@clear'] =
- new HTMLPurifier_AttrTransform_EnumToCSS('clear', array(
- 'left' => 'clear:left;',
- 'right' => 'clear:right;',
- 'all' => 'clear:both;',
- 'none' => 'clear:none;',
- ));
+ new HTMLPurifier_AttrTransform_EnumToCSS(
+ 'clear',
+ array(
+ 'left' => 'clear:left;',
+ 'right' => 'clear:right;',
+ 'all' => 'clear:both;',
+ 'none' => 'clear:none;',
+ )
+ );
// @height for td, th ---------------------------------------------
$r['td@height'] =
@@ -125,19 +145,19 @@ class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends HTMLPurifier_HTMLModule
// @type for li, ol, ul -------------------------------------------
// {{{
- $ul_types = array(
- 'disc' => 'list-style-type:disc;',
- 'square' => 'list-style-type:square;',
- 'circle' => 'list-style-type:circle;'
- );
- $ol_types = array(
- '1' => 'list-style-type:decimal;',
- 'i' => 'list-style-type:lower-roman;',
- 'I' => 'list-style-type:upper-roman;',
- 'a' => 'list-style-type:lower-alpha;',
- 'A' => 'list-style-type:upper-alpha;'
- );
- $li_types = $ul_types + $ol_types;
+ $ul_types = array(
+ 'disc' => 'list-style-type:disc;',
+ 'square' => 'list-style-type:square;',
+ 'circle' => 'list-style-type:circle;'
+ );
+ $ol_types = array(
+ '1' => 'list-style-type:decimal;',
+ 'i' => 'list-style-type:lower-roman;',
+ 'I' => 'list-style-type:upper-roman;',
+ 'a' => 'list-style-type:lower-alpha;',
+ 'A' => 'list-style-type:upper-alpha;'
+ );
+ $li_types = $ul_types + $ol_types;
// }}}
$r['ul@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $ul_types);
@@ -153,9 +173,7 @@ class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends HTMLPurifier_HTMLModule
$r['hr@width'] = new HTMLPurifier_AttrTransform_Length('width');
return $r;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php b/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php
index 9c0e03198..01dbe9deb 100644
--- a/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php
+++ b/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php
@@ -2,8 +2,14 @@
class HTMLPurifier_HTMLModule_XMLCommonAttributes extends HTMLPurifier_HTMLModule
{
+ /**
+ * @type string
+ */
public $name = 'XMLCommonAttributes';
+ /**
+ * @type array
+ */
public $attr_collections = array(
'Lang' => array(
'xml:lang' => 'LanguageCode',
diff --git a/library/HTMLPurifier/HTMLModuleManager.php b/library/HTMLPurifier/HTMLModuleManager.php
index f5c4a1d2c..f3a17cb03 100644
--- a/library/HTMLPurifier/HTMLModuleManager.php
+++ b/library/HTMLPurifier/HTMLModuleManager.php
@@ -4,57 +4,75 @@ class HTMLPurifier_HTMLModuleManager
{
/**
- * Instance of HTMLPurifier_DoctypeRegistry
+ * @type HTMLPurifier_DoctypeRegistry
*/
public $doctypes;
/**
- * Instance of current doctype
+ * Instance of current doctype.
+ * @type string
*/
public $doctype;
/**
- * Instance of HTMLPurifier_AttrTypes
+ * @type HTMLPurifier_AttrTypes
*/
public $attrTypes;
/**
* Active instances of modules for the specified doctype are
* indexed, by name, in this array.
+ * @type HTMLPurifier_HTMLModule[]
*/
public $modules = array();
/**
- * Array of recognized HTMLPurifier_Module instances, indexed by
- * module's class name. This array is usually lazy loaded, but a
+ * Array of recognized HTMLPurifier_HTMLModule instances,
+ * indexed by module's class name. This array is usually lazy loaded, but a
* user can overload a module by pre-emptively registering it.
+ * @type HTMLPurifier_HTMLModule[]
*/
public $registeredModules = array();
/**
- * List of extra modules that were added by the user using addModule().
- * These get unconditionally merged into the current doctype, whatever
+ * List of extra modules that were added by the user
+ * using addModule(). These get unconditionally merged into the current doctype, whatever
* it may be.
+ * @type HTMLPurifier_HTMLModule[]
*/
public $userModules = array();
/**
* Associative array of element name to list of modules that have
* definitions for the element; this array is dynamically filled.
+ * @type array
*/
public $elementLookup = array();
- /** List of prefixes we should use for registering small names */
+ /**
+ * List of prefixes we should use for registering small names.
+ * @type array
+ */
public $prefixes = array('HTMLPurifier_HTMLModule_');
- public $contentSets; /**< Instance of HTMLPurifier_ContentSets */
- public $attrCollections; /**< Instance of HTMLPurifier_AttrCollections */
+ /**
+ * @type HTMLPurifier_ContentSets
+ */
+ public $contentSets;
- /** If set to true, unsafe elements and attributes will be allowed */
- public $trusted = false;
+ /**
+ * @type HTMLPurifier_AttrCollections
+ */
+ public $attrCollections;
- public function __construct() {
+ /**
+ * If set to true, unsafe elements and attributes will be allowed.
+ * @type bool
+ */
+ public $trusted = false;
+ public function __construct()
+ {
// editable internal objects
$this->attrTypes = new HTMLPurifier_AttrTypes();
$this->doctypes = new HTMLPurifier_DoctypeRegistry();
@@ -65,17 +83,18 @@ class HTMLPurifier_HTMLModuleManager
'Presentation', 'Edit', 'Bdo', 'Tables', 'Image',
'StyleAttribute',
// Unsafe:
- 'Scripting', 'Object', 'Forms',
+ 'Scripting', 'Object', 'Forms',
// Sorta legacy, but present in strict:
'Name',
);
- $transitional = array('Legacy', 'Target');
+ $transitional = array('Legacy', 'Target', 'Iframe');
$xml = array('XMLCommonAttributes');
$non_xml = array('NonXMLCommonAttributes');
// setup basic doctypes
$this->doctypes->register(
- 'HTML 4.01 Transitional', false,
+ 'HTML 4.01 Transitional',
+ false,
array_merge($common, $transitional, $non_xml),
array('Tidy_Transitional', 'Tidy_Proprietary'),
array(),
@@ -84,7 +103,8 @@ class HTMLPurifier_HTMLModuleManager
);
$this->doctypes->register(
- 'HTML 4.01 Strict', false,
+ 'HTML 4.01 Strict',
+ false,
array_merge($common, $non_xml),
array('Tidy_Strict', 'Tidy_Proprietary', 'Tidy_Name'),
array(),
@@ -93,7 +113,8 @@ class HTMLPurifier_HTMLModuleManager
);
$this->doctypes->register(
- 'XHTML 1.0 Transitional', true,
+ 'XHTML 1.0 Transitional',
+ true,
array_merge($common, $transitional, $xml, $non_xml),
array('Tidy_Transitional', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Name'),
array(),
@@ -102,7 +123,8 @@ class HTMLPurifier_HTMLModuleManager
);
$this->doctypes->register(
- 'XHTML 1.0 Strict', true,
+ 'XHTML 1.0 Strict',
+ true,
array_merge($common, $xml, $non_xml),
array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Strict', 'Tidy_Proprietary', 'Tidy_Name'),
array(),
@@ -111,8 +133,11 @@ class HTMLPurifier_HTMLModuleManager
);
$this->doctypes->register(
- 'XHTML 1.1', true,
- array_merge($common, $xml, array('Ruby')),
+ 'XHTML 1.1',
+ true,
+ // Iframe is a real XHTML 1.1 module, despite being
+ // "transitional"!
+ array_merge($common, $xml, array('Ruby', 'Iframe')),
array('Tidy_Strict', 'Tidy_XHTML', 'Tidy_Proprietary', 'Tidy_Strict', 'Tidy_Name'), // Tidy_XHTML1_1
array(),
'-//W3C//DTD XHTML 1.1//EN',
@@ -142,7 +167,8 @@ class HTMLPurifier_HTMLModuleManager
* your module manually. All modules must have been included
* externally: registerModule will not perform inclusions for you!
*/
- public function registerModule($module, $overload = false) {
+ public function registerModule($module, $overload = false)
+ {
if (is_string($module)) {
// attempt to load the module
$original_module = $module;
@@ -157,8 +183,10 @@ class HTMLPurifier_HTMLModuleManager
if (!$ok) {
$module = $original_module;
if (!class_exists($module)) {
- trigger_error($original_module . ' module does not exist',
- E_USER_ERROR);
+ trigger_error(
+ $original_module . ' module does not exist',
+ E_USER_ERROR
+ );
return;
}
}
@@ -178,9 +206,12 @@ class HTMLPurifier_HTMLModuleManager
* Adds a module to the current doctype by first registering it,
* and then tacking it on to the active doctype
*/
- public function addModule($module) {
+ public function addModule($module)
+ {
$this->registerModule($module);
- if (is_object($module)) $module = $module->name;
+ if (is_object($module)) {
+ $module = $module->name;
+ }
$this->userModules[] = $module;
}
@@ -188,17 +219,18 @@ class HTMLPurifier_HTMLModuleManager
* Adds a class prefix that registerModule() will use to resolve a
* string name to a concrete class
*/
- public function addPrefix($prefix) {
+ public function addPrefix($prefix)
+ {
$this->prefixes[] = $prefix;
}
/**
* Performs processing on modules, after being called you may
* use getElement() and getElements()
- * @param $config Instance of HTMLPurifier_Config
+ * @param HTMLPurifier_Config $config
*/
- public function setup($config) {
-
+ public function setup($config)
+ {
$this->trusted = $config->get('HTML.Trusted');
// generate
@@ -211,24 +243,34 @@ class HTMLPurifier_HTMLModuleManager
if (is_array($lookup)) {
foreach ($modules as $k => $m) {
- if (isset($special_cases[$m])) continue;
- if (!isset($lookup[$m])) unset($modules[$k]);
+ if (isset($special_cases[$m])) {
+ continue;
+ }
+ if (!isset($lookup[$m])) {
+ unset($modules[$k]);
+ }
}
}
- // add proprietary module (this gets special treatment because
- // it is completely removed from doctypes, etc.)
+ // custom modules
if ($config->get('HTML.Proprietary')) {
$modules[] = 'Proprietary';
}
-
- // add SafeObject/Safeembed modules
if ($config->get('HTML.SafeObject')) {
$modules[] = 'SafeObject';
}
if ($config->get('HTML.SafeEmbed')) {
$modules[] = 'SafeEmbed';
}
+ if ($config->get('HTML.SafeScripting') !== array()) {
+ $modules[] = 'SafeScripting';
+ }
+ if ($config->get('HTML.Nofollow')) {
+ $modules[] = 'Nofollow';
+ }
+ if ($config->get('HTML.TargetBlank')) {
+ $modules[] = 'TargetBlank';
+ }
// merge in custom modules
$modules = array_merge($modules, $this->userModules);
@@ -246,7 +288,7 @@ class HTMLPurifier_HTMLModuleManager
// prepare any injectors
foreach ($this->modules as $module) {
$n = array();
- foreach ($module->info_injector as $i => $injector) {
+ foreach ($module->info_injector as $injector) {
if (!is_object($injector)) {
$class = "HTMLPurifier_Injector_$injector";
$injector = new $class;
@@ -285,7 +327,8 @@ class HTMLPurifier_HTMLModuleManager
* Takes a module and adds it to the active module collection,
* registering it if necessary.
*/
- public function processModule($module) {
+ public function processModule($module)
+ {
if (!isset($this->registeredModules[$module]) || is_object($module)) {
$this->registerModule($module);
}
@@ -296,13 +339,17 @@ class HTMLPurifier_HTMLModuleManager
* Retrieves merged element definitions.
* @return Array of HTMLPurifier_ElementDef
*/
- public function getElements() {
-
+ public function getElements()
+ {
$elements = array();
foreach ($this->modules as $module) {
- if (!$this->trusted && !$module->safe) continue;
+ if (!$this->trusted && !$module->safe) {
+ continue;
+ }
foreach ($module->info as $name => $v) {
- if (isset($elements[$name])) continue;
+ if (isset($elements[$name])) {
+ continue;
+ }
$elements[$name] = $this->getElement($name);
}
}
@@ -310,7 +357,9 @@ class HTMLPurifier_HTMLModuleManager
// remove dud elements, this happens when an element that
// appeared to be safe actually wasn't
foreach ($elements as $n => $v) {
- if ($v === false) unset($elements[$n]);
+ if ($v === false) {
+ unset($elements[$n]);
+ }
}
return $elements;
@@ -319,28 +368,29 @@ class HTMLPurifier_HTMLModuleManager
/**
* Retrieves a single merged element definition
- * @param $name Name of element
- * @param $trusted Boolean trusted overriding parameter: set to true
+ * @param string $name Name of element
+ * @param bool $trusted Boolean trusted overriding parameter: set to true
* if you want the full version of an element
- * @return Merged HTMLPurifier_ElementDef
+ * @return HTMLPurifier_ElementDef Merged HTMLPurifier_ElementDef
* @note You may notice that modules are getting iterated over twice (once
* in getElements() and once here). This
* is because
*/
- public function getElement($name, $trusted = null) {
-
+ public function getElement($name, $trusted = null)
+ {
if (!isset($this->elementLookup[$name])) {
return false;
}
// setup global state variables
$def = false;
- if ($trusted === null) $trusted = $this->trusted;
+ if ($trusted === null) {
+ $trusted = $this->trusted;
+ }
// iterate through each module that has registered itself to this
// element
- foreach($this->elementLookup[$name] as $module_name) {
-
+ foreach ($this->elementLookup[$name] as $module_name) {
$module = $this->modules[$module_name];
// refuse to create/merge from a module that is deemed unsafe--
@@ -364,6 +414,13 @@ class HTMLPurifier_HTMLModuleManager
// :TODO:
// non-standalone definitions that don't have a standalone
// to merge into could be deferred to the end
+ // HOWEVER, it is perfectly valid for a non-standalone
+ // definition to lack a standalone definition, even
+ // after all processing: this allows us to safely
+ // specify extra attributes for elements that may not be
+ // enabled all in one place. In particular, this might
+ // be the case for trusted elements. WARNING: care must
+ // be taken that the /extra/ definitions are all safe.
continue;
}
@@ -385,7 +442,9 @@ class HTMLPurifier_HTMLModuleManager
// This can occur if there is a blank definition, but no base to
// mix it in with
- if (!$def) return false;
+ if (!$def) {
+ return false;
+ }
// add information on required attributes
foreach ($def->attr as $attr_name => $attr_def) {
@@ -393,11 +452,8 @@ class HTMLPurifier_HTMLModuleManager
$def->required_attr[] = $attr_name;
}
}
-
return $def;
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/IDAccumulator.php b/library/HTMLPurifier/IDAccumulator.php
index 73215295a..65c902c07 100644
--- a/library/HTMLPurifier/IDAccumulator.php
+++ b/library/HTMLPurifier/IDAccumulator.php
@@ -17,11 +17,12 @@ class HTMLPurifier_IDAccumulator
/**
* Builds an IDAccumulator, also initializing the default blacklist
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
- * @return Fully initialized HTMLPurifier_IDAccumulator
+ * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config
+ * @param HTMLPurifier_Context $context Instance of HTMLPurifier_Context
+ * @return HTMLPurifier_IDAccumulator Fully initialized HTMLPurifier_IDAccumulator
*/
- public static function build($config, $context) {
+ public static function build($config, $context)
+ {
$id_accumulator = new HTMLPurifier_IDAccumulator();
$id_accumulator->load($config->get('Attr.IDBlacklist'));
return $id_accumulator;
@@ -29,11 +30,14 @@ class HTMLPurifier_IDAccumulator
/**
* Add an ID to the lookup table.
- * @param $id ID to be added.
- * @return Bool status, true if success, false if there's a dupe
+ * @param string $id ID to be added.
+ * @return bool status, true if success, false if there's a dupe
*/
- public function add($id) {
- if (isset($this->ids[$id])) return false;
+ public function add($id)
+ {
+ if (isset($this->ids[$id])) {
+ return false;
+ }
return $this->ids[$id] = true;
}
@@ -42,12 +46,12 @@ class HTMLPurifier_IDAccumulator
* @param $array_of_ids Array of IDs to load
* @note This function doesn't care about duplicates
*/
- public function load($array_of_ids) {
+ public function load($array_of_ids)
+ {
foreach ($array_of_ids as $id) {
$this->ids[$id] = true;
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Injector.php b/library/HTMLPurifier/Injector.php
index 5922f8130..5060eef9e 100644
--- a/library/HTMLPurifier/Injector.php
+++ b/library/HTMLPurifier/Injector.php
@@ -17,64 +17,71 @@ abstract class HTMLPurifier_Injector
{
/**
- * Advisory name of injector, this is for friendly error messages
+ * Advisory name of injector, this is for friendly error messages.
+ * @type string
*/
public $name;
/**
- * Instance of HTMLPurifier_HTMLDefinition
+ * @type HTMLPurifier_HTMLDefinition
*/
protected $htmlDefinition;
/**
* Reference to CurrentNesting variable in Context. This is an array
* list of tokens that we are currently "inside"
+ * @type array
*/
protected $currentNesting;
/**
- * Reference to InputTokens variable in Context. This is an array
- * list of the input tokens that are being processed.
+ * Reference to current token.
+ * @type HTMLPurifier_Token
*/
- protected $inputTokens;
+ protected $currentToken;
/**
- * Reference to InputIndex variable in Context. This is an integer
- * array index for $this->inputTokens that indicates what token
- * is currently being processed.
+ * Reference to InputZipper variable in Context.
+ * @type HTMLPurifier_Zipper
*/
- protected $inputIndex;
+ protected $inputZipper;
/**
* Array of elements and attributes this injector creates and therefore
* need to be allowed by the definition. Takes form of
* array('element' => array('attr', 'attr2'), 'element2')
+ * @type array
*/
public $needed = array();
/**
- * Index of inputTokens to rewind to.
+ * Number of elements to rewind backwards (relative).
+ * @type bool|int
*/
- protected $rewind = false;
+ protected $rewindOffset = false;
/**
* Rewind to a spot to re-perform processing. This is useful if you
* deleted a node, and now need to see if this change affected any
* earlier nodes. Rewinding does not affect other injectors, and can
* result in infinite loops if not used carefully.
+ * @param bool|int $offset
* @warning HTML Purifier will prevent you from fast-forwarding with this
* function.
*/
- public function rewind($index) {
- $this->rewind = $index;
+ public function rewindOffset($offset)
+ {
+ $this->rewindOffset = $offset;
}
/**
- * Retrieves rewind, and then unsets it.
+ * Retrieves rewind offset, and then unsets it.
+ * @return bool|int
*/
- public function getRewind() {
- $r = $this->rewind;
- $this->rewind = false;
+ public function getRewindOffset()
+ {
+ $r = $this->rewindOffset;
+ $this->rewindOffset = false;
return $r;
}
@@ -83,20 +90,23 @@ abstract class HTMLPurifier_Injector
* this allows references to important variables to be made within
* the injector. This function also checks if the HTML environment
* will work with the Injector (see checkNeeded()).
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
- * @return Boolean false if success, string of missing needed element/attribute if failure
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool|string Boolean false if success, string of missing needed element/attribute if failure
*/
- public function prepare($config, $context) {
+ public function prepare($config, $context)
+ {
$this->htmlDefinition = $config->getHTMLDefinition();
// Even though this might fail, some unit tests ignore this and
// still test checkNeeded, so be careful. Maybe get rid of that
// dependency.
$result = $this->checkNeeded($config);
- if ($result !== false) return $result;
+ if ($result !== false) {
+ return $result;
+ }
$this->currentNesting =& $context->get('CurrentNesting');
- $this->inputTokens =& $context->get('InputTokens');
- $this->inputIndex =& $context->get('InputIndex');
+ $this->currentToken =& $context->get('CurrentToken');
+ $this->inputZipper =& $context->get('InputZipper');
return false;
}
@@ -104,18 +114,26 @@ abstract class HTMLPurifier_Injector
* This function checks if the HTML environment
* will work with the Injector: if p tags are not allowed, the
* Auto-Paragraphing injector should not be enabled.
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
- * @return Boolean false if success, string of missing needed element/attribute if failure
+ * @param HTMLPurifier_Config $config
+ * @return bool|string Boolean false if success, string of missing needed element/attribute if failure
*/
- public function checkNeeded($config) {
+ public function checkNeeded($config)
+ {
$def = $config->getHTMLDefinition();
foreach ($this->needed as $element => $attributes) {
- if (is_int($element)) $element = $attributes;
- if (!isset($def->info[$element])) return $element;
- if (!is_array($attributes)) continue;
+ if (is_int($element)) {
+ $element = $attributes;
+ }
+ if (!isset($def->info[$element])) {
+ return $element;
+ }
+ if (!is_array($attributes)) {
+ continue;
+ }
foreach ($attributes as $name) {
- if (!isset($def->info[$element]->attr[$name])) return "$element.$name";
+ if (!isset($def->info[$element]->attr[$name])) {
+ return "$element.$name";
+ }
}
}
return false;
@@ -123,10 +141,11 @@ abstract class HTMLPurifier_Injector
/**
* Tests if the context node allows a certain element
- * @param $name Name of element to test for
- * @return True if element is allowed, false if it is not
+ * @param string $name Name of element to test for
+ * @return bool True if element is allowed, false if it is not
*/
- public function allowsElement($name) {
+ public function allowsElement($name)
+ {
if (!empty($this->currentNesting)) {
$parent_token = array_pop($this->currentNesting);
$this->currentNesting[] = $parent_token;
@@ -141,7 +160,9 @@ abstract class HTMLPurifier_Injector
for ($i = count($this->currentNesting) - 2; $i >= 0; $i--) {
$node = $this->currentNesting[$i];
$def = $this->htmlDefinition->info[$node->name];
- if (isset($def->excludes[$name])) return false;
+ if (isset($def->excludes[$name])) {
+ return false;
+ }
}
return true;
}
@@ -151,14 +172,22 @@ abstract class HTMLPurifier_Injector
* you reach the end of the input tokens.
* @warning Please prevent previous references from interfering with this
* functions by setting $i = null beforehand!
- * @param &$i Current integer index variable for inputTokens
- * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference
- */
- protected function forward(&$i, &$current) {
- if ($i === null) $i = $this->inputIndex + 1;
- else $i++;
- if (!isset($this->inputTokens[$i])) return false;
- $current = $this->inputTokens[$i];
+ * @param int $i Current integer index variable for inputTokens
+ * @param HTMLPurifier_Token $current Current token variable.
+ * Do NOT use $token, as that variable is also a reference
+ * @return bool
+ */
+ protected function forward(&$i, &$current)
+ {
+ if ($i === null) {
+ $i = count($this->inputZipper->back) - 1;
+ } else {
+ $i--;
+ }
+ if ($i < 0) {
+ return false;
+ }
+ $current = $this->inputZipper->back[$i];
return true;
}
@@ -166,14 +195,27 @@ abstract class HTMLPurifier_Injector
* Similar to _forward, but accepts a third parameter $nesting (which
* should be initialized at 0) and stops when we hit the end tag
* for the node $this->inputIndex starts in.
+ * @param int $i Current integer index variable for inputTokens
+ * @param HTMLPurifier_Token $current Current token variable.
+ * Do NOT use $token, as that variable is also a reference
+ * @param int $nesting
+ * @return bool
*/
- protected function forwardUntilEndToken(&$i, &$current, &$nesting) {
+ protected function forwardUntilEndToken(&$i, &$current, &$nesting)
+ {
$result = $this->forward($i, $current);
- if (!$result) return false;
- if ($nesting === null) $nesting = 0;
- if ($current instanceof HTMLPurifier_Token_Start) $nesting++;
- elseif ($current instanceof HTMLPurifier_Token_End) {
- if ($nesting <= 0) return false;
+ if (!$result) {
+ return false;
+ }
+ if ($nesting === null) {
+ $nesting = 0;
+ }
+ if ($current instanceof HTMLPurifier_Token_Start) {
+ $nesting++;
+ } elseif ($current instanceof HTMLPurifier_Token_End) {
+ if ($nesting <= 0) {
+ return false;
+ }
$nesting--;
}
return true;
@@ -184,56 +226,56 @@ abstract class HTMLPurifier_Injector
* you reach the beginning of input tokens.
* @warning Please prevent previous references from interfering with this
* functions by setting $i = null beforehand!
- * @param &$i Current integer index variable for inputTokens
- * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference
- */
- protected function backward(&$i, &$current) {
- if ($i === null) $i = $this->inputIndex - 1;
- else $i--;
- if ($i < 0) return false;
- $current = $this->inputTokens[$i];
- return true;
- }
-
- /**
- * Initializes the iterator at the current position. Use in a do {} while;
- * loop to force the _forward and _backward functions to start at the
- * current location.
- * @warning Please prevent previous references from interfering with this
- * functions by setting $i = null beforehand!
- * @param &$i Current integer index variable for inputTokens
- * @param &$current Current token variable. Do NOT use $token, as that variable is also a reference
+ * @param int $i Current integer index variable for inputTokens
+ * @param HTMLPurifier_Token $current Current token variable.
+ * Do NOT use $token, as that variable is also a reference
+ * @return bool
*/
- protected function current(&$i, &$current) {
- if ($i === null) $i = $this->inputIndex;
- $current = $this->inputTokens[$i];
+ protected function backward(&$i, &$current)
+ {
+ if ($i === null) {
+ $i = count($this->inputZipper->front) - 1;
+ } else {
+ $i--;
+ }
+ if ($i < 0) {
+ return false;
+ }
+ $current = $this->inputZipper->front[$i];
+ return true;
}
/**
* Handler that is called when a text token is processed
*/
- public function handleText(&$token) {}
+ public function handleText(&$token)
+ {
+ }
/**
* Handler that is called when a start or empty token is processed
*/
- public function handleElement(&$token) {}
+ public function handleElement(&$token)
+ {
+ }
/**
* Handler that is called when an end token is processed
*/
- public function handleEnd(&$token) {
+ public function handleEnd(&$token)
+ {
$this->notifyEnd($token);
}
/**
* Notifier that is called when an end token is processed
+ * @param HTMLPurifier_Token $token Current token variable.
* @note This differs from handlers in that the token is read-only
* @deprecated
*/
- public function notifyEnd($token) {}
-
-
+ public function notifyEnd($token)
+ {
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Injector/AutoParagraph.php b/library/HTMLPurifier/Injector/AutoParagraph.php
index afa760892..4afdd128d 100644
--- a/library/HTMLPurifier/Injector/AutoParagraph.php
+++ b/library/HTMLPurifier/Injector/AutoParagraph.php
@@ -8,17 +8,31 @@
*/
class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
{
-
+ /**
+ * @type string
+ */
public $name = 'AutoParagraph';
+
+ /**
+ * @type array
+ */
public $needed = array('p');
- private function _pStart() {
+ /**
+ * @return HTMLPurifier_Token_Start
+ */
+ private function _pStart()
+ {
$par = new HTMLPurifier_Token_Start('p');
$par->armor['MakeWellFormed_TagClosedError'] = true;
return $par;
}
- public function handleText(&$token) {
+ /**
+ * @param HTMLPurifier_Token_Text $token
+ */
+ public function handleText(&$token)
+ {
$text = $token->data;
// Does the current parent allow <p> tags?
if ($this->allowsElement('p')) {
@@ -72,11 +86,9 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
// ----
}
}
- // Is the current parent a <p> tag?
- } elseif (
- !empty($this->currentNesting) &&
- $this->currentNesting[count($this->currentNesting)-1]->name == 'p'
- ) {
+ // Is the current parent a <p> tag?
+ } elseif (!empty($this->currentNesting) &&
+ $this->currentNesting[count($this->currentNesting) - 1]->name == 'p') {
// State 3.1: ...<p>PAR1
// ----
@@ -84,7 +96,7 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
// ------------
$token = array();
$this->_splitText($text, $token);
- // Abort!
+ // Abort!
} else {
// State 4.1: ...<b>PAR1
// ----
@@ -94,7 +106,11 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
}
}
- public function handleElement(&$token) {
+ /**
+ * @param HTMLPurifier_Token $token
+ */
+ public function handleElement(&$token)
+ {
// We don't have to check if we're already in a <p> tag for block
// tokens, because the tag would have been autoclosed by MakeWellFormed.
if ($this->allowsElement('p')) {
@@ -102,7 +118,6 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
if ($this->_isInline($token)) {
// State 1: <div>...<b>
// ---
-
// Check if this token is adjacent to the parent token
// (seek backwards until token isn't whitespace)
$i = null;
@@ -110,31 +125,24 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
if (!$prev instanceof HTMLPurifier_Token_Start) {
// Token wasn't adjacent
-
- if (
- $prev instanceof HTMLPurifier_Token_Text &&
+ if ($prev instanceof HTMLPurifier_Token_Text &&
substr($prev->data, -2) === "\n\n"
) {
// State 1.1.4: <div><p>PAR1</p>\n\n<b>
// ---
-
// Quite frankly, this should be handled by splitText
$token = array($this->_pStart(), $token);
} else {
// State 1.1.1: <div><p>PAR1</p><b>
// ---
-
// State 1.1.2: <div><br /><b>
// ---
-
// State 1.1.3: <div>PAR<b>
// ---
}
-
} else {
// State 1.2.1: <div><b>
// ---
-
// Lookahead to see if <p> is needed.
if ($this->_pLookAhead()) {
// State 1.3.1: <div><b>PAR1\n\nPAR2
@@ -166,24 +174,20 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
$i = null;
if ($this->backward($i, $prev)) {
- if (
- !$prev instanceof HTMLPurifier_Token_Text
- ) {
+ if (!$prev instanceof HTMLPurifier_Token_Text) {
// State 3.1.1: ...</p>{p}<b>
// ---
-
// State 3.2.1: ...</p><div>
// -----
-
- if (!is_array($token)) $token = array($token);
+ if (!is_array($token)) {
+ $token = array($token);
+ }
array_unshift($token, new HTMLPurifier_Token_Text("\n\n"));
} else {
// State 3.1.2: ...</p>\n\n{p}<b>
// ---
-
// State 3.2.2: ...</p>\n\n<div>
// -----
-
// Note: PAR<ELEM> cannot occur because PAR would have been
// wrapped in <p> tags.
}
@@ -192,7 +196,6 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
} else {
// State 2.2: <ul><li>
// ----
-
// State 2.4: <p><b>
// ---
}
@@ -201,18 +204,17 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
/**
* Splits up a text in paragraph tokens and appends them
* to the result stream that will replace the original
- * @param $data String text data that will be processed
+ * @param string $data String text data that will be processed
* into paragraphs
- * @param $result Reference to array of tokens that the
+ * @param HTMLPurifier_Token[] $result Reference to array of tokens that the
* tags will be appended onto
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
*/
- private function _splitText($data, &$result) {
+ private function _splitText($data, &$result)
+ {
$raw_paragraphs = explode("\n\n", $data);
- $paragraphs = array(); // without empty paragraphs
+ $paragraphs = array(); // without empty paragraphs
$needs_start = false;
- $needs_end = false;
+ $needs_end = false;
$c = count($raw_paragraphs);
if ($c == 1) {
@@ -285,26 +287,33 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
array_pop($result); // removes \n\n
array_pop($result); // removes </p>
}
-
}
/**
* Returns true if passed token is inline (and, ergo, allowed in
* paragraph tags)
+ * @param HTMLPurifier_Token $token
+ * @return bool
*/
- private function _isInline($token) {
+ private function _isInline($token)
+ {
return isset($this->htmlDefinition->info['p']->child->elements[$token->name]);
}
/**
* Looks ahead in the token list and determines whether or not we need
* to insert a <p> tag.
+ * @return bool
*/
- private function _pLookAhead() {
- $this->current($i, $current);
- if ($current instanceof HTMLPurifier_Token_Start) $nesting = 1;
- else $nesting = 0;
+ private function _pLookAhead()
+ {
+ if ($this->currentToken instanceof HTMLPurifier_Token_Start) {
+ $nesting = 1;
+ } else {
+ $nesting = 0;
+ }
$ok = false;
+ $i = null;
while ($this->forwardUntilEndToken($i, $current, $nesting)) {
$result = $this->_checkNeedsP($current);
if ($result !== null) {
@@ -318,9 +327,12 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
/**
* Determines if a particular token requires an earlier inline token
* to get a paragraph. This should be used with _forwardUntilEndToken
+ * @param HTMLPurifier_Token $current
+ * @return bool
*/
- private function _checkNeedsP($current) {
- if ($current instanceof HTMLPurifier_Token_Start){
+ private function _checkNeedsP($current)
+ {
+ if ($current instanceof HTMLPurifier_Token_Start) {
if (!$this->_isInline($current)) {
// <div>PAR1<div>
// ----
@@ -339,7 +351,6 @@ class HTMLPurifier_Injector_AutoParagraph extends HTMLPurifier_Injector
}
return null;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Injector/DisplayLinkURI.php b/library/HTMLPurifier/Injector/DisplayLinkURI.php
index 9dce9bd08..c19b1bc27 100644
--- a/library/HTMLPurifier/Injector/DisplayLinkURI.php
+++ b/library/HTMLPurifier/Injector/DisplayLinkURI.php
@@ -5,15 +5,29 @@
*/
class HTMLPurifier_Injector_DisplayLinkURI extends HTMLPurifier_Injector
{
-
+ /**
+ * @type string
+ */
public $name = 'DisplayLinkURI';
+
+ /**
+ * @type array
+ */
public $needed = array('a');
- public function handleElement(&$token) {
+ /**
+ * @param $token
+ */
+ public function handleElement(&$token)
+ {
}
- public function handleEnd(&$token) {
- if (isset($token->start->attr['href'])){
+ /**
+ * @param HTMLPurifier_Token $token
+ */
+ public function handleEnd(&$token)
+ {
+ if (isset($token->start->attr['href'])) {
$url = $token->start->attr['href'];
unset($token->start->attr['href']);
$token = array($token, new HTMLPurifier_Token_Text(" ($url)"));
diff --git a/library/HTMLPurifier/Injector/Linkify.php b/library/HTMLPurifier/Injector/Linkify.php
index 296dac282..069708c25 100644
--- a/library/HTMLPurifier/Injector/Linkify.php
+++ b/library/HTMLPurifier/Injector/Linkify.php
@@ -5,12 +5,24 @@
*/
class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector
{
-
+ /**
+ * @type string
+ */
public $name = 'Linkify';
+
+ /**
+ * @type array
+ */
public $needed = array('a' => array('href'));
- public function handleText(&$token) {
- if (!$this->allowsElement('a')) return;
+ /**
+ * @param HTMLPurifier_Token $token
+ */
+ public function handleText(&$token)
+ {
+ if (!$this->allowsElement('a')) {
+ return;
+ }
if (strpos($token->data, '://') === false) {
// our really quick heuristic failed, abort
@@ -21,7 +33,8 @@ class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector
// there is/are URL(s). Let's split the string:
// Note: this regex is extremely permissive
- $bits = preg_split('#((?:https?|ftp)://[^\s\'"<>()]+)#S', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $bits = preg_split('#((?:https?|ftp)://[^\s\'",<>()]+)#Su', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE);
+
$token = array();
@@ -30,7 +43,9 @@ class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector
// $l = is link
for ($i = 0, $c = count($bits), $l = false; $i < $c; $i++, $l = !$l) {
if (!$l) {
- if ($bits[$i] === '') continue;
+ if ($bits[$i] === '') {
+ continue;
+ }
$token[] = new HTMLPurifier_Token_Text($bits[$i]);
} else {
$token[] = new HTMLPurifier_Token_Start('a', array('href' => $bits[$i]));
@@ -38,9 +53,7 @@ class HTMLPurifier_Injector_Linkify extends HTMLPurifier_Injector
$token[] = new HTMLPurifier_Token_End('a');
}
}
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Injector/PurifierLinkify.php b/library/HTMLPurifier/Injector/PurifierLinkify.php
index ad2455a91..cb9046f33 100644
--- a/library/HTMLPurifier/Injector/PurifierLinkify.php
+++ b/library/HTMLPurifier/Injector/PurifierLinkify.php
@@ -6,19 +6,43 @@
*/
class HTMLPurifier_Injector_PurifierLinkify extends HTMLPurifier_Injector
{
-
+ /**
+ * @type string
+ */
public $name = 'PurifierLinkify';
+
+ /**
+ * @type string
+ */
public $docURL;
+
+ /**
+ * @type array
+ */
public $needed = array('a' => array('href'));
- public function prepare($config, $context) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
+ */
+ public function prepare($config, $context)
+ {
$this->docURL = $config->get('AutoFormat.PurifierLinkify.DocURL');
return parent::prepare($config, $context);
}
- public function handleText(&$token) {
- if (!$this->allowsElement('a')) return;
- if (strpos($token->data, '%') === false) return;
+ /**
+ * @param HTMLPurifier_Token $token
+ */
+ public function handleText(&$token)
+ {
+ if (!$this->allowsElement('a')) {
+ return;
+ }
+ if (strpos($token->data, '%') === false) {
+ return;
+ }
$bits = preg_split('#%([a-z0-9]+\.[a-z0-9]+)#Si', $token->data, -1, PREG_SPLIT_DELIM_CAPTURE);
$token = array();
@@ -28,18 +52,20 @@ class HTMLPurifier_Injector_PurifierLinkify extends HTMLPurifier_Injector
// $l = is link
for ($i = 0, $c = count($bits), $l = false; $i < $c; $i++, $l = !$l) {
if (!$l) {
- if ($bits[$i] === '') continue;
+ if ($bits[$i] === '') {
+ continue;
+ }
$token[] = new HTMLPurifier_Token_Text($bits[$i]);
} else {
- $token[] = new HTMLPurifier_Token_Start('a',
- array('href' => str_replace('%s', $bits[$i], $this->docURL)));
+ $token[] = new HTMLPurifier_Token_Start(
+ 'a',
+ array('href' => str_replace('%s', $bits[$i], $this->docURL))
+ );
$token[] = new HTMLPurifier_Token_Text('%' . $bits[$i]);
$token[] = new HTMLPurifier_Token_End('a');
}
}
-
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Injector/RemoveEmpty.php b/library/HTMLPurifier/Injector/RemoveEmpty.php
index 638bfca03..cd885722e 100644
--- a/library/HTMLPurifier/Injector/RemoveEmpty.php
+++ b/library/HTMLPurifier/Injector/RemoveEmpty.php
@@ -2,10 +2,44 @@
class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector
{
+ /**
+ * @type HTMLPurifier_Context
+ */
+ private $context;
- private $context, $config, $attrValidator, $removeNbsp, $removeNbspExceptions;
+ /**
+ * @type HTMLPurifier_Config
+ */
+ private $config;
- public function prepare($config, $context) {
+ /**
+ * @type HTMLPurifier_AttrValidator
+ */
+ private $attrValidator;
+
+ /**
+ * @type bool
+ */
+ private $removeNbsp;
+
+ /**
+ * @type bool
+ */
+ private $removeNbspExceptions;
+
+ /**
+ * @type array
+ * TODO: make me configurable
+ */
+ private $_exclude = array('colgroup' => 1, 'th' => 1, 'td' => 1, 'iframe' => 1);
+
+ /**
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return void
+ */
+ public function prepare($config, $context)
+ {
parent::prepare($config, $context);
$this->config = $config;
$this->context = $context;
@@ -14,38 +48,54 @@ class HTMLPurifier_Injector_RemoveEmpty extends HTMLPurifier_Injector
$this->attrValidator = new HTMLPurifier_AttrValidator();
}
- public function handleElement(&$token) {
- if (!$token instanceof HTMLPurifier_Token_Start) return;
+ /**
+ * @param HTMLPurifier_Token $token
+ */
+ public function handleElement(&$token)
+ {
+ if (!$token instanceof HTMLPurifier_Token_Start) {
+ return;
+ }
$next = false;
- for ($i = $this->inputIndex + 1, $c = count($this->inputTokens); $i < $c; $i++) {
- $next = $this->inputTokens[$i];
+ $deleted = 1; // the current tag
+ for ($i = count($this->inputZipper->back) - 1; $i >= 0; $i--, $deleted++) {
+ $next = $this->inputZipper->back[$i];
if ($next instanceof HTMLPurifier_Token_Text) {
- if ($next->is_whitespace) continue;
+ if ($next->is_whitespace) {
+ continue;
+ }
if ($this->removeNbsp && !isset($this->removeNbspExceptions[$token->name])) {
$plain = str_replace("\xC2\xA0", "", $next->data);
$isWsOrNbsp = $plain === '' || ctype_space($plain);
- if ($isWsOrNbsp) continue;
+ if ($isWsOrNbsp) {
+ continue;
+ }
}
}
break;
}
if (!$next || ($next instanceof HTMLPurifier_Token_End && $next->name == $token->name)) {
- if ($token->name == 'colgroup') return;
+ if (isset($this->_exclude[$token->name])) {
+ return;
+ }
$this->attrValidator->validateToken($token, $this->config, $this->context);
$token->armor['ValidateAttributes'] = true;
- if (isset($token->attr['id']) || isset($token->attr['name'])) return;
- $token = $i - $this->inputIndex + 1;
- for ($b = $this->inputIndex - 1; $b > 0; $b--) {
- $prev = $this->inputTokens[$b];
- if ($prev instanceof HTMLPurifier_Token_Text && $prev->is_whitespace) continue;
+ if (isset($token->attr['id']) || isset($token->attr['name'])) {
+ return;
+ }
+ $token = $deleted + 1;
+ for ($b = 0, $c = count($this->inputZipper->front); $b < $c; $b++) {
+ $prev = $this->inputZipper->front[$b];
+ if ($prev instanceof HTMLPurifier_Token_Text && $prev->is_whitespace) {
+ continue;
+ }
break;
}
// This is safe because we removed the token that triggered this.
- $this->rewind($b - 1);
+ $this->rewindOffset($b+$deleted);
return;
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php b/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php
index b21313470..9ee7aa84d 100644
--- a/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php
+++ b/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php
@@ -5,25 +5,45 @@
*/
class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_Injector
{
+ /**
+ * @type string
+ */
public $name = 'RemoveSpansWithoutAttributes';
+
+ /**
+ * @type array
+ */
public $needed = array('span');
+ /**
+ * @type HTMLPurifier_AttrValidator
+ */
private $attrValidator;
/**
- * Used by AttrValidator
+ * Used by AttrValidator.
+ * @type HTMLPurifier_Config
*/
private $config;
+
+ /**
+ * @type HTMLPurifier_Context
+ */
private $context;
- public function prepare($config, $context) {
+ public function prepare($config, $context)
+ {
$this->attrValidator = new HTMLPurifier_AttrValidator();
$this->config = $config;
$this->context = $context;
return parent::prepare($config, $context);
}
- public function handleElement(&$token) {
+ /**
+ * @param HTMLPurifier_Token $token
+ */
+ public function handleElement(&$token)
+ {
if ($token->name !== 'span' || !$token instanceof HTMLPurifier_Token_Start) {
return;
}
@@ -39,8 +59,8 @@ class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_In
}
$nesting = 0;
- $spanContentTokens = array();
- while ($this->forwardUntilEndToken($i, $current, $nesting)) {}
+ while ($this->forwardUntilEndToken($i, $current, $nesting)) {
+ }
if ($current instanceof HTMLPurifier_Token_End && $current->name === 'span') {
// Mark closing span tag for deletion
@@ -50,7 +70,11 @@ class HTMLPurifier_Injector_RemoveSpansWithoutAttributes extends HTMLPurifier_In
}
}
- public function handleEnd(&$token) {
+ /**
+ * @param HTMLPurifier_Token $token
+ */
+ public function handleEnd(&$token)
+ {
if ($token->markForDeletion) {
$token = false;
}
diff --git a/library/HTMLPurifier/Injector/SafeObject.php b/library/HTMLPurifier/Injector/SafeObject.php
index 9e178ce01..3d17e07af 100644
--- a/library/HTMLPurifier/Injector/SafeObject.php
+++ b/library/HTMLPurifier/Injector/SafeObject.php
@@ -6,29 +6,61 @@
*/
class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
{
+ /**
+ * @type string
+ */
public $name = 'SafeObject';
+
+ /**
+ * @type array
+ */
public $needed = array('object', 'param');
+ /**
+ * @type array
+ */
protected $objectStack = array();
- protected $paramStack = array();
- // Keep this synchronized with AttrTransform/SafeParam.php
+ /**
+ * @type array
+ */
+ protected $paramStack = array();
+
+ /**
+ * Keep this synchronized with AttrTransform/SafeParam.php.
+ * @type array
+ */
protected $addParam = array(
'allowScriptAccess' => 'never',
'allowNetworking' => 'internal',
);
+
+ /**
+ * @type array
+ */
protected $allowedParam = array(
'wmode' => true,
'movie' => true,
'flashvars' => true,
'src' => true,
+ 'allowFullScreen' => true, // if omitted, assume to be 'false'
);
- public function prepare($config, $context) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return void
+ */
+ public function prepare($config, $context)
+ {
parent::prepare($config, $context);
}
- public function handleElement(&$token) {
+ /**
+ * @param HTMLPurifier_Token $token
+ */
+ public function handleElement(&$token)
+ {
if ($token->name == 'object') {
$this->objectStack[] = $token;
$this->paramStack[] = array();
@@ -50,16 +82,15 @@ class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
// attribute, which we need if a type is specified. This is
// *very* Flash specific.
if (!isset($this->objectStack[$i]->attr['data']) &&
- ($token->attr['name'] == 'movie' || $token->attr['name'] == 'src')) {
+ ($token->attr['name'] == 'movie' || $token->attr['name'] == 'src')
+ ) {
$this->objectStack[$i]->attr['data'] = $token->attr['value'];
}
// Check if the parameter is the correct value but has not
// already been added
- if (
- !isset($this->paramStack[$i][$n]) &&
+ if (!isset($this->paramStack[$i][$n]) &&
isset($this->addParam[$n]) &&
- $token->attr['name'] === $this->addParam[$n]
- ) {
+ $token->attr['name'] === $this->addParam[$n]) {
// keep token, and add to param stack
$this->paramStack[$i][$n] = true;
} elseif (isset($this->allowedParam[$n])) {
@@ -75,7 +106,8 @@ class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
}
}
- public function handleEnd(&$token) {
+ public function handleEnd(&$token)
+ {
// This is the WRONG way of handling the object and param stacks;
// we should be inserting them directly on the relevant object tokens
// so that the global stack handling handles it.
@@ -84,7 +116,6 @@ class HTMLPurifier_Injector_SafeObject extends HTMLPurifier_Injector
array_pop($this->paramStack);
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Language.php b/library/HTMLPurifier/Language.php
index 3e2be03b5..65277dd43 100644
--- a/library/HTMLPurifier/Language.php
+++ b/library/HTMLPurifier/Language.php
@@ -8,22 +8,26 @@ class HTMLPurifier_Language
{
/**
- * ISO 639 language code of language. Prefers shortest possible version
+ * ISO 639 language code of language. Prefers shortest possible version.
+ * @type string
*/
public $code = 'en';
/**
- * Fallback language code
+ * Fallback language code.
+ * @type bool|string
*/
public $fallback = false;
/**
- * Array of localizable messages
+ * Array of localizable messages.
+ * @type array
*/
public $messages = array();
/**
- * Array of localizable error codes
+ * Array of localizable error codes.
+ * @type array
*/
public $errorNames = array();
@@ -31,21 +35,33 @@ class HTMLPurifier_Language
* True if no message file was found for this language, so English
* is being used instead. Check this if you'd like to notify the
* user that they've used a non-supported language.
+ * @type bool
*/
public $error = false;
/**
* Has the language object been loaded yet?
+ * @type bool
* @todo Make it private, fix usage in HTMLPurifier_LanguageTest
*/
public $_loaded = false;
/**
- * Instances of HTMLPurifier_Config and HTMLPurifier_Context
+ * @type HTMLPurifier_Config
*/
- protected $config, $context;
+ protected $config;
- public function __construct($config, $context) {
+ /**
+ * @type HTMLPurifier_Context
+ */
+ protected $context;
+
+ /**
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ */
+ public function __construct($config, $context)
+ {
$this->config = $config;
$this->context = $context;
}
@@ -54,8 +70,11 @@ class HTMLPurifier_Language
* Loads language object with necessary info from factory cache
* @note This is a lazy loader
*/
- public function load() {
- if ($this->_loaded) return;
+ public function load()
+ {
+ if ($this->_loaded) {
+ return;
+ }
$factory = HTMLPurifier_LanguageFactory::instance();
$factory->loadLanguage($this->code);
foreach ($factory->keys as $key) {
@@ -66,31 +85,43 @@ class HTMLPurifier_Language
/**
* Retrieves a localised message.
- * @param $key string identifier of message
+ * @param string $key string identifier of message
* @return string localised message
*/
- public function getMessage($key) {
- if (!$this->_loaded) $this->load();
- if (!isset($this->messages[$key])) return "[$key]";
+ public function getMessage($key)
+ {
+ if (!$this->_loaded) {
+ $this->load();
+ }
+ if (!isset($this->messages[$key])) {
+ return "[$key]";
+ }
return $this->messages[$key];
}
/**
* Retrieves a localised error name.
- * @param $int integer error number, corresponding to PHP's error
- * reporting
+ * @param int $int error number, corresponding to PHP's error reporting
* @return string localised message
*/
- public function getErrorName($int) {
- if (!$this->_loaded) $this->load();
- if (!isset($this->errorNames[$int])) return "[Error: $int]";
+ public function getErrorName($int)
+ {
+ if (!$this->_loaded) {
+ $this->load();
+ }
+ if (!isset($this->errorNames[$int])) {
+ return "[Error: $int]";
+ }
return $this->errorNames[$int];
}
/**
* Converts an array list into a string readable representation
+ * @param array $array
+ * @return string
*/
- public function listify($array) {
+ public function listify($array)
+ {
$sep = $this->getMessage('Item separator');
$sep_last = $this->getMessage('Item separator last');
$ret = '';
@@ -108,15 +139,20 @@ class HTMLPurifier_Language
/**
* Formats a localised message with passed parameters
- * @param $key string identifier of message
- * @param $args Parameters to substitute in
+ * @param string $key string identifier of message
+ * @param array $args Parameters to substitute in
* @return string localised message
* @todo Implement conditionals? Right now, some messages make
* reference to line numbers, but those aren't always available
*/
- public function formatMessage($key, $args = array()) {
- if (!$this->_loaded) $this->load();
- if (!isset($this->messages[$key])) return "[$key]";
+ public function formatMessage($key, $args = array())
+ {
+ if (!$this->_loaded) {
+ $this->load();
+ }
+ if (!isset($this->messages[$key])) {
+ return "[$key]";
+ }
$raw = $this->messages[$key];
$subst = array();
$generator = false;
@@ -124,9 +160,15 @@ class HTMLPurifier_Language
if (is_object($value)) {
if ($value instanceof HTMLPurifier_Token) {
// factor this out some time
- if (!$generator) $generator = $this->context->get('Generator');
- if (isset($value->name)) $subst['$'.$i.'.Name'] = $value->name;
- if (isset($value->data)) $subst['$'.$i.'.Data'] = $value->data;
+ if (!$generator) {
+ $generator = $this->context->get('Generator');
+ }
+ if (isset($value->name)) {
+ $subst['$'.$i.'.Name'] = $value->name;
+ }
+ if (isset($value->data)) {
+ $subst['$'.$i.'.Data'] = $value->data;
+ }
$subst['$'.$i.'.Compact'] =
$subst['$'.$i.'.Serialized'] = $generator->generateFromToken($value);
// a more complex algorithm for compact representation
@@ -157,7 +199,6 @@ class HTMLPurifier_Language
}
return strtr($raw, $subst);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Language/classes/en-x-test.php b/library/HTMLPurifier/Language/classes/en-x-test.php
index d52fcb7ac..8828f5cde 100644
--- a/library/HTMLPurifier/Language/classes/en-x-test.php
+++ b/library/HTMLPurifier/Language/classes/en-x-test.php
@@ -4,9 +4,6 @@
class HTMLPurifier_Language_en_x_test extends HTMLPurifier_Language
{
-
-
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Language/messages/en.php b/library/HTMLPurifier/Language/messages/en.php
index 8d7b5736b..c7f197e1e 100644
--- a/library/HTMLPurifier/Language/messages/en.php
+++ b/library/HTMLPurifier/Language/messages/en.php
@@ -4,60 +4,52 @@ $fallback = false;
$messages = array(
-'HTMLPurifier' => 'HTML Purifier',
-
+ 'HTMLPurifier' => 'HTML Purifier',
// for unit testing purposes
-'LanguageFactoryTest: Pizza' => 'Pizza',
-'LanguageTest: List' => '$1',
-'LanguageTest: Hash' => '$1.Keys; $1.Values',
-
-'Item separator' => ', ',
-'Item separator last' => ' and ', // non-Harvard style
-
-'ErrorCollector: No errors' => 'No errors detected. However, because error reporting is still incomplete, there may have been errors that the error collector was not notified of; please inspect the output HTML carefully.',
-'ErrorCollector: At line' => ' at line $line',
-'ErrorCollector: Incidental errors' => 'Incidental errors',
-
-'Lexer: Unclosed comment' => 'Unclosed comment',
-'Lexer: Unescaped lt' => 'Unescaped less-than sign (<) should be &lt;',
-'Lexer: Missing gt' => 'Missing greater-than sign (>), previous less-than sign (<) should be escaped',
-'Lexer: Missing attribute key' => 'Attribute declaration has no key',
-'Lexer: Missing end quote' => 'Attribute declaration has no end quote',
-'Lexer: Extracted body' => 'Removed document metadata tags',
-
-'Strategy_RemoveForeignElements: Tag transform' => '<$1> element transformed into $CurrentToken.Serialized',
-'Strategy_RemoveForeignElements: Missing required attribute' => '$CurrentToken.Compact element missing required attribute $1',
-'Strategy_RemoveForeignElements: Foreign element to text' => 'Unrecognized $CurrentToken.Serialized tag converted to text',
-'Strategy_RemoveForeignElements: Foreign element removed' => 'Unrecognized $CurrentToken.Serialized tag removed',
-'Strategy_RemoveForeignElements: Comment removed' => 'Comment containing "$CurrentToken.Data" removed',
-'Strategy_RemoveForeignElements: Foreign meta element removed' => 'Unrecognized $CurrentToken.Serialized meta tag and all descendants removed',
-'Strategy_RemoveForeignElements: Token removed to end' => 'Tags and text starting from $1 element where removed to end',
-'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' => 'Trailing hyphen(s) in comment removed',
-'Strategy_RemoveForeignElements: Hyphens in comment collapsed' => 'Double hyphens in comments are not allowed, and were collapsed into single hyphens',
-
-'Strategy_MakeWellFormed: Unnecessary end tag removed' => 'Unnecessary $CurrentToken.Serialized tag removed',
-'Strategy_MakeWellFormed: Unnecessary end tag to text' => 'Unnecessary $CurrentToken.Serialized tag converted to text',
-'Strategy_MakeWellFormed: Tag auto closed' => '$1.Compact started on line $1.Line auto-closed by $CurrentToken.Compact',
-'Strategy_MakeWellFormed: Tag carryover' => '$1.Compact started on line $1.Line auto-continued into $CurrentToken.Compact',
-'Strategy_MakeWellFormed: Stray end tag removed' => 'Stray $CurrentToken.Serialized tag removed',
-'Strategy_MakeWellFormed: Stray end tag to text' => 'Stray $CurrentToken.Serialized tag converted to text',
-'Strategy_MakeWellFormed: Tag closed by element end' => '$1.Compact tag started on line $1.Line closed by end of $CurrentToken.Serialized',
-'Strategy_MakeWellFormed: Tag closed by document end' => '$1.Compact tag started on line $1.Line closed by end of document',
-
-'Strategy_FixNesting: Node removed' => '$CurrentToken.Compact node removed',
-'Strategy_FixNesting: Node excluded' => '$CurrentToken.Compact node removed due to descendant exclusion by ancestor element',
-'Strategy_FixNesting: Node reorganized' => 'Contents of $CurrentToken.Compact node reorganized to enforce its content model',
-'Strategy_FixNesting: Node contents removed' => 'Contents of $CurrentToken.Compact node removed',
-
-'AttrValidator: Attributes transformed' => 'Attributes on $CurrentToken.Compact transformed from $1.Keys to $2.Keys',
-'AttrValidator: Attribute removed' => '$CurrentAttr.Name attribute on $CurrentToken.Compact removed',
-
+ 'LanguageFactoryTest: Pizza' => 'Pizza',
+ 'LanguageTest: List' => '$1',
+ 'LanguageTest: Hash' => '$1.Keys; $1.Values',
+ 'Item separator' => ', ',
+ 'Item separator last' => ' and ', // non-Harvard style
+
+ 'ErrorCollector: No errors' => 'No errors detected. However, because error reporting is still incomplete, there may have been errors that the error collector was not notified of; please inspect the output HTML carefully.',
+ 'ErrorCollector: At line' => ' at line $line',
+ 'ErrorCollector: Incidental errors' => 'Incidental errors',
+ 'Lexer: Unclosed comment' => 'Unclosed comment',
+ 'Lexer: Unescaped lt' => 'Unescaped less-than sign (<) should be &lt;',
+ 'Lexer: Missing gt' => 'Missing greater-than sign (>), previous less-than sign (<) should be escaped',
+ 'Lexer: Missing attribute key' => 'Attribute declaration has no key',
+ 'Lexer: Missing end quote' => 'Attribute declaration has no end quote',
+ 'Lexer: Extracted body' => 'Removed document metadata tags',
+ 'Strategy_RemoveForeignElements: Tag transform' => '<$1> element transformed into $CurrentToken.Serialized',
+ 'Strategy_RemoveForeignElements: Missing required attribute' => '$CurrentToken.Compact element missing required attribute $1',
+ 'Strategy_RemoveForeignElements: Foreign element to text' => 'Unrecognized $CurrentToken.Serialized tag converted to text',
+ 'Strategy_RemoveForeignElements: Foreign element removed' => 'Unrecognized $CurrentToken.Serialized tag removed',
+ 'Strategy_RemoveForeignElements: Comment removed' => 'Comment containing "$CurrentToken.Data" removed',
+ 'Strategy_RemoveForeignElements: Foreign meta element removed' => 'Unrecognized $CurrentToken.Serialized meta tag and all descendants removed',
+ 'Strategy_RemoveForeignElements: Token removed to end' => 'Tags and text starting from $1 element where removed to end',
+ 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed' => 'Trailing hyphen(s) in comment removed',
+ 'Strategy_RemoveForeignElements: Hyphens in comment collapsed' => 'Double hyphens in comments are not allowed, and were collapsed into single hyphens',
+ 'Strategy_MakeWellFormed: Unnecessary end tag removed' => 'Unnecessary $CurrentToken.Serialized tag removed',
+ 'Strategy_MakeWellFormed: Unnecessary end tag to text' => 'Unnecessary $CurrentToken.Serialized tag converted to text',
+ 'Strategy_MakeWellFormed: Tag auto closed' => '$1.Compact started on line $1.Line auto-closed by $CurrentToken.Compact',
+ 'Strategy_MakeWellFormed: Tag carryover' => '$1.Compact started on line $1.Line auto-continued into $CurrentToken.Compact',
+ 'Strategy_MakeWellFormed: Stray end tag removed' => 'Stray $CurrentToken.Serialized tag removed',
+ 'Strategy_MakeWellFormed: Stray end tag to text' => 'Stray $CurrentToken.Serialized tag converted to text',
+ 'Strategy_MakeWellFormed: Tag closed by element end' => '$1.Compact tag started on line $1.Line closed by end of $CurrentToken.Serialized',
+ 'Strategy_MakeWellFormed: Tag closed by document end' => '$1.Compact tag started on line $1.Line closed by end of document',
+ 'Strategy_FixNesting: Node removed' => '$CurrentToken.Compact node removed',
+ 'Strategy_FixNesting: Node excluded' => '$CurrentToken.Compact node removed due to descendant exclusion by ancestor element',
+ 'Strategy_FixNesting: Node reorganized' => 'Contents of $CurrentToken.Compact node reorganized to enforce its content model',
+ 'Strategy_FixNesting: Node contents removed' => 'Contents of $CurrentToken.Compact node removed',
+ 'AttrValidator: Attributes transformed' => 'Attributes on $CurrentToken.Compact transformed from $1.Keys to $2.Keys',
+ 'AttrValidator: Attribute removed' => '$CurrentAttr.Name attribute on $CurrentToken.Compact removed',
);
$errorNames = array(
- E_ERROR => 'Error',
+ E_ERROR => 'Error',
E_WARNING => 'Warning',
- E_NOTICE => 'Notice'
+ E_NOTICE => 'Notice'
);
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/LanguageFactory.php b/library/HTMLPurifier/LanguageFactory.php
index 134ef8c74..4e35272d8 100644
--- a/library/HTMLPurifier/LanguageFactory.php
+++ b/library/HTMLPurifier/LanguageFactory.php
@@ -11,50 +11,53 @@ class HTMLPurifier_LanguageFactory
{
/**
- * Cache of language code information used to load HTMLPurifier_Language objects
+ * Cache of language code information used to load HTMLPurifier_Language objects.
* Structure is: $factory->cache[$language_code][$key] = $value
- * @value array map
+ * @type array
*/
public $cache;
/**
* Valid keys in the HTMLPurifier_Language object. Designates which
* variables to slurp out of a message file.
- * @value array list
+ * @type array
*/
public $keys = array('fallback', 'messages', 'errorNames');
/**
- * Instance of HTMLPurifier_AttrDef_Lang to validate language codes
- * @value object HTMLPurifier_AttrDef_Lang
+ * Instance to validate language codes.
+ * @type HTMLPurifier_AttrDef_Lang
+ *
*/
protected $validator;
/**
* Cached copy of dirname(__FILE__), directory of current file without
- * trailing slash
- * @value string filename
+ * trailing slash.
+ * @type string
*/
protected $dir;
/**
- * Keys whose contents are a hash map and can be merged
- * @value array lookup
+ * Keys whose contents are a hash map and can be merged.
+ * @type array
*/
protected $mergeable_keys_map = array('messages' => true, 'errorNames' => true);
/**
- * Keys whose contents are a list and can be merged
+ * Keys whose contents are a list and can be merged.
* @value array lookup
*/
protected $mergeable_keys_list = array();
/**
* Retrieve sole instance of the factory.
- * @param $prototype Optional prototype to overload sole instance with,
+ * @param HTMLPurifier_LanguageFactory $prototype Optional prototype to overload sole instance with,
* or bool true to reset to default factory.
+ * @return HTMLPurifier_LanguageFactory
*/
- public static function instance($prototype = null) {
+ public static function instance($prototype = null)
+ {
static $instance = null;
if ($prototype !== null) {
$instance = $prototype;
@@ -69,28 +72,34 @@ class HTMLPurifier_LanguageFactory
* Sets up the singleton, much like a constructor
* @note Prevents people from getting this outside of the singleton
*/
- public function setup() {
+ public function setup()
+ {
$this->validator = new HTMLPurifier_AttrDef_Lang();
$this->dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier';
}
/**
* Creates a language object, handles class fallbacks
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
- * @param $code Code to override configuration with. Private parameter.
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @param bool|string $code Code to override configuration with. Private parameter.
+ * @return HTMLPurifier_Language
*/
- public function create($config, $context, $code = false) {
-
+ public function create($config, $context, $code = false)
+ {
// validate language code
if ($code === false) {
$code = $this->validator->validate(
- $config->get('Core.Language'), $config, $context
+ $config->get('Core.Language'),
+ $config,
+ $context
);
} else {
$code = $this->validator->validate($code, $config, $context);
}
- if ($code === false) $code = 'en'; // malformed code becomes English
+ if ($code === false) {
+ $code = 'en'; // malformed code becomes English
+ }
$pcode = str_replace('-', '_', $code); // make valid PHP classname
static $depth = 0; // recursion protection
@@ -114,32 +123,34 @@ class HTMLPurifier_LanguageFactory
$depth--;
}
}
-
$lang->code = $code;
-
return $lang;
-
}
/**
* Returns the fallback language for language
* @note Loads the original language into cache
- * @param $code string language code
+ * @param string $code language code
+ * @return string|bool
*/
- public function getFallbackFor($code) {
+ public function getFallbackFor($code)
+ {
$this->loadLanguage($code);
return $this->cache[$code]['fallback'];
}
/**
* Loads language into the cache, handles message file and fallbacks
- * @param $code string language code
+ * @param string $code language code
*/
- public function loadLanguage($code) {
+ public function loadLanguage($code)
+ {
static $languages_seen = array(); // recursion guard
// abort if we've already loaded it
- if (isset($this->cache[$code])) return;
+ if (isset($this->cache[$code])) {
+ return;
+ }
// generate filename
$filename = $this->dir . '/Language/messages/' . $code . '.php';
@@ -162,8 +173,11 @@ class HTMLPurifier_LanguageFactory
// infinite recursion guard
if (isset($languages_seen[$code])) {
- trigger_error('Circular fallback reference in language ' .
- $code, E_USER_ERROR);
+ trigger_error(
+ 'Circular fallback reference in language ' .
+ $code,
+ E_USER_ERROR
+ );
$fallback = 'en';
}
$language_seen[$code] = true;
@@ -173,26 +187,23 @@ class HTMLPurifier_LanguageFactory
$fallback_cache = $this->cache[$fallback];
// merge fallback with current language
- foreach ( $this->keys as $key ) {
+ foreach ($this->keys as $key) {
if (isset($cache[$key]) && isset($fallback_cache[$key])) {
if (isset($this->mergeable_keys_map[$key])) {
$cache[$key] = $cache[$key] + $fallback_cache[$key];
} elseif (isset($this->mergeable_keys_list[$key])) {
- $cache[$key] = array_merge( $fallback_cache[$key], $cache[$key] );
+ $cache[$key] = array_merge($fallback_cache[$key], $cache[$key]);
}
} else {
$cache[$key] = $fallback_cache[$key];
}
}
-
}
// save to cache for later retrieval
$this->cache[$code] = $cache;
-
return;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Length.php b/library/HTMLPurifier/Length.php
index 8d2a46b7d..bbfbe6624 100644
--- a/library/HTMLPurifier/Length.php
+++ b/library/HTMLPurifier/Length.php
@@ -9,21 +9,25 @@ class HTMLPurifier_Length
/**
* String numeric magnitude.
+ * @type string
*/
protected $n;
/**
* String unit. False is permitted if $n = 0.
+ * @type string|bool
*/
protected $unit;
/**
* Whether or not this length is valid. Null if not calculated yet.
+ * @type bool
*/
protected $isValid;
/**
- * Lookup array of units recognized by CSS 2.1
+ * Array Lookup array of units recognized by CSS 2.1
+ * @type array
*/
protected static $allowedUnits = array(
'em' => true, 'ex' => true, 'px' => true, 'in' => true,
@@ -31,85 +35,126 @@ class HTMLPurifier_Length
);
/**
- * @param number $n Magnitude
- * @param string $u Unit
+ * @param string $n Magnitude
+ * @param bool|string $u Unit
*/
- public function __construct($n = '0', $u = false) {
+ public function __construct($n = '0', $u = false)
+ {
$this->n = (string) $n;
$this->unit = $u !== false ? (string) $u : false;
}
/**
* @param string $s Unit string, like '2em' or '3.4in'
+ * @return HTMLPurifier_Length
* @warning Does not perform validation.
*/
- static public function make($s) {
- if ($s instanceof HTMLPurifier_Length) return $s;
+ public static function make($s)
+ {
+ if ($s instanceof HTMLPurifier_Length) {
+ return $s;
+ }
$n_length = strspn($s, '1234567890.+-');
$n = substr($s, 0, $n_length);
$unit = substr($s, $n_length);
- if ($unit === '') $unit = false;
+ if ($unit === '') {
+ $unit = false;
+ }
return new HTMLPurifier_Length($n, $unit);
}
/**
* Validates the number and unit.
+ * @return bool
*/
- protected function validate() {
+ protected function validate()
+ {
// Special case:
- if ($this->n === '+0' || $this->n === '-0') $this->n = '0';
- if ($this->n === '0' && $this->unit === false) return true;
- if (!ctype_lower($this->unit)) $this->unit = strtolower($this->unit);
- if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) return false;
+ if ($this->n === '+0' || $this->n === '-0') {
+ $this->n = '0';
+ }
+ if ($this->n === '0' && $this->unit === false) {
+ return true;
+ }
+ if (!ctype_lower($this->unit)) {
+ $this->unit = strtolower($this->unit);
+ }
+ if (!isset(HTMLPurifier_Length::$allowedUnits[$this->unit])) {
+ return false;
+ }
// Hack:
$def = new HTMLPurifier_AttrDef_CSS_Number();
$result = $def->validate($this->n, false, false);
- if ($result === false) return false;
+ if ($result === false) {
+ return false;
+ }
$this->n = $result;
return true;
}
/**
* Returns string representation of number.
+ * @return string
*/
- public function toString() {
- if (!$this->isValid()) return false;
+ public function toString()
+ {
+ if (!$this->isValid()) {
+ return false;
+ }
return $this->n . $this->unit;
}
/**
* Retrieves string numeric magnitude.
+ * @return string
*/
- public function getN() {return $this->n;}
+ public function getN()
+ {
+ return $this->n;
+ }
/**
* Retrieves string unit.
+ * @return string
*/
- public function getUnit() {return $this->unit;}
+ public function getUnit()
+ {
+ return $this->unit;
+ }
/**
* Returns true if this length unit is valid.
+ * @return bool
*/
- public function isValid() {
- if ($this->isValid === null) $this->isValid = $this->validate();
+ public function isValid()
+ {
+ if ($this->isValid === null) {
+ $this->isValid = $this->validate();
+ }
return $this->isValid;
}
/**
* Compares two lengths, and returns 1 if greater, -1 if less and 0 if equal.
+ * @param HTMLPurifier_Length $l
+ * @return int
* @warning If both values are too large or small, this calculation will
* not work properly
*/
- public function compareTo($l) {
- if ($l === false) return false;
+ public function compareTo($l)
+ {
+ if ($l === false) {
+ return false;
+ }
if ($l->unit !== $this->unit) {
$converter = new HTMLPurifier_UnitConverter();
$l = $converter->convert($l, $this->unit);
- if ($l === false) return false;
+ if ($l === false) {
+ return false;
+ }
}
return $this->n - $l->n;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Lexer.php b/library/HTMLPurifier/Lexer.php
index b05e11546..43732621d 100644
--- a/library/HTMLPurifier/Lexer.php
+++ b/library/HTMLPurifier/Lexer.php
@@ -62,16 +62,20 @@ class HTMLPurifier_Lexer
* To specify your own prototype, set %Core.LexerImpl to it.
* This change in behavior de-singletonizes the lexer object.
*
- * @param $config Instance of HTMLPurifier_Config
- * @return Concrete lexer.
+ * @param HTMLPurifier_Config $config
+ * @return HTMLPurifier_Lexer
+ * @throws HTMLPurifier_Exception
*/
- public static function create($config) {
-
+ public static function create($config)
+ {
if (!($config instanceof HTMLPurifier_Config)) {
$lexer = $config;
- trigger_error("Passing a prototype to
- HTMLPurifier_Lexer::create() is deprecated, please instead
- use %Core.LexerImpl", E_USER_WARNING);
+ trigger_error(
+ "Passing a prototype to
+ HTMLPurifier_Lexer::create() is deprecated, please instead
+ use %Core.LexerImpl",
+ E_USER_WARNING
+ );
} else {
$lexer = $config->get('Core.LexerImpl');
}
@@ -84,30 +88,28 @@ class HTMLPurifier_Lexer
if (is_object($lexer)) {
$inst = $lexer;
} else {
-
- if (is_null($lexer)) { do {
- // auto-detection algorithm
-
- if ($needs_tracking) {
- $lexer = 'DirectLex';
- break;
- }
-
- if (
- class_exists('DOMDocument') &&
- method_exists('DOMDocument', 'loadHTML') &&
- !extension_loaded('domxml')
- ) {
- // check for DOM support, because while it's part of the
- // core, it can be disabled compile time. Also, the PECL
- // domxml extension overrides the default DOM, and is evil
- // and nasty and we shan't bother to support it
- $lexer = 'DOMLex';
- } else {
- $lexer = 'DirectLex';
- }
-
- } while(0); } // do..while so we can break
+ if (is_null($lexer)) {
+ do {
+ // auto-detection algorithm
+ if ($needs_tracking) {
+ $lexer = 'DirectLex';
+ break;
+ }
+
+ if (class_exists('DOMDocument') &&
+ method_exists('DOMDocument', 'loadHTML') &&
+ !extension_loaded('domxml')
+ ) {
+ // check for DOM support, because while it's part of the
+ // core, it can be disabled compile time. Also, the PECL
+ // domxml extension overrides the default DOM, and is evil
+ // and nasty and we shan't bother to support it
+ $lexer = 'DOMLex';
+ } else {
+ $lexer = 'DirectLex';
+ }
+ } while (0);
+ } // do..while so we can break
// instantiate recognized string names
switch ($lexer) {
@@ -121,16 +123,24 @@ class HTMLPurifier_Lexer
$inst = new HTMLPurifier_Lexer_PH5P();
break;
default:
- throw new HTMLPurifier_Exception("Cannot instantiate unrecognized Lexer type " . htmlspecialchars($lexer));
+ throw new HTMLPurifier_Exception(
+ "Cannot instantiate unrecognized Lexer type " .
+ htmlspecialchars($lexer)
+ );
}
}
- if (!$inst) throw new HTMLPurifier_Exception('No lexer was instantiated');
+ if (!$inst) {
+ throw new HTMLPurifier_Exception('No lexer was instantiated');
+ }
// once PHP DOM implements native line numbers, or we
// hack out something using XSLT, remove this stipulation
if ($needs_tracking && !$inst->tracksLineNumbers) {
- throw new HTMLPurifier_Exception('Cannot use lexer that does not support line numbers with Core.MaintainLineNumbers or Core.CollectErrors (use DirectLex instead)');
+ throw new HTMLPurifier_Exception(
+ 'Cannot use lexer that does not support line numbers with ' .
+ 'Core.MaintainLineNumbers or Core.CollectErrors (use DirectLex instead)'
+ );
}
return $inst;
@@ -139,23 +149,25 @@ class HTMLPurifier_Lexer
// -- CONVENIENCE MEMBERS ---------------------------------------------
- public function __construct() {
+ public function __construct()
+ {
$this->_entity_parser = new HTMLPurifier_EntityParser();
}
/**
* Most common entity to raw value conversion table for special entities.
+ * @type array
*/
protected $_special_entity2str =
- array(
- '&quot;' => '"',
- '&amp;' => '&',
- '&lt;' => '<',
- '&gt;' => '>',
- '&#39;' => "'",
- '&#039;' => "'",
- '&#x27;' => "'"
- );
+ array(
+ '&quot;' => '"',
+ '&amp;' => '&',
+ '&lt;' => '<',
+ '&gt;' => '>',
+ '&#39;' => "'",
+ '&#039;' => "'",
+ '&#x27;' => "'"
+ );
/**
* Parses special entities into the proper characters.
@@ -168,27 +180,33 @@ class HTMLPurifier_Lexer
* completely parsed, but that's only because all other entities should
* have been handled previously in substituteNonSpecialEntities()
*
- * @param $string String character data to be parsed.
- * @returns Parsed character data.
+ * @param string $string String character data to be parsed.
+ * @return string Parsed character data.
*/
- public function parseData($string) {
-
+ public function parseData($string)
+ {
// following functions require at least one character
- if ($string === '') return '';
+ if ($string === '') {
+ return '';
+ }
// subtracts amps that cannot possibly be escaped
$num_amp = substr_count($string, '&') - substr_count($string, '& ') -
- ($string[strlen($string)-1] === '&' ? 1 : 0);
+ ($string[strlen($string) - 1] === '&' ? 1 : 0);
- if (!$num_amp) return $string; // abort if no entities
+ if (!$num_amp) {
+ return $string;
+ } // abort if no entities
$num_esc_amp = substr_count($string, '&amp;');
$string = strtr($string, $this->_special_entity2str);
// code duplication for sake of optimization, see above
$num_amp_2 = substr_count($string, '&') - substr_count($string, '& ') -
- ($string[strlen($string)-1] === '&' ? 1 : 0);
+ ($string[strlen($string) - 1] === '&' ? 1 : 0);
- if ($num_amp_2 <= $num_esc_amp) return $string;
+ if ($num_amp_2 <= $num_esc_amp) {
+ return $string;
+ }
// hmm... now we have some uncommon entities. Use the callback.
$string = $this->_entity_parser->substituteSpecialEntities($string);
@@ -197,21 +215,23 @@ class HTMLPurifier_Lexer
/**
* Lexes an HTML string into tokens.
- *
* @param $string String HTML.
- * @return HTMLPurifier_Token array representation of HTML.
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_Token[] array representation of HTML.
*/
- public function tokenizeHTML($string, $config, $context) {
+ public function tokenizeHTML($string, $config, $context)
+ {
trigger_error('Call to abstract class', E_USER_ERROR);
}
/**
* Translates CDATA sections into regular sections (through escaping).
- *
- * @param $string HTML string to process.
- * @returns HTML with CDATA sections escaped.
+ * @param string $string HTML string to process.
+ * @return string HTML with CDATA sections escaped.
*/
- protected static function escapeCDATA($string) {
+ protected static function escapeCDATA($string)
+ {
return preg_replace_callback(
'/<!\[CDATA\[(.+?)\]\]>/s',
array('HTMLPurifier_Lexer', 'CDATACallback'),
@@ -221,8 +241,11 @@ class HTMLPurifier_Lexer
/**
* Special CDATA case that is especially convoluted for <script>
+ * @param string $string HTML string to process.
+ * @return string HTML with CDATA sections escaped.
*/
- protected static function escapeCommentedCDATA($string) {
+ protected static function escapeCommentedCDATA($string)
+ {
return preg_replace_callback(
'#<!--//--><!\[CDATA\[//><!--(.+?)//--><!\]\]>#s',
array('HTMLPurifier_Lexer', 'CDATACallback'),
@@ -231,15 +254,30 @@ class HTMLPurifier_Lexer
}
/**
+ * Special Internet Explorer conditional comments should be removed.
+ * @param string $string HTML string to process.
+ * @return string HTML with conditional comments removed.
+ */
+ protected static function removeIEConditional($string)
+ {
+ return preg_replace(
+ '#<!--\[if [^>]+\]>.*?<!\[endif\]-->#si', // probably should generalize for all strings
+ '',
+ $string
+ );
+ }
+
+ /**
* Callback function for escapeCDATA() that does the work.
*
* @warning Though this is public in order to let the callback happen,
* calling it directly is not recommended.
- * @params $matches PCRE matches array, with index 0 the entire match
+ * @param array $matches PCRE matches array, with index 0 the entire match
* and 1 the inside of the CDATA section.
- * @returns Escaped internals of the CDATA section.
+ * @return string Escaped internals of the CDATA section.
*/
- protected static function CDATACallback($matches) {
+ protected static function CDATACallback($matches)
+ {
// not exactly sure why the character set is needed, but whatever
return htmlspecialchars($matches[1], ENT_COMPAT, 'UTF-8');
}
@@ -247,13 +285,19 @@ class HTMLPurifier_Lexer
/**
* Takes a piece of HTML and normalizes it by converting entities, fixing
* encoding, extracting bits, and other good stuff.
+ * @param string $html HTML.
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
* @todo Consider making protected
*/
- public function normalize($html, $config, $context) {
-
+ public function normalize($html, $config, $context)
+ {
// normalize newlines to \n
- $html = str_replace("\r\n", "\n", $html);
- $html = str_replace("\r", "\n", $html);
+ if ($config->get('Core.NormalizeNewlines')) {
+ $html = str_replace("\r\n", "\n", $html);
+ $html = str_replace("\r", "\n", $html);
+ }
if ($config->get('HTML.Trusted')) {
// escape convoluted CDATA
@@ -263,6 +307,8 @@ class HTMLPurifier_Lexer
// escape CDATA
$html = $this->escapeCDATA($html);
+ $html = $this->removeIEConditional($html);
+
// extract body from document if applicable
if ($config->get('Core.ConvertDocumentToFragment')) {
$e = false;
@@ -284,6 +330,11 @@ class HTMLPurifier_Lexer
// represent non-SGML characters (horror, horror!)
$html = HTMLPurifier_Encoder::cleanUTF8($html);
+ // if processing instructions are to removed, remove them now
+ if ($config->get('Core.RemoveProcessingInstructions')) {
+ $html = preg_replace('#<\?.+?\?>#s', '', $html);
+ }
+
return $html;
}
@@ -291,7 +342,8 @@ class HTMLPurifier_Lexer
* Takes a string of HTML (fragment or document) and returns the content
* @todo Consider making protected
*/
- public function extractBody($html) {
+ public function extractBody($html)
+ {
$matches = array();
$result = preg_match('!<body[^>]*>(.*)</body>!is', $html, $matches);
if ($result) {
@@ -300,7 +352,6 @@ class HTMLPurifier_Lexer
return $html;
}
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Lexer/DOMLex.php b/library/HTMLPurifier/Lexer/DOMLex.php
index 20dc2ed48..720754454 100644
--- a/library/HTMLPurifier/Lexer/DOMLex.php
+++ b/library/HTMLPurifier/Lexer/DOMLex.php
@@ -27,16 +27,26 @@
class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
{
+ /**
+ * @type HTMLPurifier_TokenFactory
+ */
private $factory;
- public function __construct() {
+ public function __construct()
+ {
// setup the factory
parent::__construct();
$this->factory = new HTMLPurifier_TokenFactory();
}
- public function tokenizeHTML($html, $config, $context) {
-
+ /**
+ * @param string $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_Token[]
+ */
+ public function tokenizeHTML($html, $config, $context)
+ {
$html = $this->normalize($html, $config, $context);
// attempt to armor stray angled brackets that cannot possibly
@@ -65,30 +75,67 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
$tokens = array();
$this->tokenizeDOM(
$doc->getElementsByTagName('html')->item(0)-> // <html>
- getElementsByTagName('body')->item(0)-> // <body>
- getElementsByTagName('div')->item(0) // <div>
- , $tokens);
+ getElementsByTagName('body')->item(0)-> // <body>
+ getElementsByTagName('div')->item(0), // <div>
+ $tokens
+ );
return $tokens;
}
/**
- * Recursive function that tokenizes a node, putting it into an accumulator.
- *
- * @param $node DOMNode to be tokenized.
- * @param $tokens Array-list of already tokenized tokens.
- * @param $collect Says whether or start and close are collected, set to
- * false at first recursion because it's the implicit DIV
- * tag you're dealing with.
- * @returns Tokens of node appended to previously passed tokens.
+ * Iterative function that tokenizes a node, putting it into an accumulator.
+ * To iterate is human, to recurse divine - L. Peter Deutsch
+ * @param DOMNode $node DOMNode to be tokenized.
+ * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens.
+ * @return HTMLPurifier_Token of node appended to previously passed tokens.
*/
- protected function tokenizeDOM($node, &$tokens, $collect = false) {
+ protected function tokenizeDOM($node, &$tokens)
+ {
+ $level = 0;
+ $nodes = array($level => new HTMLPurifier_Queue(array($node)));
+ $closingNodes = array();
+ do {
+ while (!$nodes[$level]->isEmpty()) {
+ $node = $nodes[$level]->shift(); // FIFO
+ $collect = $level > 0 ? true : false;
+ $needEndingTag = $this->createStartNode($node, $tokens, $collect);
+ if ($needEndingTag) {
+ $closingNodes[$level][] = $node;
+ }
+ if ($node->childNodes && $node->childNodes->length) {
+ $level++;
+ $nodes[$level] = new HTMLPurifier_Queue();
+ foreach ($node->childNodes as $childNode) {
+ $nodes[$level]->push($childNode);
+ }
+ }
+ }
+ $level--;
+ if ($level && isset($closingNodes[$level])) {
+ while ($node = array_pop($closingNodes[$level])) {
+ $this->createEndNode($node, $tokens);
+ }
+ }
+ } while ($level > 0);
+ }
+ /**
+ * @param DOMNode $node DOMNode to be tokenized.
+ * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens.
+ * @param bool $collect Says whether or start and close are collected, set to
+ * false at first recursion because it's the implicit DIV
+ * tag you're dealing with.
+ * @return bool if the token needs an endtoken
+ * @todo data and tagName properties don't seem to exist in DOMNode?
+ */
+ protected function createStartNode($node, &$tokens, $collect)
+ {
// intercept non element nodes. WE MUST catch all of them,
// but we're not getting the character reference nodes because
// those should have been preprocessed
if ($node->nodeType === XML_TEXT_NODE) {
$tokens[] = $this->factory->createText($node->data);
- return;
+ return false;
} elseif ($node->nodeType === XML_CDATA_SECTION_NODE) {
// undo libxml's special treatment of <script> and <style> tags
$last = end($tokens);
@@ -106,59 +153,61 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
}
}
$tokens[] = $this->factory->createText($this->parseData($data));
- return;
+ return false;
} elseif ($node->nodeType === XML_COMMENT_NODE) {
// this is code is only invoked for comments in script/style in versions
// of libxml pre-2.6.28 (regular comments, of course, are still
// handled regularly)
$tokens[] = $this->factory->createComment($node->data);
- return;
- } elseif (
+ return false;
+ } elseif ($node->nodeType !== XML_ELEMENT_NODE) {
// not-well tested: there may be other nodes we have to grab
- $node->nodeType !== XML_ELEMENT_NODE
- ) {
- return;
+ return false;
}
- $attr = $node->hasAttributes() ?
- $this->transformAttrToAssoc($node->attributes) :
- array();
+ $attr = $node->hasAttributes() ? $this->transformAttrToAssoc($node->attributes) : array();
// We still have to make sure that the element actually IS empty
if (!$node->childNodes->length) {
if ($collect) {
$tokens[] = $this->factory->createEmpty($node->tagName, $attr);
}
+ return false;
} else {
- if ($collect) { // don't wrap on first iteration
+ if ($collect) {
$tokens[] = $this->factory->createStart(
$tag_name = $node->tagName, // somehow, it get's dropped
$attr
);
}
- foreach ($node->childNodes as $node) {
- // remember, it's an accumulator. Otherwise, we'd have
- // to use array_merge
- $this->tokenizeDOM($node, $tokens, true);
- }
- if ($collect) {
- $tokens[] = $this->factory->createEnd($tag_name);
- }
+ return true;
}
+ }
+ /**
+ * @param DOMNode $node
+ * @param HTMLPurifier_Token[] $tokens
+ */
+ protected function createEndNode($node, &$tokens)
+ {
+ $tokens[] = $this->factory->createEnd($node->tagName);
}
+
/**
* Converts a DOMNamedNodeMap of DOMAttr objects into an assoc array.
*
- * @param $attribute_list DOMNamedNodeMap of DOMAttr objects.
- * @returns Associative array of attributes.
+ * @param DOMNamedNodeMap $node_map DOMNamedNodeMap of DOMAttr objects.
+ * @return array Associative array of attributes.
*/
- protected function transformAttrToAssoc($node_map) {
+ protected function transformAttrToAssoc($node_map)
+ {
// NamedNodeMap is documented very well, so we're using undocumented
// features, namely, the fact that it implements Iterator and
// has a ->length attribute
- if ($node_map->length === 0) return array();
+ if ($node_map->length === 0) {
+ return array();
+ }
$array = array();
foreach ($node_map as $attr) {
$array[$attr->name] = $attr->value;
@@ -168,46 +217,64 @@ class HTMLPurifier_Lexer_DOMLex extends HTMLPurifier_Lexer
/**
* An error handler that mutes all errors
+ * @param int $errno
+ * @param string $errstr
*/
- public function muteErrorHandler($errno, $errstr) {}
+ public function muteErrorHandler($errno, $errstr)
+ {
+ }
/**
* Callback function for undoing escaping of stray angled brackets
* in comments
+ * @param array $matches
+ * @return string
*/
- public function callbackUndoCommentSubst($matches) {
- return '<!--' . strtr($matches[1], array('&amp;'=>'&','&lt;'=>'<')) . $matches[2];
+ public function callbackUndoCommentSubst($matches)
+ {
+ return '<!--' . strtr($matches[1], array('&amp;' => '&', '&lt;' => '<')) . $matches[2];
}
/**
* Callback function that entity-izes ampersands in comments so that
* callbackUndoCommentSubst doesn't clobber them
+ * @param array $matches
+ * @return string
*/
- public function callbackArmorCommentEntities($matches) {
+ public function callbackArmorCommentEntities($matches)
+ {
return '<!--' . str_replace('&', '&amp;', $matches[1]) . $matches[2];
}
/**
* Wraps an HTML fragment in the necessary HTML
+ * @param string $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
*/
- protected function wrapHTML($html, $config, $context) {
+ protected function wrapHTML($html, $config, $context)
+ {
$def = $config->getDefinition('HTML');
$ret = '';
if (!empty($def->doctype->dtdPublic) || !empty($def->doctype->dtdSystem)) {
$ret .= '<!DOCTYPE html ';
- if (!empty($def->doctype->dtdPublic)) $ret .= 'PUBLIC "' . $def->doctype->dtdPublic . '" ';
- if (!empty($def->doctype->dtdSystem)) $ret .= '"' . $def->doctype->dtdSystem . '" ';
+ if (!empty($def->doctype->dtdPublic)) {
+ $ret .= 'PUBLIC "' . $def->doctype->dtdPublic . '" ';
+ }
+ if (!empty($def->doctype->dtdSystem)) {
+ $ret .= '"' . $def->doctype->dtdSystem . '" ';
+ }
$ret .= '>';
}
$ret .= '<html><head>';
$ret .= '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
// No protection if $html contains a stray </div>!
- $ret .= '</head><body><div>'.$html.'</div></body></html>';
+ $ret .= '</head><body><div>' . $html . '</div></body></html>';
return $ret;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Lexer/DirectLex.php b/library/HTMLPurifier/Lexer/DirectLex.php
index 456e6e190..746b6e315 100644
--- a/library/HTMLPurifier/Lexer/DirectLex.php
+++ b/library/HTMLPurifier/Lexer/DirectLex.php
@@ -12,30 +12,44 @@
*/
class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
{
-
+ /**
+ * @type bool
+ */
public $tracksLineNumbers = true;
/**
* Whitespace characters for str(c)spn.
+ * @type string
*/
protected $_whitespace = "\x20\x09\x0D\x0A";
/**
* Callback function for script CDATA fudge
- * @param $matches, in form of array(opening tag, contents, closing tag)
+ * @param array $matches, in form of array(opening tag, contents, closing tag)
+ * @return string
*/
- protected function scriptCallback($matches) {
+ protected function scriptCallback($matches)
+ {
return $matches[1] . htmlspecialchars($matches[2], ENT_COMPAT, 'UTF-8') . $matches[3];
}
- public function tokenizeHTML($html, $config, $context) {
-
+ /**
+ * @param String $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array|HTMLPurifier_Token[]
+ */
+ public function tokenizeHTML($html, $config, $context)
+ {
// special normalization for script tags without any armor
// our "armor" heurstic is a < sign any number of whitespaces after
// the first script tag
if ($config->get('HTML.Trusted')) {
- $html = preg_replace_callback('#(<script[^>]*>)(\s*[^<].+?)(</script>)#si',
- array($this, 'scriptCallback'), $html);
+ $html = preg_replace_callback(
+ '#(<script[^>]*>)(\s*[^<].+?)(</script>)#si',
+ array($this, 'scriptCallback'),
+ $html
+ );
}
$html = $this->normalize($html, $config, $context);
@@ -55,15 +69,15 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
if ($maintain_line_numbers) {
$current_line = 1;
- $current_col = 0;
+ $current_col = 0;
$length = strlen($html);
} else {
$current_line = false;
- $current_col = false;
+ $current_col = false;
$length = false;
}
$context->register('CurrentLine', $current_line);
- $context->register('CurrentCol', $current_col);
+ $context->register('CurrentCol', $current_col);
$nl = "\n";
// how often to manually recalculate. This will ALWAYS be right,
// but it's pretty wasteful. Set to 0 to turn off
@@ -77,16 +91,14 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
// for testing synchronization
$loops = 0;
- while(++$loops) {
-
+ while (++$loops) {
// $cursor is either at the start of a token, or inside of
// a tag (i.e. there was a < immediately before it), as indicated
// by $inside_tag
if ($maintain_line_numbers) {
-
// $rcursor, however, is always at the start of a token.
- $rcursor = $cursor - (int) $inside_tag;
+ $rcursor = $cursor - (int)$inside_tag;
// Column number is cheap, so we calculate it every round.
// We're interested at the *end* of the newline string, so
@@ -96,14 +108,11 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
$current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1);
// recalculate lines
- if (
- $synchronize_interval && // synchronization is on
- $cursor > 0 && // cursor is further than zero
- $loops % $synchronize_interval === 0 // time to synchronize!
- ) {
+ if ($synchronize_interval && // synchronization is on
+ $cursor > 0 && // cursor is further than zero
+ $loops % $synchronize_interval === 0) { // time to synchronize!
$current_line = 1 + $this->substrCount($html, $nl, 0, $cursor);
}
-
}
$position_next_lt = strpos($html, '<', $cursor);
@@ -119,35 +128,42 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
if (!$inside_tag && $position_next_lt !== false) {
// We are not inside tag and there still is another tag to parse
$token = new
- HTMLPurifier_Token_Text(
- $this->parseData(
- substr(
- $html, $cursor, $position_next_lt - $cursor
- )
+ HTMLPurifier_Token_Text(
+ $this->parseData(
+ substr(
+ $html,
+ $cursor,
+ $position_next_lt - $cursor
)
- );
+ )
+ );
if ($maintain_line_numbers) {
$token->rawPosition($current_line, $current_col);
$current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor);
}
$array[] = $token;
- $cursor = $position_next_lt + 1;
+ $cursor = $position_next_lt + 1;
$inside_tag = true;
continue;
} elseif (!$inside_tag) {
// We are not inside tag but there are no more tags
// If we're already at the end, break
- if ($cursor === strlen($html)) break;
+ if ($cursor === strlen($html)) {
+ break;
+ }
// Create Text of rest of string
$token = new
- HTMLPurifier_Token_Text(
- $this->parseData(
- substr(
- $html, $cursor
- )
+ HTMLPurifier_Token_Text(
+ $this->parseData(
+ substr(
+ $html,
+ $cursor
)
- );
- if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col);
+ )
+ );
+ if ($maintain_line_numbers) {
+ $token->rawPosition($current_line, $current_col);
+ }
$array[] = $token;
break;
} elseif ($inside_tag && $position_next_gt !== false) {
@@ -171,16 +187,16 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
}
// Check if it's a comment
- if (
- substr($segment, 0, 3) === '!--'
- ) {
+ if (substr($segment, 0, 3) === '!--') {
// re-determine segment length, looking for -->
$position_comment_end = strpos($html, '-->', $cursor);
if ($position_comment_end === false) {
// uh oh, we have a comment that extends to
// infinity. Can't be helped: set comment
// end position to end of string
- if ($e) $e->send(E_WARNING, 'Lexer: Unclosed comment');
+ if ($e) {
+ $e->send(E_WARNING, 'Lexer: Unclosed comment');
+ }
$position_comment_end = strlen($html);
$end = true;
} else {
@@ -189,11 +205,13 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
$strlen_segment = $position_comment_end - $cursor;
$segment = substr($html, $cursor, $strlen_segment);
$token = new
- HTMLPurifier_Token_Comment(
- substr(
- $segment, 3, $strlen_segment - 3
- )
- );
+ HTMLPurifier_Token_Comment(
+ substr(
+ $segment,
+ 3,
+ $strlen_segment - 3
+ )
+ );
if ($maintain_line_numbers) {
$token->rawPosition($current_line, $current_col);
$current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment);
@@ -205,7 +223,7 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
}
// Check if it's an end tag
- $is_end_tag = (strpos($segment,'/') === 0);
+ $is_end_tag = (strpos($segment, '/') === 0);
if ($is_end_tag) {
$type = substr($segment, 1);
$token = new HTMLPurifier_Token_End($type);
@@ -224,7 +242,9 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
// text and go our merry way
if (!ctype_alpha($segment[0])) {
// XML: $segment[0] !== '_' && $segment[0] !== ':'
- if ($e) $e->send(E_NOTICE, 'Lexer: Unescaped lt');
+ if ($e) {
+ $e->send(E_NOTICE, 'Lexer: Unescaped lt');
+ }
$token = new HTMLPurifier_Token_Text('<');
if ($maintain_line_numbers) {
$token->rawPosition($current_line, $current_col);
@@ -239,7 +259,7 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
// trailing slash. Remember, we could have a tag like <br>, so
// any later token processing scripts must convert improperly
// classified EmptyTags from StartTags.
- $is_self_closing = (strrpos($segment,'/') === $strlen_segment-1);
+ $is_self_closing = (strrpos($segment, '/') === $strlen_segment - 1);
if ($is_self_closing) {
$strlen_segment--;
$segment = substr($segment, 0, $strlen_segment);
@@ -269,14 +289,16 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
$attribute_string =
trim(
substr(
- $segment, $position_first_space
+ $segment,
+ $position_first_space
)
);
if ($attribute_string) {
$attr = $this->parseAttributeString(
- $attribute_string
- , $config, $context
- );
+ $attribute_string,
+ $config,
+ $context
+ );
} else {
$attr = array();
}
@@ -296,15 +318,19 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
continue;
} else {
// inside tag, but there's no ending > sign
- if ($e) $e->send(E_WARNING, 'Lexer: Missing gt');
+ if ($e) {
+ $e->send(E_WARNING, 'Lexer: Missing gt');
+ }
$token = new
- HTMLPurifier_Token_Text(
- '<' .
- $this->parseData(
- substr($html, $cursor)
- )
- );
- if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col);
+ HTMLPurifier_Token_Text(
+ '<' .
+ $this->parseData(
+ substr($html, $cursor)
+ )
+ );
+ if ($maintain_line_numbers) {
+ $token->rawPosition($current_line, $current_col);
+ }
// no cursor scroll? Hmm...
$array[] = $token;
break;
@@ -319,8 +345,14 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
/**
* PHP 5.0.x compatible substr_count that implements offset and length
+ * @param string $haystack
+ * @param string $needle
+ * @param int $offset
+ * @param int $length
+ * @return int
*/
- protected function substrCount($haystack, $needle, $offset, $length) {
+ protected function substrCount($haystack, $needle, $offset, $length)
+ {
static $oldVersion;
if ($oldVersion === null) {
$oldVersion = version_compare(PHP_VERSION, '5.1', '<');
@@ -336,13 +368,18 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
/**
* Takes the inside of an HTML tag and makes an assoc array of attributes.
*
- * @param $string Inside of tag excluding name.
- * @returns Assoc array of attributes.
+ * @param string $string Inside of tag excluding name.
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array Assoc array of attributes.
*/
- public function parseAttributeString($string, $config, $context) {
- $string = (string) $string; // quick typecast
+ public function parseAttributeString($string, $config, $context)
+ {
+ $string = (string)$string; // quick typecast
- if ($string == '') return array(); // no attributes
+ if ($string == '') {
+ return array();
+ } // no attributes
$e = false;
if ($config->get('Core.CollectErrors')) {
@@ -361,46 +398,55 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
list($key, $quoted_value) = explode('=', $string);
$quoted_value = trim($quoted_value);
if (!$key) {
- if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key');
+ if ($e) {
+ $e->send(E_ERROR, 'Lexer: Missing attribute key');
+ }
return array();
}
- if (!$quoted_value) return array($key => '');
+ if (!$quoted_value) {
+ return array($key => '');
+ }
$first_char = @$quoted_value[0];
- $last_char = @$quoted_value[strlen($quoted_value)-1];
+ $last_char = @$quoted_value[strlen($quoted_value) - 1];
$same_quote = ($first_char == $last_char);
$open_quote = ($first_char == '"' || $first_char == "'");
- if ( $same_quote && $open_quote) {
+ if ($same_quote && $open_quote) {
// well behaved
$value = substr($quoted_value, 1, strlen($quoted_value) - 2);
} else {
// not well behaved
if ($open_quote) {
- if ($e) $e->send(E_ERROR, 'Lexer: Missing end quote');
+ if ($e) {
+ $e->send(E_ERROR, 'Lexer: Missing end quote');
+ }
$value = substr($quoted_value, 1);
} else {
$value = $quoted_value;
}
}
- if ($value === false) $value = '';
+ if ($value === false) {
+ $value = '';
+ }
return array($key => $this->parseData($value));
}
// setup loop environment
- $array = array(); // return assoc array of attributes
+ $array = array(); // return assoc array of attributes
$cursor = 0; // current position in string (moves forward)
- $size = strlen($string); // size of the string (stays the same)
+ $size = strlen($string); // size of the string (stays the same)
// if we have unquoted attributes, the parser expects a terminating
// space, so let's guarantee that there's always a terminating space.
$string .= ' ';
- while(true) {
-
- if ($cursor >= $size) {
- break;
+ $old_cursor = -1;
+ while ($cursor < $size) {
+ if ($old_cursor >= $cursor) {
+ throw new Exception("Infinite loop detected");
}
+ $old_cursor = $cursor;
$cursor += ($value = strspn($string, $this->_whitespace, $cursor));
// grab the key
@@ -415,8 +461,10 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
$key = substr($string, $key_begin, $key_end - $key_begin);
if (!$key) {
- if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key');
- $cursor += strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop
+ if ($e) {
+ $e->send(E_ERROR, 'Lexer: Missing attribute key');
+ }
+ $cursor += 1 + strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop
continue; // empty key
}
@@ -467,24 +515,25 @@ class HTMLPurifier_Lexer_DirectLex extends HTMLPurifier_Lexer
}
$value = substr($string, $value_begin, $value_end - $value_begin);
- if ($value === false) $value = '';
+ if ($value === false) {
+ $value = '';
+ }
$array[$key] = $this->parseData($value);
$cursor++;
-
} else {
// boolattr
if ($key !== '') {
$array[$key] = $key;
} else {
// purely theoretical
- if ($e) $e->send(E_ERROR, 'Lexer: Missing attribute key');
+ if ($e) {
+ $e->send(E_ERROR, 'Lexer: Missing attribute key');
+ }
}
-
}
}
return $array;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Lexer/PEARSax3.php b/library/HTMLPurifier/Lexer/PEARSax3.php
deleted file mode 100644
index 1d358c7b6..000000000
--- a/library/HTMLPurifier/Lexer/PEARSax3.php
+++ /dev/null
@@ -1,139 +0,0 @@
-<?php
-
-/**
- * Proof-of-concept lexer that uses the PEAR package XML_HTMLSax3 to parse HTML.
- *
- * PEAR, not suprisingly, also has a SAX parser for HTML. I don't know
- * very much about implementation, but it's fairly well written. However, that
- * abstraction comes at a price: performance. You need to have it installed,
- * and if the API changes, it might break our adapter. Not sure whether or not
- * it's UTF-8 aware, but it has some entity parsing trouble (in all areas,
- * text and attributes).
- *
- * Quite personally, I don't recommend using the PEAR class, and the defaults
- * don't use it. The unit tests do perform the tests on the SAX parser too, but
- * whatever it does for poorly formed HTML is up to it.
- *
- * @todo Generalize so that XML_HTMLSax is also supported.
- *
- * @warning Entity-resolution inside attributes is broken.
- */
-
-class HTMLPurifier_Lexer_PEARSax3 extends HTMLPurifier_Lexer
-{
-
- /**
- * Internal accumulator array for SAX parsers.
- */
- protected $tokens = array();
- protected $last_token_was_empty;
-
- private $parent_handler;
- private $stack = array();
-
- public function tokenizeHTML($string, $config, $context) {
-
- $this->tokens = array();
- $this->last_token_was_empty = false;
-
- $string = $this->normalize($string, $config, $context);
-
- $this->parent_handler = set_error_handler(array($this, 'muteStrictErrorHandler'));
-
- $parser = new XML_HTMLSax3();
- $parser->set_object($this);
- $parser->set_element_handler('openHandler','closeHandler');
- $parser->set_data_handler('dataHandler');
- $parser->set_escape_handler('escapeHandler');
-
- // doesn't seem to work correctly for attributes
- $parser->set_option('XML_OPTION_ENTITIES_PARSED', 1);
-
- $parser->parse($string);
-
- restore_error_handler();
-
- return $this->tokens;
-
- }
-
- /**
- * Open tag event handler, interface is defined by PEAR package.
- */
- public function openHandler(&$parser, $name, $attrs, $closed) {
- // entities are not resolved in attrs
- foreach ($attrs as $key => $attr) {
- $attrs[$key] = $this->parseData($attr);
- }
- if ($closed) {
- $this->tokens[] = new HTMLPurifier_Token_Empty($name, $attrs);
- $this->last_token_was_empty = true;
- } else {
- $this->tokens[] = new HTMLPurifier_Token_Start($name, $attrs);
- }
- $this->stack[] = $name;
- return true;
- }
-
- /**
- * Close tag event handler, interface is defined by PEAR package.
- */
- public function closeHandler(&$parser, $name) {
- // HTMLSax3 seems to always send empty tags an extra close tag
- // check and ignore if you see it:
- // [TESTME] to make sure it doesn't overreach
- if ($this->last_token_was_empty) {
- $this->last_token_was_empty = false;
- return true;
- }
- $this->tokens[] = new HTMLPurifier_Token_End($name);
- if (!empty($this->stack)) array_pop($this->stack);
- return true;
- }
-
- /**
- * Data event handler, interface is defined by PEAR package.
- */
- public function dataHandler(&$parser, $data) {
- $this->last_token_was_empty = false;
- $this->tokens[] = new HTMLPurifier_Token_Text($data);
- return true;
- }
-
- /**
- * Escaped text handler, interface is defined by PEAR package.
- */
- public function escapeHandler(&$parser, $data) {
- if (strpos($data, '--') === 0) {
- // remove trailing and leading double-dashes
- $data = substr($data, 2);
- if (strlen($data) >= 2 && substr($data, -2) == "--") {
- $data = substr($data, 0, -2);
- }
- if (isset($this->stack[sizeof($this->stack) - 1]) &&
- $this->stack[sizeof($this->stack) - 1] == "style") {
- $this->tokens[] = new HTMLPurifier_Token_Text($data);
- } else {
- $this->tokens[] = new HTMLPurifier_Token_Comment($data);
- }
- $this->last_token_was_empty = false;
- }
- // CDATA is handled elsewhere, but if it was handled here:
- //if (strpos($data, '[CDATA[') === 0) {
- // $this->tokens[] = new HTMLPurifier_Token_Text(
- // substr($data, 7, strlen($data) - 9) );
- //}
- return true;
- }
-
- /**
- * An error handler that mutes strict errors
- */
- public function muteStrictErrorHandler($errno, $errstr, $errfile=null, $errline=null, $errcontext=null) {
- if ($errno == E_STRICT) return;
- return call_user_func($this->parent_handler, $errno, $errstr, $errfile, $errline, $errcontext);
- }
-
-}
-
-// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Lexer/PH5P.php b/library/HTMLPurifier/Lexer/PH5P.php
index fa1bf973e..a4587e4cd 100644
--- a/library/HTMLPurifier/Lexer/PH5P.php
+++ b/library/HTMLPurifier/Lexer/PH5P.php
@@ -3,16 +3,23 @@
/**
* Experimental HTML5-based parser using Jeroen van der Meer's PH5P library.
* Occupies space in the HTML5 pseudo-namespace, which may cause conflicts.
- *
+ *
* @note
* Recent changes to PHP's DOM extension have resulted in some fatal
* error conditions with the original version of PH5P. Pending changes,
- * this lexer will punt to DirectLex if DOM throughs an exception.
+ * this lexer will punt to DirectLex if DOM throws an exception.
*/
-class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex {
-
- public function tokenizeHTML($html, $config, $context) {
+class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex
+{
+ /**
+ * @param string $html
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_Token[]
+ */
+ public function tokenizeHTML($html, $config, $context)
+ {
$new_html = $this->normalize($html, $config, $context);
$new_html = $this->wrapHTML($new_html, $config, $context);
try {
@@ -27,40 +34,42 @@ class HTMLPurifier_Lexer_PH5P extends HTMLPurifier_Lexer_DOMLex {
$tokens = array();
$this->tokenizeDOM(
$doc->getElementsByTagName('html')->item(0)-> // <html>
- getElementsByTagName('body')->item(0)-> // <body>
- getElementsByTagName('div')->item(0) // <div>
- , $tokens);
+ getElementsByTagName('body')->item(0)-> // <body>
+ getElementsByTagName('div')->item(0) // <div>
+ ,
+ $tokens
+ );
return $tokens;
}
-
}
/*
-Copyright 2007 Jeroen van der Meer <http://jero.net/>
+Copyright 2007 Jeroen van der Meer <http://jero.net/>
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-class HTML5 {
+class HTML5
+{
private $data;
private $char;
private $EOF;
@@ -69,91 +78,418 @@ class HTML5 {
private $token;
private $content_model;
private $escape = false;
- private $entities = array('AElig;','AElig','AMP;','AMP','Aacute;','Aacute',
- 'Acirc;','Acirc','Agrave;','Agrave','Alpha;','Aring;','Aring','Atilde;',
- 'Atilde','Auml;','Auml','Beta;','COPY;','COPY','Ccedil;','Ccedil','Chi;',
- 'Dagger;','Delta;','ETH;','ETH','Eacute;','Eacute','Ecirc;','Ecirc','Egrave;',
- 'Egrave','Epsilon;','Eta;','Euml;','Euml','GT;','GT','Gamma;','Iacute;',
- 'Iacute','Icirc;','Icirc','Igrave;','Igrave','Iota;','Iuml;','Iuml','Kappa;',
- 'LT;','LT','Lambda;','Mu;','Ntilde;','Ntilde','Nu;','OElig;','Oacute;',
- 'Oacute','Ocirc;','Ocirc','Ograve;','Ograve','Omega;','Omicron;','Oslash;',
- 'Oslash','Otilde;','Otilde','Ouml;','Ouml','Phi;','Pi;','Prime;','Psi;',
- 'QUOT;','QUOT','REG;','REG','Rho;','Scaron;','Sigma;','THORN;','THORN',
- 'TRADE;','Tau;','Theta;','Uacute;','Uacute','Ucirc;','Ucirc','Ugrave;',
- 'Ugrave','Upsilon;','Uuml;','Uuml','Xi;','Yacute;','Yacute','Yuml;','Zeta;',
- 'aacute;','aacute','acirc;','acirc','acute;','acute','aelig;','aelig',
- 'agrave;','agrave','alefsym;','alpha;','amp;','amp','and;','ang;','apos;',
- 'aring;','aring','asymp;','atilde;','atilde','auml;','auml','bdquo;','beta;',
- 'brvbar;','brvbar','bull;','cap;','ccedil;','ccedil','cedil;','cedil',
- 'cent;','cent','chi;','circ;','clubs;','cong;','copy;','copy','crarr;',
- 'cup;','curren;','curren','dArr;','dagger;','darr;','deg;','deg','delta;',
- 'diams;','divide;','divide','eacute;','eacute','ecirc;','ecirc','egrave;',
- 'egrave','empty;','emsp;','ensp;','epsilon;','equiv;','eta;','eth;','eth',
- 'euml;','euml','euro;','exist;','fnof;','forall;','frac12;','frac12',
- 'frac14;','frac14','frac34;','frac34','frasl;','gamma;','ge;','gt;','gt',
- 'hArr;','harr;','hearts;','hellip;','iacute;','iacute','icirc;','icirc',
- 'iexcl;','iexcl','igrave;','igrave','image;','infin;','int;','iota;',
- 'iquest;','iquest','isin;','iuml;','iuml','kappa;','lArr;','lambda;','lang;',
- 'laquo;','laquo','larr;','lceil;','ldquo;','le;','lfloor;','lowast;','loz;',
- 'lrm;','lsaquo;','lsquo;','lt;','lt','macr;','macr','mdash;','micro;','micro',
- 'middot;','middot','minus;','mu;','nabla;','nbsp;','nbsp','ndash;','ne;',
- 'ni;','not;','not','notin;','nsub;','ntilde;','ntilde','nu;','oacute;',
- 'oacute','ocirc;','ocirc','oelig;','ograve;','ograve','oline;','omega;',
- 'omicron;','oplus;','or;','ordf;','ordf','ordm;','ordm','oslash;','oslash',
- 'otilde;','otilde','otimes;','ouml;','ouml','para;','para','part;','permil;',
- 'perp;','phi;','pi;','piv;','plusmn;','plusmn','pound;','pound','prime;',
- 'prod;','prop;','psi;','quot;','quot','rArr;','radic;','rang;','raquo;',
- 'raquo','rarr;','rceil;','rdquo;','real;','reg;','reg','rfloor;','rho;',
- 'rlm;','rsaquo;','rsquo;','sbquo;','scaron;','sdot;','sect;','sect','shy;',
- 'shy','sigma;','sigmaf;','sim;','spades;','sub;','sube;','sum;','sup1;',
- 'sup1','sup2;','sup2','sup3;','sup3','sup;','supe;','szlig;','szlig','tau;',
- 'there4;','theta;','thetasym;','thinsp;','thorn;','thorn','tilde;','times;',
- 'times','trade;','uArr;','uacute;','uacute','uarr;','ucirc;','ucirc',
- 'ugrave;','ugrave','uml;','uml','upsih;','upsilon;','uuml;','uuml','weierp;',
- 'xi;','yacute;','yacute','yen;','yen','yuml;','yuml','zeta;','zwj;','zwnj;');
-
- const PCDATA = 0;
- const RCDATA = 1;
- const CDATA = 2;
+ private $entities = array(
+ 'AElig;',
+ 'AElig',
+ 'AMP;',
+ 'AMP',
+ 'Aacute;',
+ 'Aacute',
+ 'Acirc;',
+ 'Acirc',
+ 'Agrave;',
+ 'Agrave',
+ 'Alpha;',
+ 'Aring;',
+ 'Aring',
+ 'Atilde;',
+ 'Atilde',
+ 'Auml;',
+ 'Auml',
+ 'Beta;',
+ 'COPY;',
+ 'COPY',
+ 'Ccedil;',
+ 'Ccedil',
+ 'Chi;',
+ 'Dagger;',
+ 'Delta;',
+ 'ETH;',
+ 'ETH',
+ 'Eacute;',
+ 'Eacute',
+ 'Ecirc;',
+ 'Ecirc',
+ 'Egrave;',
+ 'Egrave',
+ 'Epsilon;',
+ 'Eta;',
+ 'Euml;',
+ 'Euml',
+ 'GT;',
+ 'GT',
+ 'Gamma;',
+ 'Iacute;',
+ 'Iacute',
+ 'Icirc;',
+ 'Icirc',
+ 'Igrave;',
+ 'Igrave',
+ 'Iota;',
+ 'Iuml;',
+ 'Iuml',
+ 'Kappa;',
+ 'LT;',
+ 'LT',
+ 'Lambda;',
+ 'Mu;',
+ 'Ntilde;',
+ 'Ntilde',
+ 'Nu;',
+ 'OElig;',
+ 'Oacute;',
+ 'Oacute',
+ 'Ocirc;',
+ 'Ocirc',
+ 'Ograve;',
+ 'Ograve',
+ 'Omega;',
+ 'Omicron;',
+ 'Oslash;',
+ 'Oslash',
+ 'Otilde;',
+ 'Otilde',
+ 'Ouml;',
+ 'Ouml',
+ 'Phi;',
+ 'Pi;',
+ 'Prime;',
+ 'Psi;',
+ 'QUOT;',
+ 'QUOT',
+ 'REG;',
+ 'REG',
+ 'Rho;',
+ 'Scaron;',
+ 'Sigma;',
+ 'THORN;',
+ 'THORN',
+ 'TRADE;',
+ 'Tau;',
+ 'Theta;',
+ 'Uacute;',
+ 'Uacute',
+ 'Ucirc;',
+ 'Ucirc',
+ 'Ugrave;',
+ 'Ugrave',
+ 'Upsilon;',
+ 'Uuml;',
+ 'Uuml',
+ 'Xi;',
+ 'Yacute;',
+ 'Yacute',
+ 'Yuml;',
+ 'Zeta;',
+ 'aacute;',
+ 'aacute',
+ 'acirc;',
+ 'acirc',
+ 'acute;',
+ 'acute',
+ 'aelig;',
+ 'aelig',
+ 'agrave;',
+ 'agrave',
+ 'alefsym;',
+ 'alpha;',
+ 'amp;',
+ 'amp',
+ 'and;',
+ 'ang;',
+ 'apos;',
+ 'aring;',
+ 'aring',
+ 'asymp;',
+ 'atilde;',
+ 'atilde',
+ 'auml;',
+ 'auml',
+ 'bdquo;',
+ 'beta;',
+ 'brvbar;',
+ 'brvbar',
+ 'bull;',
+ 'cap;',
+ 'ccedil;',
+ 'ccedil',
+ 'cedil;',
+ 'cedil',
+ 'cent;',
+ 'cent',
+ 'chi;',
+ 'circ;',
+ 'clubs;',
+ 'cong;',
+ 'copy;',
+ 'copy',
+ 'crarr;',
+ 'cup;',
+ 'curren;',
+ 'curren',
+ 'dArr;',
+ 'dagger;',
+ 'darr;',
+ 'deg;',
+ 'deg',
+ 'delta;',
+ 'diams;',
+ 'divide;',
+ 'divide',
+ 'eacute;',
+ 'eacute',
+ 'ecirc;',
+ 'ecirc',
+ 'egrave;',
+ 'egrave',
+ 'empty;',
+ 'emsp;',
+ 'ensp;',
+ 'epsilon;',
+ 'equiv;',
+ 'eta;',
+ 'eth;',
+ 'eth',
+ 'euml;',
+ 'euml',
+ 'euro;',
+ 'exist;',
+ 'fnof;',
+ 'forall;',
+ 'frac12;',
+ 'frac12',
+ 'frac14;',
+ 'frac14',
+ 'frac34;',
+ 'frac34',
+ 'frasl;',
+ 'gamma;',
+ 'ge;',
+ 'gt;',
+ 'gt',
+ 'hArr;',
+ 'harr;',
+ 'hearts;',
+ 'hellip;',
+ 'iacute;',
+ 'iacute',
+ 'icirc;',
+ 'icirc',
+ 'iexcl;',
+ 'iexcl',
+ 'igrave;',
+ 'igrave',
+ 'image;',
+ 'infin;',
+ 'int;',
+ 'iota;',
+ 'iquest;',
+ 'iquest',
+ 'isin;',
+ 'iuml;',
+ 'iuml',
+ 'kappa;',
+ 'lArr;',
+ 'lambda;',
+ 'lang;',
+ 'laquo;',
+ 'laquo',
+ 'larr;',
+ 'lceil;',
+ 'ldquo;',
+ 'le;',
+ 'lfloor;',
+ 'lowast;',
+ 'loz;',
+ 'lrm;',
+ 'lsaquo;',
+ 'lsquo;',
+ 'lt;',
+ 'lt',
+ 'macr;',
+ 'macr',
+ 'mdash;',
+ 'micro;',
+ 'micro',
+ 'middot;',
+ 'middot',
+ 'minus;',
+ 'mu;',
+ 'nabla;',
+ 'nbsp;',
+ 'nbsp',
+ 'ndash;',
+ 'ne;',
+ 'ni;',
+ 'not;',
+ 'not',
+ 'notin;',
+ 'nsub;',
+ 'ntilde;',
+ 'ntilde',
+ 'nu;',
+ 'oacute;',
+ 'oacute',
+ 'ocirc;',
+ 'ocirc',
+ 'oelig;',
+ 'ograve;',
+ 'ograve',
+ 'oline;',
+ 'omega;',
+ 'omicron;',
+ 'oplus;',
+ 'or;',
+ 'ordf;',
+ 'ordf',
+ 'ordm;',
+ 'ordm',
+ 'oslash;',
+ 'oslash',
+ 'otilde;',
+ 'otilde',
+ 'otimes;',
+ 'ouml;',
+ 'ouml',
+ 'para;',
+ 'para',
+ 'part;',
+ 'permil;',
+ 'perp;',
+ 'phi;',
+ 'pi;',
+ 'piv;',
+ 'plusmn;',
+ 'plusmn',
+ 'pound;',
+ 'pound',
+ 'prime;',
+ 'prod;',
+ 'prop;',
+ 'psi;',
+ 'quot;',
+ 'quot',
+ 'rArr;',
+ 'radic;',
+ 'rang;',
+ 'raquo;',
+ 'raquo',
+ 'rarr;',
+ 'rceil;',
+ 'rdquo;',
+ 'real;',
+ 'reg;',
+ 'reg',
+ 'rfloor;',
+ 'rho;',
+ 'rlm;',
+ 'rsaquo;',
+ 'rsquo;',
+ 'sbquo;',
+ 'scaron;',
+ 'sdot;',
+ 'sect;',
+ 'sect',
+ 'shy;',
+ 'shy',
+ 'sigma;',
+ 'sigmaf;',
+ 'sim;',
+ 'spades;',
+ 'sub;',
+ 'sube;',
+ 'sum;',
+ 'sup1;',
+ 'sup1',
+ 'sup2;',
+ 'sup2',
+ 'sup3;',
+ 'sup3',
+ 'sup;',
+ 'supe;',
+ 'szlig;',
+ 'szlig',
+ 'tau;',
+ 'there4;',
+ 'theta;',
+ 'thetasym;',
+ 'thinsp;',
+ 'thorn;',
+ 'thorn',
+ 'tilde;',
+ 'times;',
+ 'times',
+ 'trade;',
+ 'uArr;',
+ 'uacute;',
+ 'uacute',
+ 'uarr;',
+ 'ucirc;',
+ 'ucirc',
+ 'ugrave;',
+ 'ugrave',
+ 'uml;',
+ 'uml',
+ 'upsih;',
+ 'upsilon;',
+ 'uuml;',
+ 'uuml',
+ 'weierp;',
+ 'xi;',
+ 'yacute;',
+ 'yacute',
+ 'yen;',
+ 'yen',
+ 'yuml;',
+ 'yuml',
+ 'zeta;',
+ 'zwj;',
+ 'zwnj;'
+ );
+
+ const PCDATA = 0;
+ const RCDATA = 1;
+ const CDATA = 2;
const PLAINTEXT = 3;
- const DOCTYPE = 0;
+ const DOCTYPE = 0;
const STARTTAG = 1;
- const ENDTAG = 2;
- const COMMENT = 3;
+ const ENDTAG = 2;
+ const COMMENT = 3;
const CHARACTR = 4;
- const EOF = 5;
-
- public function __construct($data) {
- $data = str_replace("\r\n", "\n", $data);
- $data = str_replace("\r", null, $data);
+ const EOF = 5;
+ public function __construct($data)
+ {
$this->data = $data;
$this->char = -1;
- $this->EOF = strlen($data);
+ $this->EOF = strlen($data);
$this->tree = new HTML5TreeConstructer;
$this->content_model = self::PCDATA;
$this->state = 'data';
- while($this->state !== null) {
- $this->{$this->state.'State'}();
+ while ($this->state !== null) {
+ $this->{$this->state . 'State'}();
}
}
- public function save() {
+ public function save()
+ {
return $this->tree->save();
}
- private function char() {
+ private function char()
+ {
return ($this->char < $this->EOF)
? $this->data[$this->char]
: false;
}
- private function character($s, $l = 0) {
- if($s + $l < $this->EOF) {
- if($l === 0) {
+ private function character($s, $l = 0)
+ {
+ if ($s + $l < $this->EOF) {
+ if ($l === 0) {
return $this->data[$s];
} else {
return substr($this->data, $s, $l);
@@ -161,46 +497,52 @@ class HTML5 {
}
}
- private function characters($char_class, $start) {
- return preg_replace('#^(['.$char_class.']+).*#s', '\\1', substr($this->data, $start));
+ private function characters($char_class, $start)
+ {
+ return preg_replace('#^([' . $char_class . ']+).*#s', '\\1', substr($this->data, $start));
}
- private function dataState() {
+ private function dataState()
+ {
// Consume the next input character
$this->char++;
$char = $this->char();
- if($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) {
+ if ($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) {
/* U+0026 AMPERSAND (&)
When the content model flag is set to one of the PCDATA or RCDATA
states: switch to the entity data state. Otherwise: treat it as per
the "anything else" entry below. */
$this->state = 'entityData';
- } elseif($char === '-') {
+ } elseif ($char === '-') {
/* If the content model flag is set to either the RCDATA state or
the CDATA state, and the escape flag is false, and there are at
least three characters before this one in the input stream, and the
last four characters in the input stream, including this one, are
U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS,
and U+002D HYPHEN-MINUS ("<!--"), then set the escape flag to true. */
- if(($this->content_model === self::RCDATA || $this->content_model ===
- self::CDATA) && $this->escape === false &&
- $this->char >= 3 && $this->character($this->char - 4, 4) === '<!--') {
+ if (($this->content_model === self::RCDATA || $this->content_model ===
+ self::CDATA) && $this->escape === false &&
+ $this->char >= 3 && $this->character($this->char - 4, 4) === '<!--'
+ ) {
$this->escape = true;
}
/* In any case, emit the input character as a character token. Stay
in the data state. */
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => $char
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => $char
+ )
+ );
- /* U+003C LESS-THAN SIGN (<) */
- } elseif($char === '<' && ($this->content_model === self::PCDATA ||
- (($this->content_model === self::RCDATA ||
- $this->content_model === self::CDATA) && $this->escape === false))) {
+ /* U+003C LESS-THAN SIGN (<) */
+ } elseif ($char === '<' && ($this->content_model === self::PCDATA ||
+ (($this->content_model === self::RCDATA ||
+ $this->content_model === self::CDATA) && $this->escape === false))
+ ) {
/* When the content model flag is set to the PCDATA state: switch
to the tag open state.
@@ -211,39 +553,44 @@ class HTML5 {
Otherwise: treat it as per the "anything else" entry below. */
$this->state = 'tagOpen';
- /* U+003E GREATER-THAN SIGN (>) */
- } elseif($char === '>') {
+ /* U+003E GREATER-THAN SIGN (>) */
+ } elseif ($char === '>') {
/* If the content model flag is set to either the RCDATA state or
the CDATA state, and the escape flag is true, and the last three
characters in the input stream including this one are U+002D
HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN ("-->"),
set the escape flag to false. */
- if(($this->content_model === self::RCDATA ||
- $this->content_model === self::CDATA) && $this->escape === true &&
- $this->character($this->char, 3) === '-->') {
+ if (($this->content_model === self::RCDATA ||
+ $this->content_model === self::CDATA) && $this->escape === true &&
+ $this->character($this->char, 3) === '-->'
+ ) {
$this->escape = false;
}
/* In any case, emit the input character as a character token.
Stay in the data state. */
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => $char
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => $char
+ )
+ );
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
/* EOF
Emit an end-of-file token. */
$this->EOF();
- } elseif($this->content_model === self::PLAINTEXT) {
+ } elseif ($this->content_model === self::PLAINTEXT) {
/* When the content model flag is set to the PLAINTEXT state
THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of
the text and emit it as a character token. */
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => substr($this->data, $this->char)
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => substr($this->data, $this->char)
+ )
+ );
$this->EOF();
@@ -252,37 +599,43 @@ class HTML5 {
THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that
otherwise would also be treated as a character token and emit it
as a single character token. Stay in the data state. */
- $len = strcspn($this->data, '<&', $this->char);
+ $len = strcspn($this->data, '<&', $this->char);
$char = substr($this->data, $this->char, $len);
$this->char += $len - 1;
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => $char
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => $char
+ )
+ );
$this->state = 'data';
}
}
- private function entityDataState() {
+ private function entityDataState()
+ {
// Attempt to consume an entity.
$entity = $this->entity();
// If nothing is returned, emit a U+0026 AMPERSAND character token.
// Otherwise, emit the character token that was returned.
$char = (!$entity) ? '&' : $entity;
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => $char
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => $char
+ )
+ );
// Finally, switch to the data state.
$this->state = 'data';
}
- private function tagOpenState() {
- switch($this->content_model) {
+ private function tagOpenState()
+ {
+ switch ($this->content_model) {
case self::RCDATA:
case self::CDATA:
/* If the next input character is a U+002F SOLIDUS (/) character,
@@ -290,19 +643,21 @@ class HTML5 {
input character is not a U+002F SOLIDUS (/) character, emit a
U+003C LESS-THAN SIGN character token and switch to the data
state to process the next input character. */
- if($this->character($this->char + 1) === '/') {
+ if ($this->character($this->char + 1) === '/') {
$this->char++;
$this->state = 'closeTagOpen';
} else {
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => '<'
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => '<'
+ )
+ );
$this->state = 'data';
}
- break;
+ break;
case self::PCDATA:
// If the content model flag is set to the PCDATA state
@@ -310,42 +665,44 @@ class HTML5 {
$this->char++;
$char = $this->char();
- if($char === '!') {
+ if ($char === '!') {
/* U+0021 EXCLAMATION MARK (!)
Switch to the markup declaration open state. */
$this->state = 'markupDeclarationOpen';
- } elseif($char === '/') {
+ } elseif ($char === '/') {
/* U+002F SOLIDUS (/)
Switch to the close tag open state. */
$this->state = 'closeTagOpen';
- } elseif(preg_match('/^[A-Za-z]$/', $char)) {
+ } elseif (preg_match('/^[A-Za-z]$/', $char)) {
/* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z
Create a new start tag token, set its tag name to the lowercase
version of the input character (add 0x0020 to the character's code
point), then switch to the tag name state. (Don't emit the token
yet; further details will be filled in before it is emitted.) */
$this->token = array(
- 'name' => strtolower($char),
- 'type' => self::STARTTAG,
- 'attr' => array()
+ 'name' => strtolower($char),
+ 'type' => self::STARTTAG,
+ 'attr' => array()
);
$this->state = 'tagName';
- } elseif($char === '>') {
+ } elseif ($char === '>') {
/* U+003E GREATER-THAN SIGN (>)
Parse error. Emit a U+003C LESS-THAN SIGN character token and a
U+003E GREATER-THAN SIGN character token. Switch to the data state. */
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => '<>'
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => '<>'
+ )
+ );
$this->state = 'data';
- } elseif($char === '?') {
+ } elseif ($char === '?') {
/* U+003F QUESTION MARK (?)
Parse error. Switch to the bogus comment state. */
$this->state = 'bogusComment';
@@ -354,25 +711,31 @@ class HTML5 {
/* Anything else
Parse error. Emit a U+003C LESS-THAN SIGN character token and
reconsume the current input character in the data state. */
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => '<'
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => '<'
+ )
+ );
$this->char--;
$this->state = 'data';
}
- break;
+ break;
}
}
- private function closeTagOpenState() {
+ private function closeTagOpenState()
+ {
$next_node = strtolower($this->characters('A-Za-z', $this->char + 1));
$the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName;
- if(($this->content_model === self::RCDATA || $this->content_model === self::CDATA) &&
- (!$the_same || ($the_same && (!preg_match('/[\t\n\x0b\x0c >\/]/',
- $this->character($this->char + 1 + strlen($next_node))) || $this->EOF === $this->char)))) {
+ if (($this->content_model === self::RCDATA || $this->content_model === self::CDATA) &&
+ (!$the_same || ($the_same && (!preg_match(
+ '/[\t\n\x0b\x0c >\/]/',
+ $this->character($this->char + 1 + strlen($next_node))
+ ) || $this->EOF === $this->char)))
+ ) {
/* If the content model flag is set to the RCDATA or CDATA states then
examine the next few characters. If they do not match the tag name of
the last start tag token emitted (case insensitively), or if they do but
@@ -388,10 +751,12 @@ class HTML5 {
...then there is a parse error. Emit a U+003C LESS-THAN SIGN character
token, a U+002F SOLIDUS character token, and switch to the data state
to process the next input character. */
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => '</'
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => '</'
+ )
+ );
$this->state = 'data';
@@ -402,32 +767,34 @@ class HTML5 {
$this->char++;
$char = $this->char();
- if(preg_match('/^[A-Za-z]$/', $char)) {
+ if (preg_match('/^[A-Za-z]$/', $char)) {
/* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z
Create a new end tag token, set its tag name to the lowercase version
of the input character (add 0x0020 to the character's code point), then
switch to the tag name state. (Don't emit the token yet; further details
will be filled in before it is emitted.) */
$this->token = array(
- 'name' => strtolower($char),
- 'type' => self::ENDTAG
+ 'name' => strtolower($char),
+ 'type' => self::ENDTAG
);
$this->state = 'tagName';
- } elseif($char === '>') {
+ } elseif ($char === '>') {
/* U+003E GREATER-THAN SIGN (>)
Parse error. Switch to the data state. */
$this->state = 'data';
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
/* EOF
Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F
SOLIDUS character token. Reconsume the EOF character in the data state. */
- $this->emitToken(array(
- 'type' => self::CHARACTR,
- 'data' => '</'
- ));
+ $this->emitToken(
+ array(
+ 'type' => self::CHARACTR,
+ 'data' => '</'
+ )
+ );
$this->char--;
$this->state = 'data';
@@ -439,12 +806,13 @@ class HTML5 {
}
}
- private function tagNameState() {
+ private function tagNameState()
+ {
// Consume the next input character:
$this->char++;
$char = $this->character($this->char);
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
/* U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000B LINE TABULATION
@@ -453,13 +821,13 @@ class HTML5 {
Switch to the before attribute name state. */
$this->state = 'beforeAttributeName';
- } elseif($char === '>') {
+ } elseif ($char === '>') {
/* U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state. */
$this->emitToken($this->token);
$this->state = 'data';
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
/* EOF
Parse error. Emit the current tag token. Reconsume the EOF
character in the data state. */
@@ -468,7 +836,7 @@ class HTML5 {
$this->char--;
$this->state = 'data';
- } elseif($char === '/') {
+ } elseif ($char === '/') {
/* U+002F SOLIDUS (/)
Parse error unless this is a permitted slash. Switch to the before
attribute name state. */
@@ -483,12 +851,13 @@ class HTML5 {
}
}
- private function beforeAttributeNameState() {
+ private function beforeAttributeNameState()
+ {
// Consume the next input character:
$this->char++;
$char = $this->character($this->char);
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
/* U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000B LINE TABULATION
@@ -497,19 +866,19 @@ class HTML5 {
Stay in the before attribute name state. */
$this->state = 'beforeAttributeName';
- } elseif($char === '>') {
+ } elseif ($char === '>') {
/* U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state. */
$this->emitToken($this->token);
$this->state = 'data';
- } elseif($char === '/') {
+ } elseif ($char === '/') {
/* U+002F SOLIDUS (/)
Parse error unless this is a permitted slash. Stay in the before
attribute name state. */
$this->state = 'beforeAttributeName';
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
/* EOF
Parse error. Emit the current tag token. Reconsume the EOF
character in the data state. */
@@ -524,7 +893,7 @@ class HTML5 {
name to the current input character, and its value to the empty string.
Switch to the attribute name state. */
$this->token['attr'][] = array(
- 'name' => strtolower($char),
+ 'name' => strtolower($char),
'value' => null
);
@@ -532,12 +901,13 @@ class HTML5 {
}
}
- private function attributeNameState() {
+ private function attributeNameState()
+ {
// Consume the next input character:
$this->char++;
$char = $this->character($this->char);
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
/* U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000B LINE TABULATION
@@ -546,24 +916,24 @@ class HTML5 {
Stay in the before attribute name state. */
$this->state = 'afterAttributeName';
- } elseif($char === '=') {
+ } elseif ($char === '=') {
/* U+003D EQUALS SIGN (=)
Switch to the before attribute value state. */
$this->state = 'beforeAttributeValue';
- } elseif($char === '>') {
+ } elseif ($char === '>') {
/* U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state. */
$this->emitToken($this->token);
$this->state = 'data';
- } elseif($char === '/' && $this->character($this->char + 1) !== '>') {
+ } elseif ($char === '/' && $this->character($this->char + 1) !== '>') {
/* U+002F SOLIDUS (/)
Parse error unless this is a permitted slash. Switch to the before
attribute name state. */
$this->state = 'beforeAttributeName';
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
/* EOF
Parse error. Emit the current tag token. Reconsume the EOF
character in the data state. */
@@ -583,12 +953,13 @@ class HTML5 {
}
}
- private function afterAttributeNameState() {
+ private function afterAttributeNameState()
+ {
// Consume the next input character:
$this->char++;
$char = $this->character($this->char);
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
/* U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000B LINE TABULATION
@@ -597,24 +968,24 @@ class HTML5 {
Stay in the after attribute name state. */
$this->state = 'afterAttributeName';
- } elseif($char === '=') {
+ } elseif ($char === '=') {
/* U+003D EQUALS SIGN (=)
Switch to the before attribute value state. */
$this->state = 'beforeAttributeValue';
- } elseif($char === '>') {
+ } elseif ($char === '>') {
/* U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state. */
$this->emitToken($this->token);
$this->state = 'data';
- } elseif($char === '/' && $this->character($this->char + 1) !== '>') {
+ } elseif ($char === '/' && $this->character($this->char + 1) !== '>') {
/* U+002F SOLIDUS (/)
Parse error unless this is a permitted slash. Switch to the
before attribute name state. */
$this->state = 'beforeAttributeName';
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
/* EOF
Parse error. Emit the current tag token. Reconsume the EOF
character in the data state. */
@@ -629,7 +1000,7 @@ class HTML5 {
name to the current input character, and its value to the empty string.
Switch to the attribute name state. */
$this->token['attr'][] = array(
- 'name' => strtolower($char),
+ 'name' => strtolower($char),
'value' => null
);
@@ -637,12 +1008,13 @@ class HTML5 {
}
}
- private function beforeAttributeValueState() {
+ private function beforeAttributeValueState()
+ {
// Consume the next input character:
$this->char++;
$char = $this->character($this->char);
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
/* U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000B LINE TABULATION
@@ -651,24 +1023,24 @@ class HTML5 {
Stay in the before attribute value state. */
$this->state = 'beforeAttributeValue';
- } elseif($char === '"') {
+ } elseif ($char === '"') {
/* U+0022 QUOTATION MARK (")
Switch to the attribute value (double-quoted) state. */
$this->state = 'attributeValueDoubleQuoted';
- } elseif($char === '&') {
+ } elseif ($char === '&') {
/* U+0026 AMPERSAND (&)
Switch to the attribute value (unquoted) state and reconsume
this input character. */
$this->char--;
$this->state = 'attributeValueUnquoted';
- } elseif($char === '\'') {
+ } elseif ($char === '\'') {
/* U+0027 APOSTROPHE (')
Switch to the attribute value (single-quoted) state. */
$this->state = 'attributeValueSingleQuoted';
- } elseif($char === '>') {
+ } elseif ($char === '>') {
/* U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state. */
$this->emitToken($this->token);
@@ -685,22 +1057,23 @@ class HTML5 {
}
}
- private function attributeValueDoubleQuotedState() {
+ private function attributeValueDoubleQuotedState()
+ {
// Consume the next input character:
$this->char++;
$char = $this->character($this->char);
- if($char === '"') {
+ if ($char === '"') {
/* U+0022 QUOTATION MARK (")
Switch to the before attribute name state. */
$this->state = 'beforeAttributeName';
- } elseif($char === '&') {
+ } elseif ($char === '&') {
/* U+0026 AMPERSAND (&)
Switch to the entity in attribute value state. */
$this->entityInAttributeValueState('double');
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
/* EOF
Parse error. Emit the current tag token. Reconsume the character
in the data state. */
@@ -720,22 +1093,23 @@ class HTML5 {
}
}
- private function attributeValueSingleQuotedState() {
+ private function attributeValueSingleQuotedState()
+ {
// Consume the next input character:
$this->char++;
$char = $this->character($this->char);
- if($char === '\'') {
+ if ($char === '\'') {
/* U+0022 QUOTATION MARK (')
Switch to the before attribute name state. */
$this->state = 'beforeAttributeName';
- } elseif($char === '&') {
+ } elseif ($char === '&') {
/* U+0026 AMPERSAND (&)
Switch to the entity in attribute value state. */
$this->entityInAttributeValueState('single');
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
/* EOF
Parse error. Emit the current tag token. Reconsume the character
in the data state. */
@@ -755,12 +1129,13 @@ class HTML5 {
}
}
- private function attributeValueUnquotedState() {
+ private function attributeValueUnquotedState()
+ {
// Consume the next input character:
$this->char++;
$char = $this->character($this->char);
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
/* U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000B LINE TABULATION
@@ -769,12 +1144,12 @@ class HTML5 {
Switch to the before attribute name state. */
$this->state = 'beforeAttributeName';
- } elseif($char === '&') {
+ } elseif ($char === '&') {
/* U+0026 AMPERSAND (&)
Switch to the entity in attribute value state. */
$this->entityInAttributeValueState();
- } elseif($char === '>') {
+ } elseif ($char === '>') {
/* U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state. */
$this->emitToken($this->token);
@@ -791,7 +1166,8 @@ class HTML5 {
}
}
- private function entityInAttributeValueState() {
+ private function entityInAttributeValueState()
+ {
// Attempt to consume an entity.
$entity = $this->entity();
@@ -806,7 +1182,8 @@ class HTML5 {
$this->token['attr'][$last]['value'] .= $char;
}
- private function bogusCommentState() {
+ private function bogusCommentState()
+ {
/* Consume every character up to the first U+003E GREATER-THAN SIGN
character (>) or the end of the file (EOF), whichever comes first. Emit
a comment token whose data is the concatenation of all the characters
@@ -816,10 +1193,12 @@ class HTML5 {
end of the file otherwise. (If the comment was started by the end of
the file (EOF), the token is empty.) */
$data = $this->characters('^>', $this->char);
- $this->emitToken(array(
- 'data' => $data,
- 'type' => self::COMMENT
- ));
+ $this->emitToken(
+ array(
+ 'data' => $data,
+ 'type' => self::COMMENT
+ )
+ );
$this->char += strlen($data);
@@ -827,16 +1206,17 @@ class HTML5 {
$this->state = 'data';
/* If the end of the file was reached, reconsume the EOF character. */
- if($this->char === $this->EOF) {
+ if ($this->char === $this->EOF) {
$this->char = $this->EOF - 1;
}
}
- private function markupDeclarationOpenState() {
+ private function markupDeclarationOpenState()
+ {
/* If the next two characters are both U+002D HYPHEN-MINUS (-)
characters, consume those two characters, create a comment token whose
data is the empty string, and switch to the comment state. */
- if($this->character($this->char + 1, 2) === '--') {
+ if ($this->character($this->char + 1, 2) === '--') {
$this->char += 2;
$this->state = 'comment';
$this->token = array(
@@ -844,41 +1224,42 @@ class HTML5 {
'type' => self::COMMENT
);
- /* Otherwise if the next seven chacacters are a case-insensitive match
- for the word "DOCTYPE", then consume those characters and switch to the
- DOCTYPE state. */
- } elseif(strtolower($this->character($this->char + 1, 7)) === 'doctype') {
+ /* Otherwise if the next seven chacacters are a case-insensitive match
+ for the word "DOCTYPE", then consume those characters and switch to the
+ DOCTYPE state. */
+ } elseif (strtolower($this->character($this->char + 1, 7)) === 'doctype') {
$this->char += 7;
$this->state = 'doctype';
- /* Otherwise, is is a parse error. Switch to the bogus comment state.
- The next character that is consumed, if any, is the first character
- that will be in the comment. */
+ /* Otherwise, is is a parse error. Switch to the bogus comment state.
+ The next character that is consumed, if any, is the first character
+ that will be in the comment. */
} else {
$this->char++;
$this->state = 'bogusComment';
}
}
- private function commentState() {
+ private function commentState()
+ {
/* Consume the next input character: */
$this->char++;
$char = $this->char();
/* U+002D HYPHEN-MINUS (-) */
- if($char === '-') {
+ if ($char === '-') {
/* Switch to the comment dash state */
$this->state = 'commentDash';
- /* EOF */
- } elseif($this->char === $this->EOF) {
+ /* EOF */
+ } elseif ($this->char === $this->EOF) {
/* Parse error. Emit the comment token. Reconsume the EOF character
in the data state. */
$this->emitToken($this->token);
$this->char--;
$this->state = 'data';
- /* Anything else */
+ /* Anything else */
} else {
/* Append the input character to the comment token's data. Stay in
the comment state. */
@@ -886,62 +1267,65 @@ class HTML5 {
}
}
- private function commentDashState() {
+ private function commentDashState()
+ {
/* Consume the next input character: */
$this->char++;
$char = $this->char();
/* U+002D HYPHEN-MINUS (-) */
- if($char === '-') {
+ if ($char === '-') {
/* Switch to the comment end state */
$this->state = 'commentEnd';
- /* EOF */
- } elseif($this->char === $this->EOF) {
+ /* EOF */
+ } elseif ($this->char === $this->EOF) {
/* Parse error. Emit the comment token. Reconsume the EOF character
in the data state. */
$this->emitToken($this->token);
$this->char--;
$this->state = 'data';
- /* Anything else */
+ /* Anything else */
} else {
/* Append a U+002D HYPHEN-MINUS (-) character and the input
character to the comment token's data. Switch to the comment state. */
- $this->token['data'] .= '-'.$char;
+ $this->token['data'] .= '-' . $char;
$this->state = 'comment';
}
}
- private function commentEndState() {
+ private function commentEndState()
+ {
/* Consume the next input character: */
$this->char++;
$char = $this->char();
- if($char === '>') {
+ if ($char === '>') {
$this->emitToken($this->token);
$this->state = 'data';
- } elseif($char === '-') {
+ } elseif ($char === '-') {
$this->token['data'] .= '-';
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
$this->emitToken($this->token);
$this->char--;
$this->state = 'data';
} else {
- $this->token['data'] .= '--'.$char;
+ $this->token['data'] .= '--' . $char;
$this->state = 'comment';
}
}
- private function doctypeState() {
+ private function doctypeState()
+ {
/* Consume the next input character: */
$this->char++;
$char = $this->char();
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
$this->state = 'beforeDoctypeName';
} else {
@@ -950,15 +1334,16 @@ class HTML5 {
}
}
- private function beforeDoctypeNameState() {
+ private function beforeDoctypeNameState()
+ {
/* Consume the next input character: */
$this->char++;
$char = $this->char();
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
// Stay in the before DOCTYPE name state.
- } elseif(preg_match('/^[a-z]$/', $char)) {
+ } elseif (preg_match('/^[a-z]$/', $char)) {
$this->token = array(
'name' => strtoupper($char),
'type' => self::DOCTYPE,
@@ -967,21 +1352,25 @@ class HTML5 {
$this->state = 'doctypeName';
- } elseif($char === '>') {
- $this->emitToken(array(
- 'name' => null,
- 'type' => self::DOCTYPE,
- 'error' => true
- ));
+ } elseif ($char === '>') {
+ $this->emitToken(
+ array(
+ 'name' => null,
+ 'type' => self::DOCTYPE,
+ 'error' => true
+ )
+ );
$this->state = 'data';
- } elseif($this->char === $this->EOF) {
- $this->emitToken(array(
- 'name' => null,
- 'type' => self::DOCTYPE,
- 'error' => true
- ));
+ } elseif ($this->char === $this->EOF) {
+ $this->emitToken(
+ array(
+ 'name' => null,
+ 'type' => self::DOCTYPE,
+ 'error' => true
+ )
+ );
$this->char--;
$this->state = 'data';
@@ -997,22 +1386,23 @@ class HTML5 {
}
}
- private function doctypeNameState() {
+ private function doctypeNameState()
+ {
/* Consume the next input character: */
$this->char++;
$char = $this->char();
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
$this->state = 'AfterDoctypeName';
- } elseif($char === '>') {
+ } elseif ($char === '>') {
$this->emitToken($this->token);
$this->state = 'data';
- } elseif(preg_match('/^[a-z]$/', $char)) {
+ } elseif (preg_match('/^[a-z]$/', $char)) {
$this->token['name'] .= strtoupper($char);
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
$this->emitToken($this->token);
$this->char--;
$this->state = 'data';
@@ -1026,19 +1416,20 @@ class HTML5 {
: true;
}
- private function afterDoctypeNameState() {
+ private function afterDoctypeNameState()
+ {
/* Consume the next input character: */
$this->char++;
$char = $this->char();
- if(preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
+ if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) {
// Stay in the DOCTYPE name state.
- } elseif($char === '>') {
+ } elseif ($char === '>') {
$this->emitToken($this->token);
$this->state = 'data';
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
$this->emitToken($this->token);
$this->char--;
$this->state = 'data';
@@ -1049,16 +1440,17 @@ class HTML5 {
}
}
- private function bogusDoctypeState() {
+ private function bogusDoctypeState()
+ {
/* Consume the next input character: */
$this->char++;
$char = $this->char();
- if($char === '>') {
+ if ($char === '>') {
$this->emitToken($this->token);
$this->state = 'data';
- } elseif($this->char === $this->EOF) {
+ } elseif ($this->char === $this->EOF) {
$this->emitToken($this->token);
$this->char--;
$this->state = 'data';
@@ -1068,22 +1460,23 @@ class HTML5 {
}
}
- private function entity() {
+ private function entity()
+ {
$start = $this->char;
// This section defines how to consume an entity. This definition is
// used when parsing entities in text and in attributes.
// The behaviour depends on the identity of the next character (the
- // one immediately after the U+0026 AMPERSAND character):
+ // one immediately after the U+0026 AMPERSAND character):
- switch($this->character($this->char + 1)) {
+ switch ($this->character($this->char + 1)) {
// U+0023 NUMBER SIGN (#)
case '#':
// The behaviour further depends on the character after the
// U+0023 NUMBER SIGN:
- switch($this->character($this->char + 1)) {
+ switch ($this->character($this->char + 1)) {
// U+0078 LATIN SMALL LETTER X
// U+0058 LATIN CAPITAL LETTER X
case 'x':
@@ -1096,7 +1489,7 @@ class HTML5 {
// words, 0-9, A-F, a-f).
$char = 1;
$char_class = '0-9A-Fa-f';
- break;
+ break;
// Anything else
default:
@@ -1105,7 +1498,7 @@ class HTML5 {
// NINE (i.e. just 0-9).
$char = 0;
$char_class = '0-9';
- break;
+ break;
}
// Consume as many characters as match the range of characters
@@ -1116,7 +1509,7 @@ class HTML5 {
$cond = strlen($e_name) > 0;
// The rest of the parsing happens bellow.
- break;
+ break;
// Anything else
default:
@@ -1126,12 +1519,12 @@ class HTML5 {
$e_name = $this->characters('0-9A-Za-z;', $this->char + 1);
$len = strlen($e_name);
- for($c = 1; $c <= $len; $c++) {
+ for ($c = 1; $c <= $len; $c++) {
$id = substr($e_name, 0, $c);
$this->char++;
- if(in_array($id, $this->entities)) {
- if ($e_name[$c-1] !== ';') {
+ if (in_array($id, $this->entities)) {
+ if ($e_name[$c - 1] !== ';') {
if ($c < $len && $e_name[$c] == ';') {
$this->char++; // consume extra semicolon
}
@@ -1143,10 +1536,10 @@ class HTML5 {
$cond = isset($entity);
// The rest of the parsing happens bellow.
- break;
+ break;
}
- if(!$cond) {
+ if (!$cond) {
// If no match can be made, then this is a parse error. No
// characters are consumed, and nothing is returned.
$this->char = $start;
@@ -1155,81 +1548,157 @@ class HTML5 {
// Return a character token for the character corresponding to the
// entity name (as given by the second column of the entities table).
- return html_entity_decode('&'.$entity.';', ENT_QUOTES, 'UTF-8');
+ return html_entity_decode('&' . $entity . ';', ENT_QUOTES, 'UTF-8');
}
- private function emitToken($token) {
+ private function emitToken($token)
+ {
$emit = $this->tree->emitToken($token);
- if(is_int($emit)) {
+ if (is_int($emit)) {
$this->content_model = $emit;
- } elseif($token['type'] === self::ENDTAG) {
+ } elseif ($token['type'] === self::ENDTAG) {
$this->content_model = self::PCDATA;
}
}
- private function EOF() {
+ private function EOF()
+ {
$this->state = null;
- $this->tree->emitToken(array(
- 'type' => self::EOF
- ));
+ $this->tree->emitToken(
+ array(
+ 'type' => self::EOF
+ )
+ );
}
}
-class HTML5TreeConstructer {
+class HTML5TreeConstructer
+{
public $stack = array();
private $phase;
private $mode;
private $dom;
private $foster_parent = null;
- private $a_formatting = array();
+ private $a_formatting = array();
private $head_pointer = null;
private $form_pointer = null;
- private $scoping = array('button','caption','html','marquee','object','table','td','th');
- private $formatting = array('a','b','big','em','font','i','nobr','s','small','strike','strong','tt','u');
- private $special = array('address','area','base','basefont','bgsound',
- 'blockquote','body','br','center','col','colgroup','dd','dir','div','dl',
- 'dt','embed','fieldset','form','frame','frameset','h1','h2','h3','h4','h5',
- 'h6','head','hr','iframe','image','img','input','isindex','li','link',
- 'listing','menu','meta','noembed','noframes','noscript','ol','optgroup',
- 'option','p','param','plaintext','pre','script','select','spacer','style',
- 'tbody','textarea','tfoot','thead','title','tr','ul','wbr');
+ private $scoping = array('button', 'caption', 'html', 'marquee', 'object', 'table', 'td', 'th');
+ private $formatting = array(
+ 'a',
+ 'b',
+ 'big',
+ 'em',
+ 'font',
+ 'i',
+ 'nobr',
+ 's',
+ 'small',
+ 'strike',
+ 'strong',
+ 'tt',
+ 'u'
+ );
+ private $special = array(
+ 'address',
+ 'area',
+ 'base',
+ 'basefont',
+ 'bgsound',
+ 'blockquote',
+ 'body',
+ 'br',
+ 'center',
+ 'col',
+ 'colgroup',
+ 'dd',
+ 'dir',
+ 'div',
+ 'dl',
+ 'dt',
+ 'embed',
+ 'fieldset',
+ 'form',
+ 'frame',
+ 'frameset',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'head',
+ 'hr',
+ 'iframe',
+ 'image',
+ 'img',
+ 'input',
+ 'isindex',
+ 'li',
+ 'link',
+ 'listing',
+ 'menu',
+ 'meta',
+ 'noembed',
+ 'noframes',
+ 'noscript',
+ 'ol',
+ 'optgroup',
+ 'option',
+ 'p',
+ 'param',
+ 'plaintext',
+ 'pre',
+ 'script',
+ 'select',
+ 'spacer',
+ 'style',
+ 'tbody',
+ 'textarea',
+ 'tfoot',
+ 'thead',
+ 'title',
+ 'tr',
+ 'ul',
+ 'wbr'
+ );
// The different phases.
const INIT_PHASE = 0;
const ROOT_PHASE = 1;
const MAIN_PHASE = 2;
- const END_PHASE = 3;
+ const END_PHASE = 3;
// The different insertion modes for the main phase.
const BEFOR_HEAD = 0;
- const IN_HEAD = 1;
+ const IN_HEAD = 1;
const AFTER_HEAD = 2;
- const IN_BODY = 3;
- const IN_TABLE = 4;
+ const IN_BODY = 3;
+ const IN_TABLE = 4;
const IN_CAPTION = 5;
- const IN_CGROUP = 6;
- const IN_TBODY = 7;
- const IN_ROW = 8;
- const IN_CELL = 9;
- const IN_SELECT = 10;
+ const IN_CGROUP = 6;
+ const IN_TBODY = 7;
+ const IN_ROW = 8;
+ const IN_CELL = 9;
+ const IN_SELECT = 10;
const AFTER_BODY = 11;
- const IN_FRAME = 12;
+ const IN_FRAME = 12;
const AFTR_FRAME = 13;
// The different types of elements.
- const SPECIAL = 0;
- const SCOPING = 1;
+ const SPECIAL = 0;
+ const SCOPING = 1;
const FORMATTING = 2;
- const PHRASING = 3;
+ const PHRASING = 3;
- const MARKER = 0;
+ const MARKER = 0;
- public function __construct() {
+ public function __construct()
+ {
$this->phase = self::INIT_PHASE;
$this->mode = self::BEFOR_HEAD;
$this->dom = new DOMDocument;
@@ -1241,16 +1710,26 @@ class HTML5TreeConstructer {
}
// Process tag tokens
- public function emitToken($token) {
- switch($this->phase) {
- case self::INIT_PHASE: return $this->initPhase($token); break;
- case self::ROOT_PHASE: return $this->rootElementPhase($token); break;
- case self::MAIN_PHASE: return $this->mainPhase($token); break;
- case self::END_PHASE : return $this->trailingEndPhase($token); break;
+ public function emitToken($token)
+ {
+ switch ($this->phase) {
+ case self::INIT_PHASE:
+ return $this->initPhase($token);
+ break;
+ case self::ROOT_PHASE:
+ return $this->rootElementPhase($token);
+ break;
+ case self::MAIN_PHASE:
+ return $this->mainPhase($token);
+ break;
+ case self::END_PHASE :
+ return $this->trailingEndPhase($token);
+ break;
}
}
- private function initPhase($token) {
+ private function initPhase($token)
+ {
/* Initially, the tree construction stage must handle each token
emitted from the tokenisation stage as follows: */
@@ -1262,13 +1741,14 @@ class HTML5TreeConstructer {
U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
or U+0020 SPACE
An end-of-file token */
- if((isset($token['error']) && $token['error']) ||
- $token['type'] === HTML5::COMMENT ||
- $token['type'] === HTML5::STARTTAG ||
- $token['type'] === HTML5::ENDTAG ||
- $token['type'] === HTML5::EOF ||
- ($token['type'] === HTML5::CHARACTR && isset($token['data']) &&
- !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))) {
+ if ((isset($token['error']) && $token['error']) ||
+ $token['type'] === HTML5::COMMENT ||
+ $token['type'] === HTML5::STARTTAG ||
+ $token['type'] === HTML5::ENDTAG ||
+ $token['type'] === HTML5::EOF ||
+ ($token['type'] === HTML5::CHARACTR && isset($token['data']) &&
+ !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']))
+ ) {
/* This specification does not define how to handle this case. In
particular, user agents may ignore the entirety of this specification
altogether for such documents, and instead invoke special parse modes
@@ -1277,8 +1757,8 @@ class HTML5TreeConstructer {
$this->phase = self::ROOT_PHASE;
return $this->rootElementPhase($token);
- /* A DOCTYPE token marked as being correct */
- } elseif(isset($token['error']) && !$token['error']) {
+ /* A DOCTYPE token marked as being correct */
+ } elseif (isset($token['error']) && !$token['error']) {
/* Append a DocumentType node to the Document node, with the name
attribute set to the name given in the DOCTYPE token (which will be
"HTML"), and the other attributes specific to DocumentType objects
@@ -1289,52 +1769,58 @@ class HTML5TreeConstructer {
stage. */
$this->phase = self::ROOT_PHASE;
- /* A character token that is one of one of U+0009 CHARACTER TABULATION,
- U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
- or U+0020 SPACE */
- } elseif(isset($token['data']) && preg_match('/^[\t\n\x0b\x0c ]+$/',
- $token['data'])) {
+ /* A character token that is one of one of U+0009 CHARACTER TABULATION,
+ U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
+ or U+0020 SPACE */
+ } elseif (isset($token['data']) && preg_match(
+ '/^[\t\n\x0b\x0c ]+$/',
+ $token['data']
+ )
+ ) {
/* Append that character to the Document node. */
$text = $this->dom->createTextNode($token['data']);
$this->dom->appendChild($text);
}
}
- private function rootElementPhase($token) {
+ private function rootElementPhase($token)
+ {
/* After the initial phase, as each token is emitted from the tokenisation
stage, it must be processed as described in this section. */
/* A DOCTYPE token */
- if($token['type'] === HTML5::DOCTYPE) {
+ if ($token['type'] === HTML5::DOCTYPE) {
// Parse error. Ignore the token.
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the Document object with the data
attribute set to the data given in the comment token. */
$comment = $this->dom->createComment($token['data']);
$this->dom->appendChild($comment);
- /* A character token that is one of one of U+0009 CHARACTER TABULATION,
- U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
- or U+0020 SPACE */
- } elseif($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ /* A character token that is one of one of U+0009 CHARACTER TABULATION,
+ U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
+ or U+0020 SPACE */
+ } elseif ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Append that character to the Document node. */
$text = $this->dom->createTextNode($token['data']);
$this->dom->appendChild($text);
- /* A character token that is not one of U+0009 CHARACTER TABULATION,
- U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED
- (FF), or U+0020 SPACE
- A start tag token
- An end tag token
- An end-of-file token */
- } elseif(($token['type'] === HTML5::CHARACTR &&
- !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
- $token['type'] === HTML5::STARTTAG ||
- $token['type'] === HTML5::ENDTAG ||
- $token['type'] === HTML5::EOF) {
+ /* A character token that is not one of U+0009 CHARACTER TABULATION,
+ U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED
+ (FF), or U+0020 SPACE
+ A start tag token
+ An end tag token
+ An end-of-file token */
+ } elseif (($token['type'] === HTML5::CHARACTR &&
+ !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
+ $token['type'] === HTML5::STARTTAG ||
+ $token['type'] === HTML5::ENDTAG ||
+ $token['type'] === HTML5::EOF
+ ) {
/* Create an HTMLElement node with the tag name html, in the HTML
namespace. Append it to the Document object. Switch to the main
phase and reprocess the current token. */
@@ -1347,15 +1833,16 @@ class HTML5TreeConstructer {
}
}
- private function mainPhase($token) {
+ private function mainPhase($token)
+ {
/* Tokens in the main phase must be handled as follows: */
/* A DOCTYPE token */
- if($token['type'] === HTML5::DOCTYPE) {
+ if ($token['type'] === HTML5::DOCTYPE) {
// Parse error. Ignore the token.
- /* A start tag token with the tag name "html" */
- } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') {
+ /* A start tag token with the tag name "html" */
+ } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') {
/* If this start tag token was not the first start tag token, then
it is a parse error. */
@@ -1363,59 +1850,91 @@ class HTML5TreeConstructer {
is already present on the top element of the stack of open elements.
If it is not, add the attribute and its corresponding value to that
element. */
- foreach($token['attr'] as $attr) {
- if(!$this->stack[0]->hasAttribute($attr['name'])) {
+ foreach ($token['attr'] as $attr) {
+ if (!$this->stack[0]->hasAttribute($attr['name'])) {
$this->stack[0]->setAttribute($attr['name'], $attr['value']);
}
}
- /* An end-of-file token */
- } elseif($token['type'] === HTML5::EOF) {
+ /* An end-of-file token */
+ } elseif ($token['type'] === HTML5::EOF) {
/* Generate implied end tags. */
$this->generateImpliedEndTags();
- /* Anything else. */
+ /* Anything else. */
} else {
/* Depends on the insertion mode: */
- switch($this->mode) {
- case self::BEFOR_HEAD: return $this->beforeHead($token); break;
- case self::IN_HEAD: return $this->inHead($token); break;
- case self::AFTER_HEAD: return $this->afterHead($token); break;
- case self::IN_BODY: return $this->inBody($token); break;
- case self::IN_TABLE: return $this->inTable($token); break;
- case self::IN_CAPTION: return $this->inCaption($token); break;
- case self::IN_CGROUP: return $this->inColumnGroup($token); break;
- case self::IN_TBODY: return $this->inTableBody($token); break;
- case self::IN_ROW: return $this->inRow($token); break;
- case self::IN_CELL: return $this->inCell($token); break;
- case self::IN_SELECT: return $this->inSelect($token); break;
- case self::AFTER_BODY: return $this->afterBody($token); break;
- case self::IN_FRAME: return $this->inFrameset($token); break;
- case self::AFTR_FRAME: return $this->afterFrameset($token); break;
- case self::END_PHASE: return $this->trailingEndPhase($token); break;
+ switch ($this->mode) {
+ case self::BEFOR_HEAD:
+ return $this->beforeHead($token);
+ break;
+ case self::IN_HEAD:
+ return $this->inHead($token);
+ break;
+ case self::AFTER_HEAD:
+ return $this->afterHead($token);
+ break;
+ case self::IN_BODY:
+ return $this->inBody($token);
+ break;
+ case self::IN_TABLE:
+ return $this->inTable($token);
+ break;
+ case self::IN_CAPTION:
+ return $this->inCaption($token);
+ break;
+ case self::IN_CGROUP:
+ return $this->inColumnGroup($token);
+ break;
+ case self::IN_TBODY:
+ return $this->inTableBody($token);
+ break;
+ case self::IN_ROW:
+ return $this->inRow($token);
+ break;
+ case self::IN_CELL:
+ return $this->inCell($token);
+ break;
+ case self::IN_SELECT:
+ return $this->inSelect($token);
+ break;
+ case self::AFTER_BODY:
+ return $this->afterBody($token);
+ break;
+ case self::IN_FRAME:
+ return $this->inFrameset($token);
+ break;
+ case self::AFTR_FRAME:
+ return $this->afterFrameset($token);
+ break;
+ case self::END_PHASE:
+ return $this->trailingEndPhase($token);
+ break;
}
}
}
- private function beforeHead($token) {
+ private function beforeHead($token)
+ {
/* Handle the token as follows: */
/* A character token that is one of one of U+0009 CHARACTER TABULATION,
U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
or U+0020 SPACE */
- if($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ if ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Append the character to the current node. */
$this->insertText($token['data']);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the current node with the data attribute
set to the data given in the comment token. */
$this->insertComment($token['data']);
- /* A start tag token with the tag name "head" */
- } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') {
+ /* A start tag token with the tag name "head" */
+ } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') {
/* Create an element for the token, append the new element to the
current node and push it onto the stack of open elements. */
$element = $this->insertElement($token);
@@ -1426,32 +1945,38 @@ class HTML5TreeConstructer {
/* Change the insertion mode to "in head". */
$this->mode = self::IN_HEAD;
- /* A start tag token whose tag name is one of: "base", "link", "meta",
- "script", "style", "title". Or an end tag with the tag name "html".
- Or a character token that is not one of U+0009 CHARACTER TABULATION,
- U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
- or U+0020 SPACE. Or any other start tag token */
- } elseif($token['type'] === HTML5::STARTTAG ||
- ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') ||
- ($token['type'] === HTML5::CHARACTR && !preg_match('/^[\t\n\x0b\x0c ]$/',
- $token['data']))) {
+ /* A start tag token whose tag name is one of: "base", "link", "meta",
+ "script", "style", "title". Or an end tag with the tag name "html".
+ Or a character token that is not one of U+0009 CHARACTER TABULATION,
+ U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
+ or U+0020 SPACE. Or any other start tag token */
+ } elseif ($token['type'] === HTML5::STARTTAG ||
+ ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') ||
+ ($token['type'] === HTML5::CHARACTR && !preg_match(
+ '/^[\t\n\x0b\x0c ]$/',
+ $token['data']
+ ))
+ ) {
/* Act as if a start tag token with the tag name "head" and no
attributes had been seen, then reprocess the current token. */
- $this->beforeHead(array(
- 'name' => 'head',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
+ $this->beforeHead(
+ array(
+ 'name' => 'head',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
return $this->inHead($token);
- /* Any other end tag */
- } elseif($token['type'] === HTML5::ENDTAG) {
+ /* Any other end tag */
+ } elseif ($token['type'] === HTML5::ENDTAG) {
/* Parse error. Ignore the token. */
}
}
- private function inHead($token) {
+ private function inHead($token)
+ {
/* Handle the token as follows: */
/* A character token that is one of one of U+0009 CHARACTER TABULATION,
@@ -1461,30 +1986,34 @@ class HTML5TreeConstructer {
THIS DIFFERS FROM THE SPEC: If the current node is either a title, style
or script element, append the character to the current node regardless
of its content. */
- if(($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || (
- $token['type'] === HTML5::CHARACTR && in_array(end($this->stack)->nodeName,
- array('title', 'style', 'script')))) {
+ if (($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || (
+ $token['type'] === HTML5::CHARACTR && in_array(
+ end($this->stack)->nodeName,
+ array('title', 'style', 'script')
+ ))
+ ) {
/* Append the character to the current node. */
$this->insertText($token['data']);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the current node with the data attribute
set to the data given in the comment token. */
$this->insertComment($token['data']);
- } elseif($token['type'] === HTML5::ENDTAG &&
- in_array($token['name'], array('title', 'style', 'script'))) {
+ } elseif ($token['type'] === HTML5::ENDTAG &&
+ in_array($token['name'], array('title', 'style', 'script'))
+ ) {
array_pop($this->stack);
return HTML5::PCDATA;
- /* A start tag with the tag name "title" */
- } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') {
+ /* A start tag with the tag name "title" */
+ } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') {
/* Create an element for the token and append the new element to the
node pointed to by the head element pointer, or, if that is null
(innerHTML case), to the current node. */
- if($this->head_pointer !== null) {
+ if ($this->head_pointer !== null) {
$element = $this->insertElement($token, false);
$this->head_pointer->appendChild($element);
@@ -1495,12 +2024,12 @@ class HTML5TreeConstructer {
/* Switch the tokeniser's content model flag to the RCDATA state. */
return HTML5::RCDATA;
- /* A start tag with the tag name "style" */
- } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') {
+ /* A start tag with the tag name "style" */
+ } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') {
/* Create an element for the token and append the new element to the
node pointed to by the head element pointer, or, if that is null
(innerHTML case), to the current node. */
- if($this->head_pointer !== null) {
+ if ($this->head_pointer !== null) {
$element = $this->insertElement($token, false);
$this->head_pointer->appendChild($element);
@@ -1511,8 +2040,8 @@ class HTML5TreeConstructer {
/* Switch the tokeniser's content model flag to the CDATA state. */
return HTML5::CDATA;
- /* A start tag with the tag name "script" */
- } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') {
+ /* A start tag with the tag name "script" */
+ } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') {
/* Create an element for the token. */
$element = $this->insertElement($token, false);
$this->head_pointer->appendChild($element);
@@ -1520,13 +2049,16 @@ class HTML5TreeConstructer {
/* Switch the tokeniser's content model flag to the CDATA state. */
return HTML5::CDATA;
- /* A start tag with the tag name "base", "link", or "meta" */
- } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
- array('base', 'link', 'meta'))) {
+ /* A start tag with the tag name "base", "link", or "meta" */
+ } elseif ($token['type'] === HTML5::STARTTAG && in_array(
+ $token['name'],
+ array('base', 'link', 'meta')
+ )
+ ) {
/* Create an element for the token and append the new element to the
node pointed to by the head element pointer, or, if that is null
(innerHTML case), to the current node. */
- if($this->head_pointer !== null) {
+ if ($this->head_pointer !== null) {
$element = $this->insertElement($token, false);
$this->head_pointer->appendChild($element);
array_pop($this->stack);
@@ -1535,14 +2067,14 @@ class HTML5TreeConstructer {
$this->insertElement($token);
}
- /* An end tag with the tag name "head" */
- } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') {
+ /* An end tag with the tag name "head" */
+ } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') {
/* If the current node is a head element, pop the current node off
the stack of open elements. */
- if($this->head_pointer->isSameNode(end($this->stack))) {
+ if ($this->head_pointer->isSameNode(end($this->stack))) {
array_pop($this->stack);
- /* Otherwise, this is a parse error. */
+ /* Otherwise, this is a parse error. */
} else {
// k
}
@@ -1550,22 +2082,25 @@ class HTML5TreeConstructer {
/* Change the insertion mode to "after head". */
$this->mode = self::AFTER_HEAD;
- /* A start tag with the tag name "head" or an end tag except "html". */
- } elseif(($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') ||
- ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')) {
+ /* A start tag with the tag name "head" or an end tag except "html". */
+ } elseif (($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') ||
+ ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html')
+ ) {
// Parse error. Ignore the token.
- /* Anything else */
+ /* Anything else */
} else {
/* If the current node is a head element, act as if an end tag
token with the tag name "head" had been seen. */
- if($this->head_pointer->isSameNode(end($this->stack))) {
- $this->inHead(array(
- 'name' => 'head',
- 'type' => HTML5::ENDTAG
- ));
+ if ($this->head_pointer->isSameNode(end($this->stack))) {
+ $this->inHead(
+ array(
+ 'name' => 'head',
+ 'type' => HTML5::ENDTAG
+ )
+ );
- /* Otherwise, change the insertion mode to "after head". */
+ /* Otherwise, change the insertion mode to "after head". */
} else {
$this->mode = self::AFTER_HEAD;
}
@@ -1575,66 +2110,74 @@ class HTML5TreeConstructer {
}
}
- private function afterHead($token) {
+ private function afterHead($token)
+ {
/* Handle the token as follows: */
/* A character token that is one of one of U+0009 CHARACTER TABULATION,
U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
or U+0020 SPACE */
- if($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ if ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Append the character to the current node. */
$this->insertText($token['data']);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the current node with the data attribute
set to the data given in the comment token. */
$this->insertComment($token['data']);
- /* A start tag token with the tag name "body" */
- } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') {
+ /* A start tag token with the tag name "body" */
+ } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') {
/* Insert a body element for the token. */
$this->insertElement($token);
/* Change the insertion mode to "in body". */
$this->mode = self::IN_BODY;
- /* A start tag token with the tag name "frameset" */
- } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') {
+ /* A start tag token with the tag name "frameset" */
+ } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') {
/* Insert a frameset element for the token. */
$this->insertElement($token);
/* Change the insertion mode to "in frameset". */
$this->mode = self::IN_FRAME;
- /* A start tag token whose tag name is one of: "base", "link", "meta",
- "script", "style", "title" */
- } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
- array('base', 'link', 'meta', 'script', 'style', 'title'))) {
+ /* A start tag token whose tag name is one of: "base", "link", "meta",
+ "script", "style", "title" */
+ } elseif ($token['type'] === HTML5::STARTTAG && in_array(
+ $token['name'],
+ array('base', 'link', 'meta', 'script', 'style', 'title')
+ )
+ ) {
/* Parse error. Switch the insertion mode back to "in head" and
reprocess the token. */
$this->mode = self::IN_HEAD;
return $this->inHead($token);
- /* Anything else */
+ /* Anything else */
} else {
/* Act as if a start tag token with the tag name "body" and no
attributes had been seen, and then reprocess the current token. */
- $this->afterHead(array(
- 'name' => 'body',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
+ $this->afterHead(
+ array(
+ 'name' => 'body',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
return $this->inBody($token);
}
}
- private function inBody($token) {
+ private function inBody($token)
+ {
/* Handle the token as follows: */
- switch($token['type']) {
+ switch ($token['type']) {
/* A character token */
case HTML5::CHARACTR:
/* Reconstruct the active formatting elements, if any. */
@@ -1642,1015 +2185,1159 @@ class HTML5TreeConstructer {
/* Append the token's character to the current node. */
$this->insertText($token['data']);
- break;
+ break;
/* A comment token */
case HTML5::COMMENT:
/* Append a Comment node to the current node with the data
attribute set to the data given in the comment token. */
$this->insertComment($token['data']);
- break;
+ break;
case HTML5::STARTTAG:
- switch($token['name']) {
- /* A start tag token whose tag name is one of: "script",
- "style" */
- case 'script': case 'style':
- /* Process the token as if the insertion mode had been "in
- head". */
- return $this->inHead($token);
- break;
+ switch ($token['name']) {
+ /* A start tag token whose tag name is one of: "script",
+ "style" */
+ case 'script':
+ case 'style':
+ /* Process the token as if the insertion mode had been "in
+ head". */
+ return $this->inHead($token);
+ break;
- /* A start tag token whose tag name is one of: "base", "link",
- "meta", "title" */
- case 'base': case 'link': case 'meta': case 'title':
- /* Parse error. Process the token as if the insertion mode
- had been "in head". */
- return $this->inHead($token);
- break;
+ /* A start tag token whose tag name is one of: "base", "link",
+ "meta", "title" */
+ case 'base':
+ case 'link':
+ case 'meta':
+ case 'title':
+ /* Parse error. Process the token as if the insertion mode
+ had been "in head". */
+ return $this->inHead($token);
+ break;
- /* A start tag token with the tag name "body" */
- case 'body':
- /* Parse error. If the second element on the stack of open
- elements is not a body element, or, if the stack of open
- elements has only one node on it, then ignore the token.
- (innerHTML case) */
- if(count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') {
- // Ignore
-
- /* Otherwise, for each attribute on the token, check to see
- if the attribute is already present on the body element (the
- second element) on the stack of open elements. If it is not,
- add the attribute and its corresponding value to that
- element. */
- } else {
- foreach($token['attr'] as $attr) {
- if(!$this->stack[1]->hasAttribute($attr['name'])) {
- $this->stack[1]->setAttribute($attr['name'], $attr['value']);
+ /* A start tag token with the tag name "body" */
+ case 'body':
+ /* Parse error. If the second element on the stack of open
+ elements is not a body element, or, if the stack of open
+ elements has only one node on it, then ignore the token.
+ (innerHTML case) */
+ if (count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') {
+ // Ignore
+
+ /* Otherwise, for each attribute on the token, check to see
+ if the attribute is already present on the body element (the
+ second element) on the stack of open elements. If it is not,
+ add the attribute and its corresponding value to that
+ element. */
+ } else {
+ foreach ($token['attr'] as $attr) {
+ if (!$this->stack[1]->hasAttribute($attr['name'])) {
+ $this->stack[1]->setAttribute($attr['name'], $attr['value']);
+ }
}
}
- }
- break;
-
- /* A start tag whose tag name is one of: "address",
- "blockquote", "center", "dir", "div", "dl", "fieldset",
- "listing", "menu", "ol", "p", "ul" */
- case 'address': case 'blockquote': case 'center': case 'dir':
- case 'div': case 'dl': case 'fieldset': case 'listing':
- case 'menu': case 'ol': case 'p': case 'ul':
- /* If the stack of open elements has a p element in scope,
- then act as if an end tag with the tag name p had been
- seen. */
- if($this->elementInScope('p')) {
- $this->emitToken(array(
- 'name' => 'p',
- 'type' => HTML5::ENDTAG
- ));
- }
-
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
- break;
+ break;
- /* A start tag whose tag name is "form" */
- case 'form':
- /* If the form element pointer is not null, ignore the
- token with a parse error. */
- if($this->form_pointer !== null) {
- // Ignore.
-
- /* Otherwise: */
- } else {
- /* If the stack of open elements has a p element in
- scope, then act as if an end tag with the tag name p
- had been seen. */
- if($this->elementInScope('p')) {
- $this->emitToken(array(
- 'name' => 'p',
- 'type' => HTML5::ENDTAG
- ));
+ /* A start tag whose tag name is one of: "address",
+ "blockquote", "center", "dir", "div", "dl", "fieldset",
+ "listing", "menu", "ol", "p", "ul" */
+ case 'address':
+ case 'blockquote':
+ case 'center':
+ case 'dir':
+ case 'div':
+ case 'dl':
+ case 'fieldset':
+ case 'listing':
+ case 'menu':
+ case 'ol':
+ case 'p':
+ case 'ul':
+ /* If the stack of open elements has a p element in scope,
+ then act as if an end tag with the tag name p had been
+ seen. */
+ if ($this->elementInScope('p')) {
+ $this->emitToken(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::ENDTAG
+ )
+ );
}
- /* Insert an HTML element for the token, and set the
- form element pointer to point to the element created. */
- $element = $this->insertElement($token);
- $this->form_pointer = $element;
- }
- break;
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
+ break;
- /* A start tag whose tag name is "li", "dd" or "dt" */
- case 'li': case 'dd': case 'dt':
- /* If the stack of open elements has a p element in scope,
- then act as if an end tag with the tag name p had been
- seen. */
- if($this->elementInScope('p')) {
- $this->emitToken(array(
- 'name' => 'p',
- 'type' => HTML5::ENDTAG
- ));
- }
+ /* A start tag whose tag name is "form" */
+ case 'form':
+ /* If the form element pointer is not null, ignore the
+ token with a parse error. */
+ if ($this->form_pointer !== null) {
+ // Ignore.
- $stack_length = count($this->stack) - 1;
-
- for($n = $stack_length; 0 <= $n; $n--) {
- /* 1. Initialise node to be the current node (the
- bottommost node of the stack). */
- $stop = false;
- $node = $this->stack[$n];
- $cat = $this->getElementCategory($node->tagName);
-
- /* 2. If node is an li, dd or dt element, then pop all
- the nodes from the current node up to node, including
- node, then stop this algorithm. */
- if($token['name'] === $node->tagName || ($token['name'] !== 'li'
- && ($node->tagName === 'dd' || $node->tagName === 'dt'))) {
- for($x = $stack_length; $x >= $n ; $x--) {
- array_pop($this->stack);
+ /* Otherwise: */
+ } else {
+ /* If the stack of open elements has a p element in
+ scope, then act as if an end tag with the tag name p
+ had been seen. */
+ if ($this->elementInScope('p')) {
+ $this->emitToken(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::ENDTAG
+ )
+ );
}
- break;
+ /* Insert an HTML element for the token, and set the
+ form element pointer to point to the element created. */
+ $element = $this->insertElement($token);
+ $this->form_pointer = $element;
}
+ break;
- /* 3. If node is not in the formatting category, and is
- not in the phrasing category, and is not an address or
- div element, then stop this algorithm. */
- if($cat !== self::FORMATTING && $cat !== self::PHRASING &&
- $node->tagName !== 'address' && $node->tagName !== 'div') {
- break;
+ /* A start tag whose tag name is "li", "dd" or "dt" */
+ case 'li':
+ case 'dd':
+ case 'dt':
+ /* If the stack of open elements has a p element in scope,
+ then act as if an end tag with the tag name p had been
+ seen. */
+ if ($this->elementInScope('p')) {
+ $this->emitToken(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::ENDTAG
+ )
+ );
}
- }
- /* Finally, insert an HTML element with the same tag
- name as the token's. */
- $this->insertElement($token);
- break;
+ $stack_length = count($this->stack) - 1;
+
+ for ($n = $stack_length; 0 <= $n; $n--) {
+ /* 1. Initialise node to be the current node (the
+ bottommost node of the stack). */
+ $stop = false;
+ $node = $this->stack[$n];
+ $cat = $this->getElementCategory($node->tagName);
+
+ /* 2. If node is an li, dd or dt element, then pop all
+ the nodes from the current node up to node, including
+ node, then stop this algorithm. */
+ if ($token['name'] === $node->tagName || ($token['name'] !== 'li'
+ && ($node->tagName === 'dd' || $node->tagName === 'dt'))
+ ) {
+ for ($x = $stack_length; $x >= $n; $x--) {
+ array_pop($this->stack);
+ }
- /* A start tag token whose tag name is "plaintext" */
- case 'plaintext':
- /* If the stack of open elements has a p element in scope,
- then act as if an end tag with the tag name p had been
- seen. */
- if($this->elementInScope('p')) {
- $this->emitToken(array(
- 'name' => 'p',
- 'type' => HTML5::ENDTAG
- ));
- }
+ break;
+ }
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
+ /* 3. If node is not in the formatting category, and is
+ not in the phrasing category, and is not an address or
+ div element, then stop this algorithm. */
+ if ($cat !== self::FORMATTING && $cat !== self::PHRASING &&
+ $node->tagName !== 'address' && $node->tagName !== 'div'
+ ) {
+ break;
+ }
+ }
- return HTML5::PLAINTEXT;
- break;
+ /* Finally, insert an HTML element with the same tag
+ name as the token's. */
+ $this->insertElement($token);
+ break;
- /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4",
- "h5", "h6" */
- case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
- /* If the stack of open elements has a p element in scope,
- then act as if an end tag with the tag name p had been seen. */
- if($this->elementInScope('p')) {
- $this->emitToken(array(
- 'name' => 'p',
- 'type' => HTML5::ENDTAG
- ));
- }
+ /* A start tag token whose tag name is "plaintext" */
+ case 'plaintext':
+ /* If the stack of open elements has a p element in scope,
+ then act as if an end tag with the tag name p had been
+ seen. */
+ if ($this->elementInScope('p')) {
+ $this->emitToken(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+ }
- /* If the stack of open elements has in scope an element whose
- tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
- this is a parse error; pop elements from the stack until an
- element with one of those tag names has been popped from the
- stack. */
- while($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) {
- array_pop($this->stack);
- }
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
- break;
+ return HTML5::PLAINTEXT;
+ break;
- /* A start tag whose tag name is "a" */
- case 'a':
- /* If the list of active formatting elements contains
- an element whose tag name is "a" between the end of the
- list and the last marker on the list (or the start of
- the list if there is no marker on the list), then this
- is a parse error; act as if an end tag with the tag name
- "a" had been seen, then remove that element from the list
- of active formatting elements and the stack of open
- elements if the end tag didn't already remove it (it
- might not have if the element is not in table scope). */
- $leng = count($this->a_formatting);
-
- for($n = $leng - 1; $n >= 0; $n--) {
- if($this->a_formatting[$n] === self::MARKER) {
- break;
-
- } elseif($this->a_formatting[$n]->nodeName === 'a') {
- $this->emitToken(array(
- 'name' => 'a',
- 'type' => HTML5::ENDTAG
- ));
- break;
+ /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4",
+ "h5", "h6" */
+ case 'h1':
+ case 'h2':
+ case 'h3':
+ case 'h4':
+ case 'h5':
+ case 'h6':
+ /* If the stack of open elements has a p element in scope,
+ then act as if an end tag with the tag name p had been seen. */
+ if ($this->elementInScope('p')) {
+ $this->emitToken(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::ENDTAG
+ )
+ );
}
- }
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ /* If the stack of open elements has in scope an element whose
+ tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
+ this is a parse error; pop elements from the stack until an
+ element with one of those tag names has been popped from the
+ stack. */
+ while ($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) {
+ array_pop($this->stack);
+ }
- /* Insert an HTML element for the token. */
- $el = $this->insertElement($token);
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
+ break;
- /* Add that element to the list of active formatting
- elements. */
- $this->a_formatting[] = $el;
- break;
+ /* A start tag whose tag name is "a" */
+ case 'a':
+ /* If the list of active formatting elements contains
+ an element whose tag name is "a" between the end of the
+ list and the last marker on the list (or the start of
+ the list if there is no marker on the list), then this
+ is a parse error; act as if an end tag with the tag name
+ "a" had been seen, then remove that element from the list
+ of active formatting elements and the stack of open
+ elements if the end tag didn't already remove it (it
+ might not have if the element is not in table scope). */
+ $leng = count($this->a_formatting);
+
+ for ($n = $leng - 1; $n >= 0; $n--) {
+ if ($this->a_formatting[$n] === self::MARKER) {
+ break;
- /* A start tag whose tag name is one of: "b", "big", "em", "font",
- "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
- case 'b': case 'big': case 'em': case 'font': case 'i':
- case 'nobr': case 's': case 'small': case 'strike':
- case 'strong': case 'tt': case 'u':
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ } elseif ($this->a_formatting[$n]->nodeName === 'a') {
+ $this->emitToken(
+ array(
+ 'name' => 'a',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+ break;
+ }
+ }
- /* Insert an HTML element for the token. */
- $el = $this->insertElement($token);
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
- /* Add that element to the list of active formatting
- elements. */
- $this->a_formatting[] = $el;
- break;
+ /* Insert an HTML element for the token. */
+ $el = $this->insertElement($token);
- /* A start tag token whose tag name is "button" */
- case 'button':
- /* If the stack of open elements has a button element in scope,
- then this is a parse error; act as if an end tag with the tag
- name "button" had been seen, then reprocess the token. (We don't
- do that. Unnecessary.) */
- if($this->elementInScope('button')) {
- $this->inBody(array(
- 'name' => 'button',
- 'type' => HTML5::ENDTAG
- ));
- }
+ /* Add that element to the list of active formatting
+ elements. */
+ $this->a_formatting[] = $el;
+ break;
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ /* A start tag whose tag name is one of: "b", "big", "em", "font",
+ "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
+ case 'b':
+ case 'big':
+ case 'em':
+ case 'font':
+ case 'i':
+ case 'nobr':
+ case 's':
+ case 'small':
+ case 'strike':
+ case 'strong':
+ case 'tt':
+ case 'u':
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
+
+ /* Insert an HTML element for the token. */
+ $el = $this->insertElement($token);
+
+ /* Add that element to the list of active formatting
+ elements. */
+ $this->a_formatting[] = $el;
+ break;
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
+ /* A start tag token whose tag name is "button" */
+ case 'button':
+ /* If the stack of open elements has a button element in scope,
+ then this is a parse error; act as if an end tag with the tag
+ name "button" had been seen, then reprocess the token. (We don't
+ do that. Unnecessary.) */
+ if ($this->elementInScope('button')) {
+ $this->inBody(
+ array(
+ 'name' => 'button',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+ }
- /* Insert a marker at the end of the list of active
- formatting elements. */
- $this->a_formatting[] = self::MARKER;
- break;
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
- /* A start tag token whose tag name is one of: "marquee", "object" */
- case 'marquee': case 'object':
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
+ /* Insert a marker at the end of the list of active
+ formatting elements. */
+ $this->a_formatting[] = self::MARKER;
+ break;
- /* Insert a marker at the end of the list of active
- formatting elements. */
- $this->a_formatting[] = self::MARKER;
- break;
+ /* A start tag token whose tag name is one of: "marquee", "object" */
+ case 'marquee':
+ case 'object':
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
- /* A start tag token whose tag name is "xmp" */
- case 'xmp':
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
+ /* Insert a marker at the end of the list of active
+ formatting elements. */
+ $this->a_formatting[] = self::MARKER;
+ break;
- /* Switch the content model flag to the CDATA state. */
- return HTML5::CDATA;
- break;
+ /* A start tag token whose tag name is "xmp" */
+ case 'xmp':
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
- /* A start tag whose tag name is "table" */
- case 'table':
- /* If the stack of open elements has a p element in scope,
- then act as if an end tag with the tag name p had been seen. */
- if($this->elementInScope('p')) {
- $this->emitToken(array(
- 'name' => 'p',
- 'type' => HTML5::ENDTAG
- ));
- }
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
+ /* Switch the content model flag to the CDATA state. */
+ return HTML5::CDATA;
+ break;
- /* Change the insertion mode to "in table". */
- $this->mode = self::IN_TABLE;
- break;
+ /* A start tag whose tag name is "table" */
+ case 'table':
+ /* If the stack of open elements has a p element in scope,
+ then act as if an end tag with the tag name p had been seen. */
+ if ($this->elementInScope('p')) {
+ $this->emitToken(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+ }
- /* A start tag whose tag name is one of: "area", "basefont",
- "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */
- case 'area': case 'basefont': case 'bgsound': case 'br':
- case 'embed': case 'img': case 'param': case 'spacer':
- case 'wbr':
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
+ /* Change the insertion mode to "in table". */
+ $this->mode = self::IN_TABLE;
+ break;
- /* Immediately pop the current node off the stack of open elements. */
- array_pop($this->stack);
- break;
+ /* A start tag whose tag name is one of: "area", "basefont",
+ "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */
+ case 'area':
+ case 'basefont':
+ case 'bgsound':
+ case 'br':
+ case 'embed':
+ case 'img':
+ case 'param':
+ case 'spacer':
+ case 'wbr':
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
+
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
+
+ /* Immediately pop the current node off the stack of open elements. */
+ array_pop($this->stack);
+ break;
- /* A start tag whose tag name is "hr" */
- case 'hr':
- /* If the stack of open elements has a p element in scope,
- then act as if an end tag with the tag name p had been seen. */
- if($this->elementInScope('p')) {
- $this->emitToken(array(
- 'name' => 'p',
- 'type' => HTML5::ENDTAG
- ));
- }
+ /* A start tag whose tag name is "hr" */
+ case 'hr':
+ /* If the stack of open elements has a p element in scope,
+ then act as if an end tag with the tag name p had been seen. */
+ if ($this->elementInScope('p')) {
+ $this->emitToken(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+ }
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
- /* Immediately pop the current node off the stack of open elements. */
- array_pop($this->stack);
- break;
+ /* Immediately pop the current node off the stack of open elements. */
+ array_pop($this->stack);
+ break;
- /* A start tag whose tag name is "image" */
- case 'image':
- /* Parse error. Change the token's tag name to "img" and
- reprocess it. (Don't ask.) */
- $token['name'] = 'img';
- return $this->inBody($token);
- break;
+ /* A start tag whose tag name is "image" */
+ case 'image':
+ /* Parse error. Change the token's tag name to "img" and
+ reprocess it. (Don't ask.) */
+ $token['name'] = 'img';
+ return $this->inBody($token);
+ break;
- /* A start tag whose tag name is "input" */
- case 'input':
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ /* A start tag whose tag name is "input" */
+ case 'input':
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
- /* Insert an input element for the token. */
- $element = $this->insertElement($token, false);
+ /* Insert an input element for the token. */
+ $element = $this->insertElement($token, false);
- /* If the form element pointer is not null, then associate the
- input element with the form element pointed to by the form
- element pointer. */
- $this->form_pointer !== null
- ? $this->form_pointer->appendChild($element)
- : end($this->stack)->appendChild($element);
+ /* If the form element pointer is not null, then associate the
+ input element with the form element pointed to by the form
+ element pointer. */
+ $this->form_pointer !== null
+ ? $this->form_pointer->appendChild($element)
+ : end($this->stack)->appendChild($element);
- /* Pop that input element off the stack of open elements. */
- array_pop($this->stack);
- break;
+ /* Pop that input element off the stack of open elements. */
+ array_pop($this->stack);
+ break;
- /* A start tag whose tag name is "isindex" */
- case 'isindex':
- /* Parse error. */
- // w/e
-
- /* If the form element pointer is not null,
- then ignore the token. */
- if($this->form_pointer === null) {
- /* Act as if a start tag token with the tag name "form" had
- been seen. */
- $this->inBody(array(
- 'name' => 'body',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
-
- /* Act as if a start tag token with the tag name "hr" had
- been seen. */
- $this->inBody(array(
- 'name' => 'hr',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
-
- /* Act as if a start tag token with the tag name "p" had
- been seen. */
- $this->inBody(array(
- 'name' => 'p',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
-
- /* Act as if a start tag token with the tag name "label"
- had been seen. */
- $this->inBody(array(
- 'name' => 'label',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
-
- /* Act as if a stream of character tokens had been seen. */
- $this->insertText('This is a searchable index. '.
- 'Insert your search keywords here: ');
-
- /* Act as if a start tag token with the tag name "input"
- had been seen, with all the attributes from the "isindex"
- token, except with the "name" attribute set to the value
- "isindex" (ignoring any explicit "name" attribute). */
- $attr = $token['attr'];
- $attr[] = array('name' => 'name', 'value' => 'isindex');
-
- $this->inBody(array(
- 'name' => 'input',
- 'type' => HTML5::STARTTAG,
- 'attr' => $attr
- ));
-
- /* Act as if a stream of character tokens had been seen
- (see below for what they should say). */
- $this->insertText('This is a searchable index. '.
- 'Insert your search keywords here: ');
-
- /* Act as if an end tag token with the tag name "label"
- had been seen. */
- $this->inBody(array(
- 'name' => 'label',
- 'type' => HTML5::ENDTAG
- ));
-
- /* Act as if an end tag token with the tag name "p" had
- been seen. */
- $this->inBody(array(
- 'name' => 'p',
- 'type' => HTML5::ENDTAG
- ));
-
- /* Act as if a start tag token with the tag name "hr" had
- been seen. */
- $this->inBody(array(
- 'name' => 'hr',
- 'type' => HTML5::ENDTAG
- ));
-
- /* Act as if an end tag token with the tag name "form" had
- been seen. */
- $this->inBody(array(
- 'name' => 'form',
- 'type' => HTML5::ENDTAG
- ));
- }
- break;
+ /* A start tag whose tag name is "isindex" */
+ case 'isindex':
+ /* Parse error. */
+ // w/e
- /* A start tag whose tag name is "textarea" */
- case 'textarea':
- $this->insertElement($token);
+ /* If the form element pointer is not null,
+ then ignore the token. */
+ if ($this->form_pointer === null) {
+ /* Act as if a start tag token with the tag name "form" had
+ been seen. */
+ $this->inBody(
+ array(
+ 'name' => 'body',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
+
+ /* Act as if a start tag token with the tag name "hr" had
+ been seen. */
+ $this->inBody(
+ array(
+ 'name' => 'hr',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
+
+ /* Act as if a start tag token with the tag name "p" had
+ been seen. */
+ $this->inBody(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
+
+ /* Act as if a start tag token with the tag name "label"
+ had been seen. */
+ $this->inBody(
+ array(
+ 'name' => 'label',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
+
+ /* Act as if a stream of character tokens had been seen. */
+ $this->insertText(
+ 'This is a searchable index. ' .
+ 'Insert your search keywords here: '
+ );
+
+ /* Act as if a start tag token with the tag name "input"
+ had been seen, with all the attributes from the "isindex"
+ token, except with the "name" attribute set to the value
+ "isindex" (ignoring any explicit "name" attribute). */
+ $attr = $token['attr'];
+ $attr[] = array('name' => 'name', 'value' => 'isindex');
+
+ $this->inBody(
+ array(
+ 'name' => 'input',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => $attr
+ )
+ );
+
+ /* Act as if a stream of character tokens had been seen
+ (see below for what they should say). */
+ $this->insertText(
+ 'This is a searchable index. ' .
+ 'Insert your search keywords here: '
+ );
+
+ /* Act as if an end tag token with the tag name "label"
+ had been seen. */
+ $this->inBody(
+ array(
+ 'name' => 'label',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+
+ /* Act as if an end tag token with the tag name "p" had
+ been seen. */
+ $this->inBody(
+ array(
+ 'name' => 'p',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+
+ /* Act as if a start tag token with the tag name "hr" had
+ been seen. */
+ $this->inBody(
+ array(
+ 'name' => 'hr',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+
+ /* Act as if an end tag token with the tag name "form" had
+ been seen. */
+ $this->inBody(
+ array(
+ 'name' => 'form',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+ }
+ break;
- /* Switch the tokeniser's content model flag to the
- RCDATA state. */
- return HTML5::RCDATA;
- break;
+ /* A start tag whose tag name is "textarea" */
+ case 'textarea':
+ $this->insertElement($token);
- /* A start tag whose tag name is one of: "iframe", "noembed",
- "noframes" */
- case 'iframe': case 'noembed': case 'noframes':
- $this->insertElement($token);
+ /* Switch the tokeniser's content model flag to the
+ RCDATA state. */
+ return HTML5::RCDATA;
+ break;
- /* Switch the tokeniser's content model flag to the CDATA state. */
- return HTML5::CDATA;
- break;
+ /* A start tag whose tag name is one of: "iframe", "noembed",
+ "noframes" */
+ case 'iframe':
+ case 'noembed':
+ case 'noframes':
+ $this->insertElement($token);
- /* A start tag whose tag name is "select" */
- case 'select':
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ /* Switch the tokeniser's content model flag to the CDATA state. */
+ return HTML5::CDATA;
+ break;
- /* Insert an HTML element for the token. */
- $this->insertElement($token);
+ /* A start tag whose tag name is "select" */
+ case 'select':
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
- /* Change the insertion mode to "in select". */
- $this->mode = self::IN_SELECT;
- break;
+ /* Insert an HTML element for the token. */
+ $this->insertElement($token);
- /* A start or end tag whose tag name is one of: "caption", "col",
- "colgroup", "frame", "frameset", "head", "option", "optgroup",
- "tbody", "td", "tfoot", "th", "thead", "tr". */
- case 'caption': case 'col': case 'colgroup': case 'frame':
- case 'frameset': case 'head': case 'option': case 'optgroup':
- case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead':
- case 'tr':
- // Parse error. Ignore the token.
- break;
+ /* Change the insertion mode to "in select". */
+ $this->mode = self::IN_SELECT;
+ break;
- /* A start or end tag whose tag name is one of: "event-source",
- "section", "nav", "article", "aside", "header", "footer",
- "datagrid", "command" */
- case 'event-source': case 'section': case 'nav': case 'article':
- case 'aside': case 'header': case 'footer': case 'datagrid':
- case 'command':
- // Work in progress!
- break;
+ /* A start or end tag whose tag name is one of: "caption", "col",
+ "colgroup", "frame", "frameset", "head", "option", "optgroup",
+ "tbody", "td", "tfoot", "th", "thead", "tr". */
+ case 'caption':
+ case 'col':
+ case 'colgroup':
+ case 'frame':
+ case 'frameset':
+ case 'head':
+ case 'option':
+ case 'optgroup':
+ case 'tbody':
+ case 'td':
+ case 'tfoot':
+ case 'th':
+ case 'thead':
+ case 'tr':
+ // Parse error. Ignore the token.
+ break;
- /* A start tag token not covered by the previous entries */
- default:
- /* Reconstruct the active formatting elements, if any. */
- $this->reconstructActiveFormattingElements();
+ /* A start or end tag whose tag name is one of: "event-source",
+ "section", "nav", "article", "aside", "header", "footer",
+ "datagrid", "command" */
+ case 'event-source':
+ case 'section':
+ case 'nav':
+ case 'article':
+ case 'aside':
+ case 'header':
+ case 'footer':
+ case 'datagrid':
+ case 'command':
+ // Work in progress!
+ break;
+
+ /* A start tag token not covered by the previous entries */
+ default:
+ /* Reconstruct the active formatting elements, if any. */
+ $this->reconstructActiveFormattingElements();
- $this->insertElement($token, true, true);
+ $this->insertElement($token, true, true);
+ break;
+ }
break;
- }
- break;
case HTML5::ENDTAG:
- switch($token['name']) {
- /* An end tag with the tag name "body" */
- case 'body':
- /* If the second element in the stack of open elements is
- not a body element, this is a parse error. Ignore the token.
- (innerHTML case) */
- if(count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') {
- // Ignore.
-
- /* If the current node is not the body element, then this
- is a parse error. */
- } elseif(end($this->stack)->nodeName !== 'body') {
- // Parse error.
- }
+ switch ($token['name']) {
+ /* An end tag with the tag name "body" */
+ case 'body':
+ /* If the second element in the stack of open elements is
+ not a body element, this is a parse error. Ignore the token.
+ (innerHTML case) */
+ if (count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') {
+ // Ignore.
+
+ /* If the current node is not the body element, then this
+ is a parse error. */
+ } elseif (end($this->stack)->nodeName !== 'body') {
+ // Parse error.
+ }
- /* Change the insertion mode to "after body". */
- $this->mode = self::AFTER_BODY;
- break;
+ /* Change the insertion mode to "after body". */
+ $this->mode = self::AFTER_BODY;
+ break;
- /* An end tag with the tag name "html" */
- case 'html':
- /* Act as if an end tag with tag name "body" had been seen,
- then, if that token wasn't ignored, reprocess the current
- token. */
- $this->inBody(array(
- 'name' => 'body',
- 'type' => HTML5::ENDTAG
- ));
+ /* An end tag with the tag name "html" */
+ case 'html':
+ /* Act as if an end tag with tag name "body" had been seen,
+ then, if that token wasn't ignored, reprocess the current
+ token. */
+ $this->inBody(
+ array(
+ 'name' => 'body',
+ 'type' => HTML5::ENDTAG
+ )
+ );
- return $this->afterBody($token);
- break;
+ return $this->afterBody($token);
+ break;
- /* An end tag whose tag name is one of: "address", "blockquote",
- "center", "dir", "div", "dl", "fieldset", "listing", "menu",
- "ol", "pre", "ul" */
- case 'address': case 'blockquote': case 'center': case 'dir':
- case 'div': case 'dl': case 'fieldset': case 'listing':
- case 'menu': case 'ol': case 'pre': case 'ul':
- /* If the stack of open elements has an element in scope
- with the same tag name as that of the token, then generate
- implied end tags. */
- if($this->elementInScope($token['name'])) {
- $this->generateImpliedEndTags();
-
- /* Now, if the current node is not an element with
- the same tag name as that of the token, then this
- is a parse error. */
- // w/e
+ /* An end tag whose tag name is one of: "address", "blockquote",
+ "center", "dir", "div", "dl", "fieldset", "listing", "menu",
+ "ol", "pre", "ul" */
+ case 'address':
+ case 'blockquote':
+ case 'center':
+ case 'dir':
+ case 'div':
+ case 'dl':
+ case 'fieldset':
+ case 'listing':
+ case 'menu':
+ case 'ol':
+ case 'pre':
+ case 'ul':
+ /* If the stack of open elements has an element in scope
+ with the same tag name as that of the token, then generate
+ implied end tags. */
+ if ($this->elementInScope($token['name'])) {
+ $this->generateImpliedEndTags();
- /* If the stack of open elements has an element in
- scope with the same tag name as that of the token,
- then pop elements from this stack until an element
- with that tag name has been popped from the stack. */
- for($n = count($this->stack) - 1; $n >= 0; $n--) {
- if($this->stack[$n]->nodeName === $token['name']) {
- $n = -1;
+ /* Now, if the current node is not an element with
+ the same tag name as that of the token, then this
+ is a parse error. */
+ // w/e
+
+ /* If the stack of open elements has an element in
+ scope with the same tag name as that of the token,
+ then pop elements from this stack until an element
+ with that tag name has been popped from the stack. */
+ for ($n = count($this->stack) - 1; $n >= 0; $n--) {
+ if ($this->stack[$n]->nodeName === $token['name']) {
+ $n = -1;
+ }
+
+ array_pop($this->stack);
}
+ }
+ break;
+
+ /* An end tag whose tag name is "form" */
+ case 'form':
+ /* If the stack of open elements has an element in scope
+ with the same tag name as that of the token, then generate
+ implied end tags. */
+ if ($this->elementInScope($token['name'])) {
+ $this->generateImpliedEndTags();
- array_pop($this->stack);
}
- }
- break;
- /* An end tag whose tag name is "form" */
- case 'form':
- /* If the stack of open elements has an element in scope
- with the same tag name as that of the token, then generate
- implied end tags. */
- if($this->elementInScope($token['name'])) {
- $this->generateImpliedEndTags();
+ if (end($this->stack)->nodeName !== $token['name']) {
+ /* Now, if the current node is not an element with the
+ same tag name as that of the token, then this is a parse
+ error. */
+ // w/e
- }
+ } else {
+ /* Otherwise, if the current node is an element with
+ the same tag name as that of the token pop that element
+ from the stack. */
+ array_pop($this->stack);
+ }
- if(end($this->stack)->nodeName !== $token['name']) {
- /* Now, if the current node is not an element with the
- same tag name as that of the token, then this is a parse
- error. */
- // w/e
+ /* In any case, set the form element pointer to null. */
+ $this->form_pointer = null;
+ break;
- } else {
- /* Otherwise, if the current node is an element with
- the same tag name as that of the token pop that element
- from the stack. */
- array_pop($this->stack);
- }
+ /* An end tag whose tag name is "p" */
+ case 'p':
+ /* If the stack of open elements has a p element in scope,
+ then generate implied end tags, except for p elements. */
+ if ($this->elementInScope('p')) {
+ $this->generateImpliedEndTags(array('p'));
- /* In any case, set the form element pointer to null. */
- $this->form_pointer = null;
- break;
+ /* If the current node is not a p element, then this is
+ a parse error. */
+ // k
- /* An end tag whose tag name is "p" */
- case 'p':
- /* If the stack of open elements has a p element in scope,
- then generate implied end tags, except for p elements. */
- if($this->elementInScope('p')) {
- $this->generateImpliedEndTags(array('p'));
-
- /* If the current node is not a p element, then this is
- a parse error. */
- // k
-
- /* If the stack of open elements has a p element in
- scope, then pop elements from this stack until the stack
- no longer has a p element in scope. */
- for($n = count($this->stack) - 1; $n >= 0; $n--) {
- if($this->elementInScope('p')) {
- array_pop($this->stack);
+ /* If the stack of open elements has a p element in
+ scope, then pop elements from this stack until the stack
+ no longer has a p element in scope. */
+ for ($n = count($this->stack) - 1; $n >= 0; $n--) {
+ if ($this->elementInScope('p')) {
+ array_pop($this->stack);
- } else {
- break;
+ } else {
+ break;
+ }
}
}
- }
- break;
-
- /* An end tag whose tag name is "dd", "dt", or "li" */
- case 'dd': case 'dt': case 'li':
- /* If the stack of open elements has an element in scope
- whose tag name matches the tag name of the token, then
- generate implied end tags, except for elements with the
- same tag name as the token. */
- if($this->elementInScope($token['name'])) {
- $this->generateImpliedEndTags(array($token['name']));
-
- /* If the current node is not an element with the same
- tag name as the token, then this is a parse error. */
- // w/e
+ break;
+ /* An end tag whose tag name is "dd", "dt", or "li" */
+ case 'dd':
+ case 'dt':
+ case 'li':
/* If the stack of open elements has an element in scope
whose tag name matches the tag name of the token, then
- pop elements from this stack until an element with that
- tag name has been popped from the stack. */
- for($n = count($this->stack) - 1; $n >= 0; $n--) {
- if($this->stack[$n]->nodeName === $token['name']) {
- $n = -1;
- }
+ generate implied end tags, except for elements with the
+ same tag name as the token. */
+ if ($this->elementInScope($token['name'])) {
+ $this->generateImpliedEndTags(array($token['name']));
+
+ /* If the current node is not an element with the same
+ tag name as the token, then this is a parse error. */
+ // w/e
+
+ /* If the stack of open elements has an element in scope
+ whose tag name matches the tag name of the token, then
+ pop elements from this stack until an element with that
+ tag name has been popped from the stack. */
+ for ($n = count($this->stack) - 1; $n >= 0; $n--) {
+ if ($this->stack[$n]->nodeName === $token['name']) {
+ $n = -1;
+ }
- array_pop($this->stack);
+ array_pop($this->stack);
+ }
}
- }
- break;
-
- /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4",
- "h5", "h6" */
- case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
- $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
+ break;
- /* If the stack of open elements has in scope an element whose
- tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
- generate implied end tags. */
- if($this->elementInScope($elements)) {
- $this->generateImpliedEndTags();
+ /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4",
+ "h5", "h6" */
+ case 'h1':
+ case 'h2':
+ case 'h3':
+ case 'h4':
+ case 'h5':
+ case 'h6':
+ $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
+
+ /* If the stack of open elements has in scope an element whose
+ tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
+ generate implied end tags. */
+ if ($this->elementInScope($elements)) {
+ $this->generateImpliedEndTags();
- /* Now, if the current node is not an element with the same
- tag name as that of the token, then this is a parse error. */
- // w/e
+ /* Now, if the current node is not an element with the same
+ tag name as that of the token, then this is a parse error. */
+ // w/e
- /* If the stack of open elements has in scope an element
- whose tag name is one of "h1", "h2", "h3", "h4", "h5", or
- "h6", then pop elements from the stack until an element
- with one of those tag names has been popped from the stack. */
- while($this->elementInScope($elements)) {
- array_pop($this->stack);
+ /* If the stack of open elements has in scope an element
+ whose tag name is one of "h1", "h2", "h3", "h4", "h5", or
+ "h6", then pop elements from the stack until an element
+ with one of those tag names has been popped from the stack. */
+ while ($this->elementInScope($elements)) {
+ array_pop($this->stack);
+ }
}
- }
- break;
+ break;
- /* An end tag whose tag name is one of: "a", "b", "big", "em",
- "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
- case 'a': case 'b': case 'big': case 'em': case 'font':
- case 'i': case 'nobr': case 's': case 'small': case 'strike':
- case 'strong': case 'tt': case 'u':
- /* 1. Let the formatting element be the last element in
- the list of active formatting elements that:
- * is between the end of the list and the last scope
- marker in the list, if any, or the start of the list
- otherwise, and
- * has the same tag name as the token.
- */
- while(true) {
- for($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
- if($this->a_formatting[$a] === self::MARKER) {
+ /* An end tag whose tag name is one of: "a", "b", "big", "em",
+ "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
+ case 'a':
+ case 'b':
+ case 'big':
+ case 'em':
+ case 'font':
+ case 'i':
+ case 'nobr':
+ case 's':
+ case 'small':
+ case 'strike':
+ case 'strong':
+ case 'tt':
+ case 'u':
+ /* 1. Let the formatting element be the last element in
+ the list of active formatting elements that:
+ * is between the end of the list and the last scope
+ marker in the list, if any, or the start of the list
+ otherwise, and
+ * has the same tag name as the token.
+ */
+ while (true) {
+ for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
+ if ($this->a_formatting[$a] === self::MARKER) {
+ break;
+
+ } elseif ($this->a_formatting[$a]->tagName === $token['name']) {
+ $formatting_element = $this->a_formatting[$a];
+ $in_stack = in_array($formatting_element, $this->stack, true);
+ $fe_af_pos = $a;
+ break;
+ }
+ }
+
+ /* If there is no such node, or, if that node is
+ also in the stack of open elements but the element
+ is not in scope, then this is a parse error. Abort
+ these steps. The token is ignored. */
+ if (!isset($formatting_element) || ($in_stack &&
+ !$this->elementInScope($token['name']))
+ ) {
break;
- } elseif($this->a_formatting[$a]->tagName === $token['name']) {
- $formatting_element = $this->a_formatting[$a];
- $in_stack = in_array($formatting_element, $this->stack, true);
- $fe_af_pos = $a;
+ /* Otherwise, if there is such a node, but that node
+ is not in the stack of open elements, then this is a
+ parse error; remove the element from the list, and
+ abort these steps. */
+ } elseif (isset($formatting_element) && !$in_stack) {
+ unset($this->a_formatting[$fe_af_pos]);
+ $this->a_formatting = array_merge($this->a_formatting);
break;
}
- }
-
- /* If there is no such node, or, if that node is
- also in the stack of open elements but the element
- is not in scope, then this is a parse error. Abort
- these steps. The token is ignored. */
- if(!isset($formatting_element) || ($in_stack &&
- !$this->elementInScope($token['name']))) {
- break;
-
- /* Otherwise, if there is such a node, but that node
- is not in the stack of open elements, then this is a
- parse error; remove the element from the list, and
- abort these steps. */
- } elseif(isset($formatting_element) && !$in_stack) {
- unset($this->a_formatting[$fe_af_pos]);
- $this->a_formatting = array_merge($this->a_formatting);
- break;
- }
- /* 2. Let the furthest block be the topmost node in the
- stack of open elements that is lower in the stack
- than the formatting element, and is not an element in
- the phrasing or formatting categories. There might
- not be one. */
- $fe_s_pos = array_search($formatting_element, $this->stack, true);
- $length = count($this->stack);
+ /* 2. Let the furthest block be the topmost node in the
+ stack of open elements that is lower in the stack
+ than the formatting element, and is not an element in
+ the phrasing or formatting categories. There might
+ not be one. */
+ $fe_s_pos = array_search($formatting_element, $this->stack, true);
+ $length = count($this->stack);
- for($s = $fe_s_pos + 1; $s < $length; $s++) {
- $category = $this->getElementCategory($this->stack[$s]->nodeName);
+ for ($s = $fe_s_pos + 1; $s < $length; $s++) {
+ $category = $this->getElementCategory($this->stack[$s]->nodeName);
- if($category !== self::PHRASING && $category !== self::FORMATTING) {
- $furthest_block = $this->stack[$s];
+ if ($category !== self::PHRASING && $category !== self::FORMATTING) {
+ $furthest_block = $this->stack[$s];
+ }
}
- }
- /* 3. If there is no furthest block, then the UA must
- skip the subsequent steps and instead just pop all
- the nodes from the bottom of the stack of open
- elements, from the current node up to the formatting
- element, and remove the formatting element from the
- list of active formatting elements. */
- if(!isset($furthest_block)) {
- for($n = $length - 1; $n >= $fe_s_pos; $n--) {
- array_pop($this->stack);
- }
+ /* 3. If there is no furthest block, then the UA must
+ skip the subsequent steps and instead just pop all
+ the nodes from the bottom of the stack of open
+ elements, from the current node up to the formatting
+ element, and remove the formatting element from the
+ list of active formatting elements. */
+ if (!isset($furthest_block)) {
+ for ($n = $length - 1; $n >= $fe_s_pos; $n--) {
+ array_pop($this->stack);
+ }
- unset($this->a_formatting[$fe_af_pos]);
- $this->a_formatting = array_merge($this->a_formatting);
- break;
- }
+ unset($this->a_formatting[$fe_af_pos]);
+ $this->a_formatting = array_merge($this->a_formatting);
+ break;
+ }
- /* 4. Let the common ancestor be the element
- immediately above the formatting element in the stack
- of open elements. */
- $common_ancestor = $this->stack[$fe_s_pos - 1];
+ /* 4. Let the common ancestor be the element
+ immediately above the formatting element in the stack
+ of open elements. */
+ $common_ancestor = $this->stack[$fe_s_pos - 1];
- /* 5. If the furthest block has a parent node, then
- remove the furthest block from its parent node. */
- if($furthest_block->parentNode !== null) {
- $furthest_block->parentNode->removeChild($furthest_block);
- }
+ /* 5. If the furthest block has a parent node, then
+ remove the furthest block from its parent node. */
+ if ($furthest_block->parentNode !== null) {
+ $furthest_block->parentNode->removeChild($furthest_block);
+ }
- /* 6. Let a bookmark note the position of the
- formatting element in the list of active formatting
- elements relative to the elements on either side
- of it in the list. */
- $bookmark = $fe_af_pos;
-
- /* 7. Let node and last node be the furthest block.
- Follow these steps: */
- $node = $furthest_block;
- $last_node = $furthest_block;
-
- while(true) {
- for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) {
- /* 7.1 Let node be the element immediately
- prior to node in the stack of open elements. */
- $node = $this->stack[$n];
-
- /* 7.2 If node is not in the list of active
- formatting elements, then remove node from
- the stack of open elements and then go back
- to step 1. */
- if(!in_array($node, $this->a_formatting, true)) {
- unset($this->stack[$n]);
- $this->stack = array_merge($this->stack);
+ /* 6. Let a bookmark note the position of the
+ formatting element in the list of active formatting
+ elements relative to the elements on either side
+ of it in the list. */
+ $bookmark = $fe_af_pos;
+
+ /* 7. Let node and last node be the furthest block.
+ Follow these steps: */
+ $node = $furthest_block;
+ $last_node = $furthest_block;
+
+ while (true) {
+ for ($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) {
+ /* 7.1 Let node be the element immediately
+ prior to node in the stack of open elements. */
+ $node = $this->stack[$n];
+
+ /* 7.2 If node is not in the list of active
+ formatting elements, then remove node from
+ the stack of open elements and then go back
+ to step 1. */
+ if (!in_array($node, $this->a_formatting, true)) {
+ unset($this->stack[$n]);
+ $this->stack = array_merge($this->stack);
+
+ } else {
+ break;
+ }
+ }
- } else {
+ /* 7.3 Otherwise, if node is the formatting
+ element, then go to the next step in the overall
+ algorithm. */
+ if ($node === $formatting_element) {
break;
+
+ /* 7.4 Otherwise, if last node is the furthest
+ block, then move the aforementioned bookmark to
+ be immediately after the node in the list of
+ active formatting elements. */
+ } elseif ($last_node === $furthest_block) {
+ $bookmark = array_search($node, $this->a_formatting, true) + 1;
}
- }
- /* 7.3 Otherwise, if node is the formatting
- element, then go to the next step in the overall
- algorithm. */
- if($node === $formatting_element) {
- break;
+ /* 7.5 If node has any children, perform a
+ shallow clone of node, replace the entry for
+ node in the list of active formatting elements
+ with an entry for the clone, replace the entry
+ for node in the stack of open elements with an
+ entry for the clone, and let node be the clone. */
+ if ($node->hasChildNodes()) {
+ $clone = $node->cloneNode();
+ $s_pos = array_search($node, $this->stack, true);
+ $a_pos = array_search($node, $this->a_formatting, true);
+
+ $this->stack[$s_pos] = $clone;
+ $this->a_formatting[$a_pos] = $clone;
+ $node = $clone;
+ }
- /* 7.4 Otherwise, if last node is the furthest
- block, then move the aforementioned bookmark to
- be immediately after the node in the list of
- active formatting elements. */
- } elseif($last_node === $furthest_block) {
- $bookmark = array_search($node, $this->a_formatting, true) + 1;
- }
+ /* 7.6 Insert last node into node, first removing
+ it from its previous parent node if any. */
+ if ($last_node->parentNode !== null) {
+ $last_node->parentNode->removeChild($last_node);
+ }
+
+ $node->appendChild($last_node);
- /* 7.5 If node has any children, perform a
- shallow clone of node, replace the entry for
- node in the list of active formatting elements
- with an entry for the clone, replace the entry
- for node in the stack of open elements with an
- entry for the clone, and let node be the clone. */
- if($node->hasChildNodes()) {
- $clone = $node->cloneNode();
- $s_pos = array_search($node, $this->stack, true);
- $a_pos = array_search($node, $this->a_formatting, true);
-
- $this->stack[$s_pos] = $clone;
- $this->a_formatting[$a_pos] = $clone;
- $node = $clone;
+ /* 7.7 Let last node be node. */
+ $last_node = $node;
}
- /* 7.6 Insert last node into node, first removing
- it from its previous parent node if any. */
- if($last_node->parentNode !== null) {
+ /* 8. Insert whatever last node ended up being in
+ the previous step into the common ancestor node,
+ first removing it from its previous parent node if
+ any. */
+ if ($last_node->parentNode !== null) {
$last_node->parentNode->removeChild($last_node);
}
- $node->appendChild($last_node);
+ $common_ancestor->appendChild($last_node);
- /* 7.7 Let last node be node. */
- $last_node = $node;
- }
+ /* 9. Perform a shallow clone of the formatting
+ element. */
+ $clone = $formatting_element->cloneNode();
- /* 8. Insert whatever last node ended up being in
- the previous step into the common ancestor node,
- first removing it from its previous parent node if
- any. */
- if($last_node->parentNode !== null) {
- $last_node->parentNode->removeChild($last_node);
- }
+ /* 10. Take all of the child nodes of the furthest
+ block and append them to the clone created in the
+ last step. */
+ while ($furthest_block->hasChildNodes()) {
+ $child = $furthest_block->firstChild;
+ $furthest_block->removeChild($child);
+ $clone->appendChild($child);
+ }
- $common_ancestor->appendChild($last_node);
+ /* 11. Append that clone to the furthest block. */
+ $furthest_block->appendChild($clone);
- /* 9. Perform a shallow clone of the formatting
- element. */
- $clone = $formatting_element->cloneNode();
+ /* 12. Remove the formatting element from the list
+ of active formatting elements, and insert the clone
+ into the list of active formatting elements at the
+ position of the aforementioned bookmark. */
+ $fe_af_pos = array_search($formatting_element, $this->a_formatting, true);
+ unset($this->a_formatting[$fe_af_pos]);
+ $this->a_formatting = array_merge($this->a_formatting);
- /* 10. Take all of the child nodes of the furthest
- block and append them to the clone created in the
- last step. */
- while($furthest_block->hasChildNodes()) {
- $child = $furthest_block->firstChild;
- $furthest_block->removeChild($child);
- $clone->appendChild($child);
+ $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
+ $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting));
+ $this->a_formatting = array_merge($af_part1, array($clone), $af_part2);
+
+ /* 13. Remove the formatting element from the stack
+ of open elements, and insert the clone into the stack
+ of open elements immediately after (i.e. in a more
+ deeply nested position than) the position of the
+ furthest block in that stack. */
+ $fe_s_pos = array_search($formatting_element, $this->stack, true);
+ $fb_s_pos = array_search($furthest_block, $this->stack, true);
+ unset($this->stack[$fe_s_pos]);
+
+ $s_part1 = array_slice($this->stack, 0, $fb_s_pos);
+ $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack));
+ $this->stack = array_merge($s_part1, array($clone), $s_part2);
+
+ /* 14. Jump back to step 1 in this series of steps. */
+ unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
}
+ break;
- /* 11. Append that clone to the furthest block. */
- $furthest_block->appendChild($clone);
-
- /* 12. Remove the formatting element from the list
- of active formatting elements, and insert the clone
- into the list of active formatting elements at the
- position of the aforementioned bookmark. */
- $fe_af_pos = array_search($formatting_element, $this->a_formatting, true);
- unset($this->a_formatting[$fe_af_pos]);
- $this->a_formatting = array_merge($this->a_formatting);
-
- $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
- $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting));
- $this->a_formatting = array_merge($af_part1, array($clone), $af_part2);
-
- /* 13. Remove the formatting element from the stack
- of open elements, and insert the clone into the stack
- of open elements immediately after (i.e. in a more
- deeply nested position than) the position of the
- furthest block in that stack. */
- $fe_s_pos = array_search($formatting_element, $this->stack, true);
- $fb_s_pos = array_search($furthest_block, $this->stack, true);
- unset($this->stack[$fe_s_pos]);
-
- $s_part1 = array_slice($this->stack, 0, $fb_s_pos);
- $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack));
- $this->stack = array_merge($s_part1, array($clone), $s_part2);
-
- /* 14. Jump back to step 1 in this series of steps. */
- unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
- }
- break;
+ /* An end tag token whose tag name is one of: "button",
+ "marquee", "object" */
+ case 'button':
+ case 'marquee':
+ case 'object':
+ /* If the stack of open elements has an element in scope whose
+ tag name matches the tag name of the token, then generate implied
+ tags. */
+ if ($this->elementInScope($token['name'])) {
+ $this->generateImpliedEndTags();
- /* An end tag token whose tag name is one of: "button",
- "marquee", "object" */
- case 'button': case 'marquee': case 'object':
- /* If the stack of open elements has an element in scope whose
- tag name matches the tag name of the token, then generate implied
- tags. */
- if($this->elementInScope($token['name'])) {
- $this->generateImpliedEndTags();
-
- /* Now, if the current node is not an element with the same
- tag name as the token, then this is a parse error. */
- // k
-
- /* Now, if the stack of open elements has an element in scope
- whose tag name matches the tag name of the token, then pop
- elements from the stack until that element has been popped from
- the stack, and clear the list of active formatting elements up
- to the last marker. */
- for($n = count($this->stack) - 1; $n >= 0; $n--) {
- if($this->stack[$n]->nodeName === $token['name']) {
- $n = -1;
- }
+ /* Now, if the current node is not an element with the same
+ tag name as the token, then this is a parse error. */
+ // k
- array_pop($this->stack);
- }
+ /* Now, if the stack of open elements has an element in scope
+ whose tag name matches the tag name of the token, then pop
+ elements from the stack until that element has been popped from
+ the stack, and clear the list of active formatting elements up
+ to the last marker. */
+ for ($n = count($this->stack) - 1; $n >= 0; $n--) {
+ if ($this->stack[$n]->nodeName === $token['name']) {
+ $n = -1;
+ }
- $marker = end(array_keys($this->a_formatting, self::MARKER, true));
+ array_pop($this->stack);
+ }
- for($n = count($this->a_formatting) - 1; $n > $marker; $n--) {
- array_pop($this->a_formatting);
- }
- }
- break;
+ $marker = end(array_keys($this->a_formatting, self::MARKER, true));
- /* Or an end tag whose tag name is one of: "area", "basefont",
- "bgsound", "br", "embed", "hr", "iframe", "image", "img",
- "input", "isindex", "noembed", "noframes", "param", "select",
- "spacer", "table", "textarea", "wbr" */
- case 'area': case 'basefont': case 'bgsound': case 'br':
- case 'embed': case 'hr': case 'iframe': case 'image':
- case 'img': case 'input': case 'isindex': case 'noembed':
- case 'noframes': case 'param': case 'select': case 'spacer':
- case 'table': case 'textarea': case 'wbr':
- // Parse error. Ignore the token.
- break;
+ for ($n = count($this->a_formatting) - 1; $n > $marker; $n--) {
+ array_pop($this->a_formatting);
+ }
+ }
+ break;
- /* An end tag token not covered by the previous entries */
- default:
- for($n = count($this->stack) - 1; $n >= 0; $n--) {
- /* Initialise node to be the current node (the bottommost
- node of the stack). */
- $node = end($this->stack);
-
- /* If node has the same tag name as the end tag token,
- then: */
- if($token['name'] === $node->nodeName) {
- /* Generate implied end tags. */
- $this->generateImpliedEndTags();
+ /* Or an end tag whose tag name is one of: "area", "basefont",
+ "bgsound", "br", "embed", "hr", "iframe", "image", "img",
+ "input", "isindex", "noembed", "noframes", "param", "select",
+ "spacer", "table", "textarea", "wbr" */
+ case 'area':
+ case 'basefont':
+ case 'bgsound':
+ case 'br':
+ case 'embed':
+ case 'hr':
+ case 'iframe':
+ case 'image':
+ case 'img':
+ case 'input':
+ case 'isindex':
+ case 'noembed':
+ case 'noframes':
+ case 'param':
+ case 'select':
+ case 'spacer':
+ case 'table':
+ case 'textarea':
+ case 'wbr':
+ // Parse error. Ignore the token.
+ break;
- /* If the tag name of the end tag token does not
- match the tag name of the current node, this is a
- parse error. */
- // k
+ /* An end tag token not covered by the previous entries */
+ default:
+ for ($n = count($this->stack) - 1; $n >= 0; $n--) {
+ /* Initialise node to be the current node (the bottommost
+ node of the stack). */
+ $node = end($this->stack);
+
+ /* If node has the same tag name as the end tag token,
+ then: */
+ if ($token['name'] === $node->nodeName) {
+ /* Generate implied end tags. */
+ $this->generateImpliedEndTags();
+
+ /* If the tag name of the end tag token does not
+ match the tag name of the current node, this is a
+ parse error. */
+ // k
+
+ /* Pop all the nodes from the current node up to
+ node, including node, then stop this algorithm. */
+ for ($x = count($this->stack) - $n; $x >= $n; $x--) {
+ array_pop($this->stack);
+ }
- /* Pop all the nodes from the current node up to
- node, including node, then stop this algorithm. */
- for($x = count($this->stack) - $n; $x >= $n; $x--) {
- array_pop($this->stack);
- }
-
- } else {
- $category = $this->getElementCategory($node);
-
- if($category !== self::SPECIAL && $category !== self::SCOPING) {
- /* Otherwise, if node is in neither the formatting
- category nor the phrasing category, then this is a
- parse error. Stop this algorithm. The end tag token
- is ignored. */
- return false;
+ } else {
+ $category = $this->getElementCategory($node);
+
+ if ($category !== self::SPECIAL && $category !== self::SCOPING) {
+ /* Otherwise, if node is in neither the formatting
+ category nor the phrasing category, then this is a
+ parse error. Stop this algorithm. The end tag token
+ is ignored. */
+ return false;
+ }
}
}
- }
+ break;
+ }
break;
- }
- break;
}
}
- private function inTable($token) {
+ private function inTable($token)
+ {
$clear = array('html', 'table');
/* A character token that is one of one of U+0009 CHARACTER TABULATION,
U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
or U+0020 SPACE */
- if($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ if ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Append the character to the current node. */
$text = $this->dom->createTextNode($token['data']);
end($this->stack)->appendChild($text);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the current node with the data
attribute set to the data given in the comment token. */
$comment = $this->dom->createComment($token['data']);
end($this->stack)->appendChild($comment);
- /* A start tag whose tag name is "caption" */
- } elseif($token['type'] === HTML5::STARTTAG &&
- $token['name'] === 'caption') {
+ /* A start tag whose tag name is "caption" */
+ } elseif ($token['type'] === HTML5::STARTTAG &&
+ $token['name'] === 'caption'
+ ) {
/* Clear the stack back to a table context. */
$this->clearStackToTableContext($clear);
@@ -2663,9 +3350,10 @@ class HTML5TreeConstructer {
$this->insertElement($token);
$this->mode = self::IN_CAPTION;
- /* A start tag whose tag name is "colgroup" */
- } elseif($token['type'] === HTML5::STARTTAG &&
- $token['name'] === 'colgroup') {
+ /* A start tag whose tag name is "colgroup" */
+ } elseif ($token['type'] === HTML5::STARTTAG &&
+ $token['name'] === 'colgroup'
+ ) {
/* Clear the stack back to a table context. */
$this->clearStackToTableContext($clear);
@@ -2674,20 +3362,26 @@ class HTML5TreeConstructer {
$this->insertElement($token);
$this->mode = self::IN_CGROUP;
- /* A start tag whose tag name is "col" */
- } elseif($token['type'] === HTML5::STARTTAG &&
- $token['name'] === 'col') {
- $this->inTable(array(
- 'name' => 'colgroup',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
+ /* A start tag whose tag name is "col" */
+ } elseif ($token['type'] === HTML5::STARTTAG &&
+ $token['name'] === 'col'
+ ) {
+ $this->inTable(
+ array(
+ 'name' => 'colgroup',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
$this->inColumnGroup($token);
- /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */
- } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
- array('tbody', 'tfoot', 'thead'))) {
+ /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */
+ } elseif ($token['type'] === HTML5::STARTTAG && in_array(
+ $token['name'],
+ array('tbody', 'tfoot', 'thead')
+ )
+ ) {
/* Clear the stack back to a table context. */
$this->clearStackToTableContext($clear);
@@ -2696,42 +3390,49 @@ class HTML5TreeConstructer {
$this->insertElement($token);
$this->mode = self::IN_TBODY;
- /* A start tag whose tag name is one of: "td", "th", "tr" */
- } elseif($token['type'] === HTML5::STARTTAG &&
- in_array($token['name'], array('td', 'th', 'tr'))) {
+ /* A start tag whose tag name is one of: "td", "th", "tr" */
+ } elseif ($token['type'] === HTML5::STARTTAG &&
+ in_array($token['name'], array('td', 'th', 'tr'))
+ ) {
/* Act as if a start tag token with the tag name "tbody" had been
seen, then reprocess the current token. */
- $this->inTable(array(
- 'name' => 'tbody',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
+ $this->inTable(
+ array(
+ 'name' => 'tbody',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
return $this->inTableBody($token);
- /* A start tag whose tag name is "table" */
- } elseif($token['type'] === HTML5::STARTTAG &&
- $token['name'] === 'table') {
+ /* A start tag whose tag name is "table" */
+ } elseif ($token['type'] === HTML5::STARTTAG &&
+ $token['name'] === 'table'
+ ) {
/* Parse error. Act as if an end tag token with the tag name "table"
had been seen, then, if that token wasn't ignored, reprocess the
current token. */
- $this->inTable(array(
- 'name' => 'table',
- 'type' => HTML5::ENDTAG
- ));
+ $this->inTable(
+ array(
+ 'name' => 'table',
+ 'type' => HTML5::ENDTAG
+ )
+ );
return $this->mainPhase($token);
- /* An end tag whose tag name is "table" */
- } elseif($token['type'] === HTML5::ENDTAG &&
- $token['name'] === 'table') {
+ /* An end tag whose tag name is "table" */
+ } elseif ($token['type'] === HTML5::ENDTAG &&
+ $token['name'] === 'table'
+ ) {
/* If the stack of open elements does not have an element in table
scope with the same tag name as the token, this is a parse error.
Ignore the token. (innerHTML case) */
- if(!$this->elementInScope($token['name'], true)) {
+ if (!$this->elementInScope($token['name'], true)) {
return false;
- /* Otherwise: */
+ /* Otherwise: */
} else {
/* Generate implied end tags. */
$this->generateImpliedEndTags();
@@ -2742,11 +3443,11 @@ class HTML5TreeConstructer {
/* Pop elements from this stack until a table element has been
popped from the stack. */
- while(true) {
+ while (true) {
$current = end($this->stack)->nodeName;
array_pop($this->stack);
- if($current === 'table') {
+ if ($current === 'table') {
break;
}
}
@@ -2755,14 +3456,28 @@ class HTML5TreeConstructer {
$this->resetInsertionMode();
}
- /* An end tag whose tag name is one of: "body", "caption", "col",
- "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
- } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
- array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td',
- 'tfoot', 'th', 'thead', 'tr'))) {
+ /* An end tag whose tag name is one of: "body", "caption", "col",
+ "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
+ } elseif ($token['type'] === HTML5::ENDTAG && in_array(
+ $token['name'],
+ array(
+ 'body',
+ 'caption',
+ 'col',
+ 'colgroup',
+ 'html',
+ 'tbody',
+ 'td',
+ 'tfoot',
+ 'th',
+ 'thead',
+ 'tr'
+ )
+ )
+ ) {
// Parse error. Ignore the token.
- /* Anything else */
+ /* Anything else */
} else {
/* Parse error. Process the token as if the insertion mode was "in
body", with the following exception: */
@@ -2770,8 +3485,11 @@ class HTML5TreeConstructer {
/* If the current node is a table, tbody, tfoot, thead, or tr
element, then, whenever a node would be inserted into the current
node, it must instead be inserted into the foster parent element. */
- if(in_array(end($this->stack)->nodeName,
- array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
+ if (in_array(
+ end($this->stack)->nodeName,
+ array('table', 'tbody', 'tfoot', 'thead', 'tr')
+ )
+ ) {
/* The foster parent element is the parent element of the last
table element in the stack of open elements, if there is a
table element and it has such a parent element. If there is no
@@ -2783,21 +3501,22 @@ class HTML5TreeConstructer {
its parent node is not an element, then the foster parent
element is the element before the last table element in the
stack of open elements. */
- for($n = count($this->stack) - 1; $n >= 0; $n--) {
- if($this->stack[$n]->nodeName === 'table') {
+ for ($n = count($this->stack) - 1; $n >= 0; $n--) {
+ if ($this->stack[$n]->nodeName === 'table') {
$table = $this->stack[$n];
break;
}
}
- if(isset($table) && $table->parentNode !== null) {
+ if (isset($table) && $table->parentNode !== null) {
$this->foster_parent = $table->parentNode;
- } elseif(!isset($table)) {
+ } elseif (!isset($table)) {
$this->foster_parent = $this->stack[0];
- } elseif(isset($table) && ($table->parentNode === null ||
- $table->parentNode->nodeType !== XML_ELEMENT_NODE)) {
+ } elseif (isset($table) && ($table->parentNode === null ||
+ $table->parentNode->nodeType !== XML_ELEMENT_NODE)
+ ) {
$this->foster_parent = $this->stack[$n - 1];
}
}
@@ -2806,16 +3525,17 @@ class HTML5TreeConstructer {
}
}
- private function inCaption($token) {
+ private function inCaption($token)
+ {
/* An end tag whose tag name is "caption" */
- if($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') {
+ if ($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') {
/* If the stack of open elements does not have an element in table
scope with the same tag name as the token, this is a parse error.
Ignore the token. (innerHTML case) */
- if(!$this->elementInScope($token['name'], true)) {
+ if (!$this->elementInScope($token['name'], true)) {
// Ignore
- /* Otherwise: */
+ /* Otherwise: */
} else {
/* Generate implied end tags. */
$this->generateImpliedEndTags();
@@ -2826,11 +3546,11 @@ class HTML5TreeConstructer {
/* Pop elements from this stack until a caption element has
been popped from the stack. */
- while(true) {
+ while (true) {
$node = end($this->stack)->nodeName;
array_pop($this->stack);
- if($node === 'caption') {
+ if ($node === 'caption') {
break;
}
}
@@ -2843,99 +3563,131 @@ class HTML5TreeConstructer {
$this->mode = self::IN_TABLE;
}
- /* A start tag whose tag name is one of: "caption", "col", "colgroup",
- "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag
- name is "table" */
- } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'],
- array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
- 'thead', 'tr'))) || ($token['type'] === HTML5::ENDTAG &&
- $token['name'] === 'table')) {
+ /* A start tag whose tag name is one of: "caption", "col", "colgroup",
+ "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag
+ name is "table" */
+ } elseif (($token['type'] === HTML5::STARTTAG && in_array(
+ $token['name'],
+ array(
+ 'caption',
+ 'col',
+ 'colgroup',
+ 'tbody',
+ 'td',
+ 'tfoot',
+ 'th',
+ 'thead',
+ 'tr'
+ )
+ )) || ($token['type'] === HTML5::ENDTAG &&
+ $token['name'] === 'table')
+ ) {
/* Parse error. Act as if an end tag with the tag name "caption"
had been seen, then, if that token wasn't ignored, reprocess the
current token. */
- $this->inCaption(array(
- 'name' => 'caption',
- 'type' => HTML5::ENDTAG
- ));
+ $this->inCaption(
+ array(
+ 'name' => 'caption',
+ 'type' => HTML5::ENDTAG
+ )
+ );
return $this->inTable($token);
- /* An end tag whose tag name is one of: "body", "col", "colgroup",
- "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
- } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
- array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th',
- 'thead', 'tr'))) {
+ /* An end tag whose tag name is one of: "body", "col", "colgroup",
+ "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
+ } elseif ($token['type'] === HTML5::ENDTAG && in_array(
+ $token['name'],
+ array(
+ 'body',
+ 'col',
+ 'colgroup',
+ 'html',
+ 'tbody',
+ 'tfoot',
+ 'th',
+ 'thead',
+ 'tr'
+ )
+ )
+ ) {
// Parse error. Ignore the token.
- /* Anything else */
+ /* Anything else */
} else {
/* Process the token as if the insertion mode was "in body". */
$this->inBody($token);
}
}
- private function inColumnGroup($token) {
+ private function inColumnGroup($token)
+ {
/* A character token that is one of one of U+0009 CHARACTER TABULATION,
U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
or U+0020 SPACE */
- if($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ if ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Append the character to the current node. */
$text = $this->dom->createTextNode($token['data']);
end($this->stack)->appendChild($text);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the current node with the data
attribute set to the data given in the comment token. */
$comment = $this->dom->createComment($token['data']);
end($this->stack)->appendChild($comment);
- /* A start tag whose tag name is "col" */
- } elseif($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') {
+ /* A start tag whose tag name is "col" */
+ } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') {
/* Insert a col element for the token. Immediately pop the current
node off the stack of open elements. */
$this->insertElement($token);
array_pop($this->stack);
- /* An end tag whose tag name is "colgroup" */
- } elseif($token['type'] === HTML5::ENDTAG &&
- $token['name'] === 'colgroup') {
+ /* An end tag whose tag name is "colgroup" */
+ } elseif ($token['type'] === HTML5::ENDTAG &&
+ $token['name'] === 'colgroup'
+ ) {
/* If the current node is the root html element, then this is a
parse error, ignore the token. (innerHTML case) */
- if(end($this->stack)->nodeName === 'html') {
+ if (end($this->stack)->nodeName === 'html') {
// Ignore
- /* Otherwise, pop the current node (which will be a colgroup
- element) from the stack of open elements. Switch the insertion
- mode to "in table". */
+ /* Otherwise, pop the current node (which will be a colgroup
+ element) from the stack of open elements. Switch the insertion
+ mode to "in table". */
} else {
array_pop($this->stack);
$this->mode = self::IN_TABLE;
}
- /* An end tag whose tag name is "col" */
- } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') {
+ /* An end tag whose tag name is "col" */
+ } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') {
/* Parse error. Ignore the token. */
- /* Anything else */
+ /* Anything else */
} else {
/* Act as if an end tag with the tag name "colgroup" had been seen,
and then, if that token wasn't ignored, reprocess the current token. */
- $this->inColumnGroup(array(
- 'name' => 'colgroup',
- 'type' => HTML5::ENDTAG
- ));
+ $this->inColumnGroup(
+ array(
+ 'name' => 'colgroup',
+ 'type' => HTML5::ENDTAG
+ )
+ );
return $this->inTable($token);
}
}
- private function inTableBody($token) {
+ private function inTableBody($token)
+ {
$clear = array('tbody', 'tfoot', 'thead', 'html');
/* A start tag whose tag name is "tr" */
- if($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') {
+ if ($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') {
/* Clear the stack back to a table body context. */
$this->clearStackToTableContext($clear);
@@ -2944,29 +3696,33 @@ class HTML5TreeConstructer {
$this->insertElement($token);
$this->mode = self::IN_ROW;
- /* A start tag whose tag name is one of: "th", "td" */
- } elseif($token['type'] === HTML5::STARTTAG &&
- ($token['name'] === 'th' || $token['name'] === 'td')) {
+ /* A start tag whose tag name is one of: "th", "td" */
+ } elseif ($token['type'] === HTML5::STARTTAG &&
+ ($token['name'] === 'th' || $token['name'] === 'td')
+ ) {
/* Parse error. Act as if a start tag with the tag name "tr" had
been seen, then reprocess the current token. */
- $this->inTableBody(array(
- 'name' => 'tr',
- 'type' => HTML5::STARTTAG,
- 'attr' => array()
- ));
+ $this->inTableBody(
+ array(
+ 'name' => 'tr',
+ 'type' => HTML5::STARTTAG,
+ 'attr' => array()
+ )
+ );
return $this->inRow($token);
- /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
- } elseif($token['type'] === HTML5::ENDTAG &&
- in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
+ /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
+ } elseif ($token['type'] === HTML5::ENDTAG &&
+ in_array($token['name'], array('tbody', 'tfoot', 'thead'))
+ ) {
/* If the stack of open elements does not have an element in table
scope with the same tag name as the token, this is a parse error.
Ignore the token. */
- if(!$this->elementInScope($token['name'], true)) {
+ if (!$this->elementInScope($token['name'], true)) {
// Ignore
- /* Otherwise: */
+ /* Otherwise: */
} else {
/* Clear the stack back to a table body context. */
$this->clearStackToTableContext($clear);
@@ -2977,18 +3733,21 @@ class HTML5TreeConstructer {
$this->mode = self::IN_TABLE;
}
- /* A start tag whose tag name is one of: "caption", "col", "colgroup",
- "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */
- } elseif(($token['type'] === HTML5::STARTTAG && in_array($token['name'],
- array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead'))) ||
- ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')) {
+ /* A start tag whose tag name is one of: "caption", "col", "colgroup",
+ "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */
+ } elseif (($token['type'] === HTML5::STARTTAG && in_array(
+ $token['name'],
+ array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead')
+ )) ||
+ ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table')
+ ) {
/* If the stack of open elements does not have a tbody, thead, or
tfoot element in table scope, this is a parse error. Ignore the
token. (innerHTML case) */
- if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) {
+ if (!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) {
// Ignore.
- /* Otherwise: */
+ /* Otherwise: */
} else {
/* Clear the stack back to a table body context. */
$this->clearStackToTableContext($clear);
@@ -2996,33 +3755,40 @@ class HTML5TreeConstructer {
/* Act as if an end tag with the same tag name as the current
node ("tbody", "tfoot", or "thead") had been seen, then
reprocess the current token. */
- $this->inTableBody(array(
- 'name' => end($this->stack)->nodeName,
- 'type' => HTML5::ENDTAG
- ));
+ $this->inTableBody(
+ array(
+ 'name' => end($this->stack)->nodeName,
+ 'type' => HTML5::ENDTAG
+ )
+ );
return $this->mainPhase($token);
}
- /* An end tag whose tag name is one of: "body", "caption", "col",
- "colgroup", "html", "td", "th", "tr" */
- } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
- array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) {
+ /* An end tag whose tag name is one of: "body", "caption", "col",
+ "colgroup", "html", "td", "th", "tr" */
+ } elseif ($token['type'] === HTML5::ENDTAG && in_array(
+ $token['name'],
+ array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr')
+ )
+ ) {
/* Parse error. Ignore the token. */
- /* Anything else */
+ /* Anything else */
} else {
/* Process the token as if the insertion mode was "in table". */
$this->inTable($token);
}
}
- private function inRow($token) {
+ private function inRow($token)
+ {
$clear = array('tr', 'html');
/* A start tag whose tag name is one of: "th", "td" */
- if($token['type'] === HTML5::STARTTAG &&
- ($token['name'] === 'th' || $token['name'] === 'td')) {
+ if ($token['type'] === HTML5::STARTTAG &&
+ ($token['name'] === 'th' || $token['name'] === 'td')
+ ) {
/* Clear the stack back to a table row context. */
$this->clearStackToTableContext($clear);
@@ -3035,15 +3801,15 @@ class HTML5TreeConstructer {
elements. */
$this->a_formatting[] = self::MARKER;
- /* An end tag whose tag name is "tr" */
- } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') {
+ /* An end tag whose tag name is "tr" */
+ } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') {
/* If the stack of open elements does not have an element in table
scope with the same tag name as the token, this is a parse error.
Ignore the token. (innerHTML case) */
- if(!$this->elementInScope($token['name'], true)) {
+ if (!$this->elementInScope($token['name'], true)) {
// Ignore.
- /* Otherwise: */
+ /* Otherwise: */
} else {
/* Clear the stack back to a table row context. */
$this->clearStackToTableContext($clear);
@@ -3055,64 +3821,77 @@ class HTML5TreeConstructer {
$this->mode = self::IN_TBODY;
}
- /* A start tag whose tag name is one of: "caption", "col", "colgroup",
- "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */
- } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
- array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) {
+ /* A start tag whose tag name is one of: "caption", "col", "colgroup",
+ "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */
+ } elseif ($token['type'] === HTML5::STARTTAG && in_array(
+ $token['name'],
+ array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr')
+ )
+ ) {
/* Act as if an end tag with the tag name "tr" had been seen, then,
if that token wasn't ignored, reprocess the current token. */
- $this->inRow(array(
- 'name' => 'tr',
- 'type' => HTML5::ENDTAG
- ));
+ $this->inRow(
+ array(
+ 'name' => 'tr',
+ 'type' => HTML5::ENDTAG
+ )
+ );
return $this->inCell($token);
- /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
- } elseif($token['type'] === HTML5::ENDTAG &&
- in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
+ /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
+ } elseif ($token['type'] === HTML5::ENDTAG &&
+ in_array($token['name'], array('tbody', 'tfoot', 'thead'))
+ ) {
/* If the stack of open elements does not have an element in table
scope with the same tag name as the token, this is a parse error.
Ignore the token. */
- if(!$this->elementInScope($token['name'], true)) {
+ if (!$this->elementInScope($token['name'], true)) {
// Ignore.
- /* Otherwise: */
+ /* Otherwise: */
} else {
/* Otherwise, act as if an end tag with the tag name "tr" had
been seen, then reprocess the current token. */
- $this->inRow(array(
- 'name' => 'tr',
- 'type' => HTML5::ENDTAG
- ));
+ $this->inRow(
+ array(
+ 'name' => 'tr',
+ 'type' => HTML5::ENDTAG
+ )
+ );
return $this->inCell($token);
}
- /* An end tag whose tag name is one of: "body", "caption", "col",
- "colgroup", "html", "td", "th" */
- } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
- array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) {
+ /* An end tag whose tag name is one of: "body", "caption", "col",
+ "colgroup", "html", "td", "th" */
+ } elseif ($token['type'] === HTML5::ENDTAG && in_array(
+ $token['name'],
+ array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr')
+ )
+ ) {
/* Parse error. Ignore the token. */
- /* Anything else */
+ /* Anything else */
} else {
/* Process the token as if the insertion mode was "in table". */
$this->inTable($token);
}
}
- private function inCell($token) {
+ private function inCell($token)
+ {
/* An end tag whose tag name is one of: "td", "th" */
- if($token['type'] === HTML5::ENDTAG &&
- ($token['name'] === 'td' || $token['name'] === 'th')) {
+ if ($token['type'] === HTML5::ENDTAG &&
+ ($token['name'] === 'td' || $token['name'] === 'th')
+ ) {
/* If the stack of open elements does not have an element in table
scope with the same tag name as that of the token, then this is a
parse error and the token must be ignored. */
- if(!$this->elementInScope($token['name'], true)) {
+ if (!$this->elementInScope($token['name'], true)) {
// Ignore.
- /* Otherwise: */
+ /* Otherwise: */
} else {
/* Generate implied end tags, except for elements with the same
tag name as the token. */
@@ -3124,11 +3903,11 @@ class HTML5TreeConstructer {
/* Pop elements from this stack until an element with the same
tag name as the token has been popped from the stack. */
- while(true) {
+ while (true) {
$node = end($this->stack)->nodeName;
array_pop($this->stack);
- if($node === $token['name']) {
+ if ($node === $token['name']) {
break;
}
}
@@ -3142,178 +3921,223 @@ class HTML5TreeConstructer {
$this->mode = self::IN_ROW;
}
- /* A start tag whose tag name is one of: "caption", "col", "colgroup",
- "tbody", "td", "tfoot", "th", "thead", "tr" */
- } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
- array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
- 'thead', 'tr'))) {
+ /* A start tag whose tag name is one of: "caption", "col", "colgroup",
+ "tbody", "td", "tfoot", "th", "thead", "tr" */
+ } elseif ($token['type'] === HTML5::STARTTAG && in_array(
+ $token['name'],
+ array(
+ 'caption',
+ 'col',
+ 'colgroup',
+ 'tbody',
+ 'td',
+ 'tfoot',
+ 'th',
+ 'thead',
+ 'tr'
+ )
+ )
+ ) {
/* If the stack of open elements does not have a td or th element
in table scope, then this is a parse error; ignore the token.
(innerHTML case) */
- if(!$this->elementInScope(array('td', 'th'), true)) {
+ if (!$this->elementInScope(array('td', 'th'), true)) {
// Ignore.
- /* Otherwise, close the cell (see below) and reprocess the current
- token. */
+ /* Otherwise, close the cell (see below) and reprocess the current
+ token. */
} else {
$this->closeCell();
return $this->inRow($token);
}
- /* A start tag whose tag name is one of: "caption", "col", "colgroup",
- "tbody", "td", "tfoot", "th", "thead", "tr" */
- } elseif($token['type'] === HTML5::STARTTAG && in_array($token['name'],
- array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
- 'thead', 'tr'))) {
+ /* A start tag whose tag name is one of: "caption", "col", "colgroup",
+ "tbody", "td", "tfoot", "th", "thead", "tr" */
+ } elseif ($token['type'] === HTML5::STARTTAG && in_array(
+ $token['name'],
+ array(
+ 'caption',
+ 'col',
+ 'colgroup',
+ 'tbody',
+ 'td',
+ 'tfoot',
+ 'th',
+ 'thead',
+ 'tr'
+ )
+ )
+ ) {
/* If the stack of open elements does not have a td or th element
in table scope, then this is a parse error; ignore the token.
(innerHTML case) */
- if(!$this->elementInScope(array('td', 'th'), true)) {
+ if (!$this->elementInScope(array('td', 'th'), true)) {
// Ignore.
- /* Otherwise, close the cell (see below) and reprocess the current
- token. */
+ /* Otherwise, close the cell (see below) and reprocess the current
+ token. */
} else {
$this->closeCell();
return $this->inRow($token);
}
- /* An end tag whose tag name is one of: "body", "caption", "col",
- "colgroup", "html" */
- } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
- array('body', 'caption', 'col', 'colgroup', 'html'))) {
+ /* An end tag whose tag name is one of: "body", "caption", "col",
+ "colgroup", "html" */
+ } elseif ($token['type'] === HTML5::ENDTAG && in_array(
+ $token['name'],
+ array('body', 'caption', 'col', 'colgroup', 'html')
+ )
+ ) {
/* Parse error. Ignore the token. */
- /* An end tag whose tag name is one of: "table", "tbody", "tfoot",
- "thead", "tr" */
- } elseif($token['type'] === HTML5::ENDTAG && in_array($token['name'],
- array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
+ /* An end tag whose tag name is one of: "table", "tbody", "tfoot",
+ "thead", "tr" */
+ } elseif ($token['type'] === HTML5::ENDTAG && in_array(
+ $token['name'],
+ array('table', 'tbody', 'tfoot', 'thead', 'tr')
+ )
+ ) {
/* If the stack of open elements does not have an element in table
scope with the same tag name as that of the token (which can only
happen for "tbody", "tfoot" and "thead", or, in the innerHTML case),
then this is a parse error and the token must be ignored. */
- if(!$this->elementInScope($token['name'], true)) {
+ if (!$this->elementInScope($token['name'], true)) {
// Ignore.
- /* Otherwise, close the cell (see below) and reprocess the current
- token. */
+ /* Otherwise, close the cell (see below) and reprocess the current
+ token. */
} else {
$this->closeCell();
return $this->inRow($token);
}
- /* Anything else */
+ /* Anything else */
} else {
/* Process the token as if the insertion mode was "in body". */
$this->inBody($token);
}
}
- private function inSelect($token) {
+ private function inSelect($token)
+ {
/* Handle the token as follows: */
/* A character token */
- if($token['type'] === HTML5::CHARACTR) {
+ if ($token['type'] === HTML5::CHARACTR) {
/* Append the token's character to the current node. */
$this->insertText($token['data']);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the current node with the data
attribute set to the data given in the comment token. */
$this->insertComment($token['data']);
- /* A start tag token whose tag name is "option" */
- } elseif($token['type'] === HTML5::STARTTAG &&
- $token['name'] === 'option') {
+ /* A start tag token whose tag name is "option" */
+ } elseif ($token['type'] === HTML5::STARTTAG &&
+ $token['name'] === 'option'
+ ) {
/* If the current node is an option element, act as if an end tag
with the tag name "option" had been seen. */
- if(end($this->stack)->nodeName === 'option') {
- $this->inSelect(array(
- 'name' => 'option',
- 'type' => HTML5::ENDTAG
- ));
+ if (end($this->stack)->nodeName === 'option') {
+ $this->inSelect(
+ array(
+ 'name' => 'option',
+ 'type' => HTML5::ENDTAG
+ )
+ );
}
/* Insert an HTML element for the token. */
$this->insertElement($token);
- /* A start tag token whose tag name is "optgroup" */
- } elseif($token['type'] === HTML5::STARTTAG &&
- $token['name'] === 'optgroup') {
+ /* A start tag token whose tag name is "optgroup" */
+ } elseif ($token['type'] === HTML5::STARTTAG &&
+ $token['name'] === 'optgroup'
+ ) {
/* If the current node is an option element, act as if an end tag
with the tag name "option" had been seen. */
- if(end($this->stack)->nodeName === 'option') {
- $this->inSelect(array(
- 'name' => 'option',
- 'type' => HTML5::ENDTAG
- ));
+ if (end($this->stack)->nodeName === 'option') {
+ $this->inSelect(
+ array(
+ 'name' => 'option',
+ 'type' => HTML5::ENDTAG
+ )
+ );
}
/* If the current node is an optgroup element, act as if an end tag
with the tag name "optgroup" had been seen. */
- if(end($this->stack)->nodeName === 'optgroup') {
- $this->inSelect(array(
- 'name' => 'optgroup',
- 'type' => HTML5::ENDTAG
- ));
+ if (end($this->stack)->nodeName === 'optgroup') {
+ $this->inSelect(
+ array(
+ 'name' => 'optgroup',
+ 'type' => HTML5::ENDTAG
+ )
+ );
}
/* Insert an HTML element for the token. */
$this->insertElement($token);
- /* An end tag token whose tag name is "optgroup" */
- } elseif($token['type'] === HTML5::ENDTAG &&
- $token['name'] === 'optgroup') {
+ /* An end tag token whose tag name is "optgroup" */
+ } elseif ($token['type'] === HTML5::ENDTAG &&
+ $token['name'] === 'optgroup'
+ ) {
/* First, if the current node is an option element, and the node
immediately before it in the stack of open elements is an optgroup
element, then act as if an end tag with the tag name "option" had
been seen. */
$elements_in_stack = count($this->stack);
- if($this->stack[$elements_in_stack - 1]->nodeName === 'option' &&
- $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup') {
- $this->inSelect(array(
- 'name' => 'option',
- 'type' => HTML5::ENDTAG
- ));
+ if ($this->stack[$elements_in_stack - 1]->nodeName === 'option' &&
+ $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup'
+ ) {
+ $this->inSelect(
+ array(
+ 'name' => 'option',
+ 'type' => HTML5::ENDTAG
+ )
+ );
}
/* If the current node is an optgroup element, then pop that node
from the stack of open elements. Otherwise, this is a parse error,
ignore the token. */
- if($this->stack[$elements_in_stack - 1] === 'optgroup') {
+ if ($this->stack[$elements_in_stack - 1] === 'optgroup') {
array_pop($this->stack);
}
- /* An end tag token whose tag name is "option" */
- } elseif($token['type'] === HTML5::ENDTAG &&
- $token['name'] === 'option') {
+ /* An end tag token whose tag name is "option" */
+ } elseif ($token['type'] === HTML5::ENDTAG &&
+ $token['name'] === 'option'
+ ) {
/* If the current node is an option element, then pop that node
from the stack of open elements. Otherwise, this is a parse error,
ignore the token. */
- if(end($this->stack)->nodeName === 'option') {
+ if (end($this->stack)->nodeName === 'option') {
array_pop($this->stack);
}
- /* An end tag whose tag name is "select" */
- } elseif($token['type'] === HTML5::ENDTAG &&
- $token['name'] === 'select') {
+ /* An end tag whose tag name is "select" */
+ } elseif ($token['type'] === HTML5::ENDTAG &&
+ $token['name'] === 'select'
+ ) {
/* If the stack of open elements does not have an element in table
scope with the same tag name as the token, this is a parse error.
Ignore the token. (innerHTML case) */
- if(!$this->elementInScope($token['name'], true)) {
+ if (!$this->elementInScope($token['name'], true)) {
// w/e
- /* Otherwise: */
+ /* Otherwise: */
} else {
/* Pop elements from the stack of open elements until a select
element has been popped from the stack. */
- while(true) {
+ while (true) {
$current = end($this->stack)->nodeName;
array_pop($this->stack);
- if($current === 'select') {
+ if ($current === 'select') {
break;
}
}
@@ -3322,20 +4146,35 @@ class HTML5TreeConstructer {
$this->resetInsertionMode();
}
- /* A start tag whose tag name is "select" */
- } elseif($token['name'] === 'select' &&
- $token['type'] === HTML5::STARTTAG) {
+ /* A start tag whose tag name is "select" */
+ } elseif ($token['name'] === 'select' &&
+ $token['type'] === HTML5::STARTTAG
+ ) {
/* Parse error. Act as if the token had been an end tag with the
tag name "select" instead. */
- $this->inSelect(array(
- 'name' => 'select',
- 'type' => HTML5::ENDTAG
- ));
-
- /* An end tag whose tag name is one of: "caption", "table", "tbody",
- "tfoot", "thead", "tr", "td", "th" */
- } elseif(in_array($token['name'], array('caption', 'table', 'tbody',
- 'tfoot', 'thead', 'tr', 'td', 'th')) && $token['type'] === HTML5::ENDTAG) {
+ $this->inSelect(
+ array(
+ 'name' => 'select',
+ 'type' => HTML5::ENDTAG
+ )
+ );
+
+ /* An end tag whose tag name is one of: "caption", "table", "tbody",
+ "tfoot", "thead", "tr", "td", "th" */
+ } elseif (in_array(
+ $token['name'],
+ array(
+ 'caption',
+ 'table',
+ 'tbody',
+ 'tfoot',
+ 'thead',
+ 'tr',
+ 'td',
+ 'th'
+ )
+ ) && $token['type'] === HTML5::ENDTAG
+ ) {
/* Parse error. */
// w/e
@@ -3343,43 +4182,47 @@ class HTML5TreeConstructer {
the same tag name as that of the token, then act as if an end tag
with the tag name "select" had been seen, and reprocess the token.
Otherwise, ignore the token. */
- if($this->elementInScope($token['name'], true)) {
- $this->inSelect(array(
- 'name' => 'select',
- 'type' => HTML5::ENDTAG
- ));
+ if ($this->elementInScope($token['name'], true)) {
+ $this->inSelect(
+ array(
+ 'name' => 'select',
+ 'type' => HTML5::ENDTAG
+ )
+ );
$this->mainPhase($token);
}
- /* Anything else */
+ /* Anything else */
} else {
/* Parse error. Ignore the token. */
}
}
- private function afterBody($token) {
+ private function afterBody($token)
+ {
/* Handle the token as follows: */
/* A character token that is one of one of U+0009 CHARACTER TABULATION,
U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
or U+0020 SPACE */
- if($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ if ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Process the token as it would be processed if the insertion mode
was "in body". */
$this->inBody($token);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the first element in the stack of open
elements (the html element), with the data attribute set to the
data given in the comment token. */
$comment = $this->dom->createComment($token['data']);
$this->stack[0]->appendChild($comment);
- /* An end tag with the tag name "html" */
- } elseif($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') {
+ /* An end tag with the tag name "html" */
+ } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') {
/* If the parser was originally created in order to handle the
setting of an element's innerHTML attribute, this is a parse error;
ignore the token. (The element will be an html element in this
@@ -3388,7 +4231,7 @@ class HTML5TreeConstructer {
/* Otherwise, switch to the trailing end phase. */
$this->phase = self::END_PHASE;
- /* Anything else */
+ /* Anything else */
} else {
/* Parse error. Set the insertion mode to "in body" and reprocess
the token. */
@@ -3397,34 +4240,38 @@ class HTML5TreeConstructer {
}
}
- private function inFrameset($token) {
+ private function inFrameset($token)
+ {
/* Handle the token as follows: */
/* A character token that is one of one of U+0009 CHARACTER TABULATION,
U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
- if($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ if ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Append the character to the current node. */
$this->insertText($token['data']);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the current node with the data
attribute set to the data given in the comment token. */
$this->insertComment($token['data']);
- /* A start tag with the tag name "frameset" */
- } elseif($token['name'] === 'frameset' &&
- $token['type'] === HTML5::STARTTAG) {
+ /* A start tag with the tag name "frameset" */
+ } elseif ($token['name'] === 'frameset' &&
+ $token['type'] === HTML5::STARTTAG
+ ) {
$this->insertElement($token);
- /* An end tag with the tag name "frameset" */
- } elseif($token['name'] === 'frameset' &&
- $token['type'] === HTML5::ENDTAG) {
+ /* An end tag with the tag name "frameset" */
+ } elseif ($token['name'] === 'frameset' &&
+ $token['type'] === HTML5::ENDTAG
+ ) {
/* If the current node is the root html element, then this is a
parse error; ignore the token. (innerHTML case) */
- if(end($this->stack)->nodeName === 'html') {
+ if (end($this->stack)->nodeName === 'html') {
// Ignore
} else {
@@ -3439,103 +4286,113 @@ class HTML5TreeConstructer {
$this->mode = self::AFTR_FRAME;
}
- /* A start tag with the tag name "frame" */
- } elseif($token['name'] === 'frame' &&
- $token['type'] === HTML5::STARTTAG) {
+ /* A start tag with the tag name "frame" */
+ } elseif ($token['name'] === 'frame' &&
+ $token['type'] === HTML5::STARTTAG
+ ) {
/* Insert an HTML element for the token. */
$this->insertElement($token);
/* Immediately pop the current node off the stack of open elements. */
array_pop($this->stack);
- /* A start tag with the tag name "noframes" */
- } elseif($token['name'] === 'noframes' &&
- $token['type'] === HTML5::STARTTAG) {
+ /* A start tag with the tag name "noframes" */
+ } elseif ($token['name'] === 'noframes' &&
+ $token['type'] === HTML5::STARTTAG
+ ) {
/* Process the token as if the insertion mode had been "in body". */
$this->inBody($token);
- /* Anything else */
+ /* Anything else */
} else {
/* Parse error. Ignore the token. */
}
}
- private function afterFrameset($token) {
+ private function afterFrameset($token)
+ {
/* Handle the token as follows: */
/* A character token that is one of one of U+0009 CHARACTER TABULATION,
U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
- if($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ if ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Append the character to the current node. */
$this->insertText($token['data']);
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the current node with the data
attribute set to the data given in the comment token. */
$this->insertComment($token['data']);
- /* An end tag with the tag name "html" */
- } elseif($token['name'] === 'html' &&
- $token['type'] === HTML5::ENDTAG) {
+ /* An end tag with the tag name "html" */
+ } elseif ($token['name'] === 'html' &&
+ $token['type'] === HTML5::ENDTAG
+ ) {
/* Switch to the trailing end phase. */
$this->phase = self::END_PHASE;
- /* A start tag with the tag name "noframes" */
- } elseif($token['name'] === 'noframes' &&
- $token['type'] === HTML5::STARTTAG) {
+ /* A start tag with the tag name "noframes" */
+ } elseif ($token['name'] === 'noframes' &&
+ $token['type'] === HTML5::STARTTAG
+ ) {
/* Process the token as if the insertion mode had been "in body". */
$this->inBody($token);
- /* Anything else */
+ /* Anything else */
} else {
/* Parse error. Ignore the token. */
}
}
- private function trailingEndPhase($token) {
+ private function trailingEndPhase($token)
+ {
/* After the main phase, as each token is emitted from the tokenisation
stage, it must be processed as described in this section. */
/* A DOCTYPE token */
- if($token['type'] === HTML5::DOCTYPE) {
+ if ($token['type'] === HTML5::DOCTYPE) {
// Parse error. Ignore the token.
- /* A comment token */
- } elseif($token['type'] === HTML5::COMMENT) {
+ /* A comment token */
+ } elseif ($token['type'] === HTML5::COMMENT) {
/* Append a Comment node to the Document object with the data
attribute set to the data given in the comment token. */
$comment = $this->dom->createComment($token['data']);
$this->dom->appendChild($comment);
- /* A character token that is one of one of U+0009 CHARACTER TABULATION,
- U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
- or U+0020 SPACE */
- } elseif($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) {
+ /* A character token that is one of one of U+0009 CHARACTER TABULATION,
+ U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
+ or U+0020 SPACE */
+ } elseif ($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])
+ ) {
/* Process the token as it would be processed in the main phase. */
$this->mainPhase($token);
- /* A character token that is not one of U+0009 CHARACTER TABULATION,
- U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
- or U+0020 SPACE. Or a start tag token. Or an end tag token. */
- } elseif(($token['type'] === HTML5::CHARACTR &&
- preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
- $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG) {
+ /* A character token that is not one of U+0009 CHARACTER TABULATION,
+ U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
+ or U+0020 SPACE. Or a start tag token. Or an end tag token. */
+ } elseif (($token['type'] === HTML5::CHARACTR &&
+ preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) ||
+ $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG
+ ) {
/* Parse error. Switch back to the main phase and reprocess the
token. */
$this->phase = self::MAIN_PHASE;
return $this->mainPhase($token);
- /* An end-of-file token */
- } elseif($token['type'] === HTML5::EOF) {
+ /* An end-of-file token */
+ } elseif ($token['type'] === HTML5::EOF) {
/* OMG DONE!! */
}
}
- private function insertElement($token, $append = true, $check = false) {
+ private function insertElement($token, $append = true, $check = false)
+ {
// Proprietary workaround for libxml2's limitations with tag names
if ($check) {
// Slightly modified HTML5 tag-name modification,
@@ -3544,13 +4401,15 @@ class HTML5TreeConstructer {
// Remove leading hyphens and numbers
$token['name'] = ltrim($token['name'], '-0..9');
// In theory, this should ever be needed, but just in case
- if ($token['name'] === '') $token['name'] = 'span'; // arbitrary generic choice
+ if ($token['name'] === '') {
+ $token['name'] = 'span';
+ } // arbitrary generic choice
}
-
+
$el = $this->dom->createElement($token['name']);
- foreach($token['attr'] as $attr) {
- if(!$el->hasAttribute($attr['name'])) {
+ foreach ($token['attr'] as $attr) {
+ if (!$el->hasAttribute($attr['name'])) {
$el->setAttribute($attr['name'], $attr['value']);
}
}
@@ -3561,48 +4420,54 @@ class HTML5TreeConstructer {
return $el;
}
- private function insertText($data) {
+ private function insertText($data)
+ {
$text = $this->dom->createTextNode($data);
$this->appendToRealParent($text);
}
- private function insertComment($data) {
+ private function insertComment($data)
+ {
$comment = $this->dom->createComment($data);
$this->appendToRealParent($comment);
}
- private function appendToRealParent($node) {
- if($this->foster_parent === null) {
+ private function appendToRealParent($node)
+ {
+ if ($this->foster_parent === null) {
end($this->stack)->appendChild($node);
- } elseif($this->foster_parent !== null) {
+ } elseif ($this->foster_parent !== null) {
/* If the foster parent element is the parent element of the
last table element in the stack of open elements, then the new
node must be inserted immediately before the last table element
in the stack of open elements in the foster parent element;
otherwise, the new node must be appended to the foster parent
element. */
- for($n = count($this->stack) - 1; $n >= 0; $n--) {
- if($this->stack[$n]->nodeName === 'table' &&
- $this->stack[$n]->parentNode !== null) {
+ for ($n = count($this->stack) - 1; $n >= 0; $n--) {
+ if ($this->stack[$n]->nodeName === 'table' &&
+ $this->stack[$n]->parentNode !== null
+ ) {
$table = $this->stack[$n];
break;
}
}
- if(isset($table) && $this->foster_parent->isSameNode($table->parentNode))
+ if (isset($table) && $this->foster_parent->isSameNode($table->parentNode)) {
$this->foster_parent->insertBefore($node, $table);
- else
+ } else {
$this->foster_parent->appendChild($node);
+ }
$this->foster_parent = null;
}
}
- private function elementInScope($el, $table = false) {
- if(is_array($el)) {
- foreach($el as $element) {
- if($this->elementInScope($element, $table)) {
+ private function elementInScope($el, $table = false)
+ {
+ if (is_array($el)) {
+ foreach ($el as $element) {
+ if ($this->elementInScope($element, $table)) {
return true;
}
}
@@ -3612,28 +4477,38 @@ class HTML5TreeConstructer {
$leng = count($this->stack);
- for($n = 0; $n < $leng; $n++) {
+ for ($n = 0; $n < $leng; $n++) {
/* 1. Initialise node to be the current node (the bottommost node of
the stack). */
$node = $this->stack[$leng - 1 - $n];
- if($node->tagName === $el) {
+ if ($node->tagName === $el) {
/* 2. If node is the target node, terminate in a match state. */
return true;
- } elseif($node->tagName === 'table') {
+ } elseif ($node->tagName === 'table') {
/* 3. Otherwise, if node is a table element, terminate in a failure
state. */
return false;
- } elseif($table === true && in_array($node->tagName, array('caption', 'td',
- 'th', 'button', 'marquee', 'object'))) {
+ } elseif ($table === true && in_array(
+ $node->tagName,
+ array(
+ 'caption',
+ 'td',
+ 'th',
+ 'button',
+ 'marquee',
+ 'object'
+ )
+ )
+ ) {
/* 4. Otherwise, if the algorithm is the "has an element in scope"
variant (rather than the "has an element in table scope" variant),
and node is one of the following, terminate in a failure state. */
return false;
- } elseif($node === $node->ownerDocument->documentElement) {
+ } elseif ($node === $node->ownerDocument->documentElement) {
/* 5. Otherwise, if node is an html element (root element), terminate
in a failure state. (This can only happen if the node is the topmost
node of the stack of open elements, and prevents the next step from
@@ -3648,12 +4523,13 @@ class HTML5TreeConstructer {
}
}
- private function reconstructActiveFormattingElements() {
+ private function reconstructActiveFormattingElements()
+ {
/* 1. If there are no entries in the list of active formatting elements,
then there is nothing to reconstruct; stop this algorithm. */
$formatting_elements = count($this->a_formatting);
- if($formatting_elements === 0) {
+ if ($formatting_elements === 0) {
return false;
}
@@ -3665,14 +4541,14 @@ class HTML5TreeConstructer {
formatting elements is a marker, or if it is an element that is in the
stack of open elements, then there is nothing to reconstruct; stop this
algorithm. */
- if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
+ if ($entry === self::MARKER || in_array($entry, $this->stack, true)) {
return false;
}
- for($a = $formatting_elements - 1; $a >= 0; true) {
+ for ($a = $formatting_elements - 1; $a >= 0; true) {
/* 4. If there are no entries before entry in the list of active
formatting elements, then jump to step 8. */
- if($a === 0) {
+ if ($a === 0) {
$step_seven = false;
break;
}
@@ -3684,15 +4560,15 @@ class HTML5TreeConstructer {
/* 6. If entry is neither a marker nor an element that is also in
thetack of open elements, go to step 4. */
- if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
+ if ($entry === self::MARKER || in_array($entry, $this->stack, true)) {
break;
}
}
- while(true) {
+ while (true) {
/* 7. Let entry be the element one later than entry in the list of
active formatting elements. */
- if(isset($step_seven) && $step_seven === true) {
+ if (isset($step_seven) && $step_seven === true) {
$a++;
$entry = $this->a_formatting[$a];
}
@@ -3711,7 +4587,7 @@ class HTML5TreeConstructer {
/* 11. If the entry for clone in the list of active formatting
elements is not the last entry in the list, return to step 7. */
- if(end($this->a_formatting) !== $clone) {
+ if (end($this->a_formatting) !== $clone) {
$step_seven = true;
} else {
break;
@@ -3719,12 +4595,13 @@ class HTML5TreeConstructer {
}
}
- private function clearTheActiveFormattingElementsUpToTheLastMarker() {
+ private function clearTheActiveFormattingElementsUpToTheLastMarker()
+ {
/* When the steps below require the UA to clear the list of active
formatting elements up to the last marker, the UA must perform the
following steps: */
- while(true) {
+ while (true) {
/* 1. Let entry be the last (most recently added) entry in the list
of active formatting elements. */
$entry = end($this->a_formatting);
@@ -3734,13 +4611,14 @@ class HTML5TreeConstructer {
/* 3. If entry was a marker, then stop the algorithm at this point.
The list has been cleared up to the last marker. */
- if($entry === self::MARKER) {
+ if ($entry === self::MARKER) {
break;
}
}
}
- private function generateImpliedEndTags($exclude = array()) {
+ private function generateImpliedEndTags($exclude = array())
+ {
/* When the steps below require the UA to generate implied end tags,
then, if the current node is a dd element, a dt element, an li element,
a p element, a td element, a th element, or a tr element, the UA must
@@ -3749,36 +4627,36 @@ class HTML5TreeConstructer {
$node = end($this->stack);
$elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude);
- while(in_array(end($this->stack)->nodeName, $elements)) {
+ while (in_array(end($this->stack)->nodeName, $elements)) {
array_pop($this->stack);
}
}
- private function getElementCategory($node) {
+ private function getElementCategory($node)
+ {
$name = $node->tagName;
- if(in_array($name, $this->special))
+ if (in_array($name, $this->special)) {
return self::SPECIAL;
-
- elseif(in_array($name, $this->scoping))
+ } elseif (in_array($name, $this->scoping)) {
return self::SCOPING;
-
- elseif(in_array($name, $this->formatting))
+ } elseif (in_array($name, $this->formatting)) {
return self::FORMATTING;
-
- else
+ } else {
return self::PHRASING;
+ }
}
- private function clearStackToTableContext($elements) {
+ private function clearStackToTableContext($elements)
+ {
/* When the steps above require the UA to clear the stack back to a
table context, it means that the UA must, while the current node is not
a table element or an html element, pop elements from the stack of open
elements. If this causes any elements to be popped from the stack, then
this is a parse error. */
- while(true) {
+ while (true) {
$node = end($this->stack)->nodeName;
- if(in_array($node, $elements)) {
+ if (in_array($node, $elements)) {
break;
} else {
array_pop($this->stack);
@@ -3786,12 +4664,13 @@ class HTML5TreeConstructer {
}
}
- private function resetInsertionMode() {
+ private function resetInsertionMode()
+ {
/* 1. Let last be false. */
$last = false;
$leng = count($this->stack);
- for($n = $leng - 1; $n >= 0; $n--) {
+ for ($n = $leng - 1; $n >= 0; $n--) {
/* 2. Let node be the last node in the stack of open elements. */
$node = $this->stack[$n];
@@ -3799,108 +4678,111 @@ class HTML5TreeConstructer {
set last to true. If the element whose innerHTML attribute is being
set is neither a td element nor a th element, then set node to the
element whose innerHTML attribute is being set. (innerHTML case) */
- if($this->stack[0]->isSameNode($node)) {
+ if ($this->stack[0]->isSameNode($node)) {
$last = true;
}
/* 4. If node is a select element, then switch the insertion mode to
"in select" and abort these steps. (innerHTML case) */
- if($node->nodeName === 'select') {
+ if ($node->nodeName === 'select') {
$this->mode = self::IN_SELECT;
break;
- /* 5. If node is a td or th element, then switch the insertion mode
- to "in cell" and abort these steps. */
- } elseif($node->nodeName === 'td' || $node->nodeName === 'th') {
+ /* 5. If node is a td or th element, then switch the insertion mode
+ to "in cell" and abort these steps. */
+ } elseif ($node->nodeName === 'td' || $node->nodeName === 'th') {
$this->mode = self::IN_CELL;
break;
- /* 6. If node is a tr element, then switch the insertion mode to
- "in row" and abort these steps. */
- } elseif($node->nodeName === 'tr') {
+ /* 6. If node is a tr element, then switch the insertion mode to
+ "in row" and abort these steps. */
+ } elseif ($node->nodeName === 'tr') {
$this->mode = self::IN_ROW;
break;
- /* 7. If node is a tbody, thead, or tfoot element, then switch the
- insertion mode to "in table body" and abort these steps. */
- } elseif(in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) {
+ /* 7. If node is a tbody, thead, or tfoot element, then switch the
+ insertion mode to "in table body" and abort these steps. */
+ } elseif (in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) {
$this->mode = self::IN_TBODY;
break;
- /* 8. If node is a caption element, then switch the insertion mode
- to "in caption" and abort these steps. */
- } elseif($node->nodeName === 'caption') {
+ /* 8. If node is a caption element, then switch the insertion mode
+ to "in caption" and abort these steps. */
+ } elseif ($node->nodeName === 'caption') {
$this->mode = self::IN_CAPTION;
break;
- /* 9. If node is a colgroup element, then switch the insertion mode
- to "in column group" and abort these steps. (innerHTML case) */
- } elseif($node->nodeName === 'colgroup') {
+ /* 9. If node is a colgroup element, then switch the insertion mode
+ to "in column group" and abort these steps. (innerHTML case) */
+ } elseif ($node->nodeName === 'colgroup') {
$this->mode = self::IN_CGROUP;
break;
- /* 10. If node is a table element, then switch the insertion mode
- to "in table" and abort these steps. */
- } elseif($node->nodeName === 'table') {
+ /* 10. If node is a table element, then switch the insertion mode
+ to "in table" and abort these steps. */
+ } elseif ($node->nodeName === 'table') {
$this->mode = self::IN_TABLE;
break;
- /* 11. If node is a head element, then switch the insertion mode
- to "in body" ("in body"! not "in head"!) and abort these steps.
- (innerHTML case) */
- } elseif($node->nodeName === 'head') {
+ /* 11. If node is a head element, then switch the insertion mode
+ to "in body" ("in body"! not "in head"!) and abort these steps.
+ (innerHTML case) */
+ } elseif ($node->nodeName === 'head') {
$this->mode = self::IN_BODY;
break;
- /* 12. If node is a body element, then switch the insertion mode to
- "in body" and abort these steps. */
- } elseif($node->nodeName === 'body') {
+ /* 12. If node is a body element, then switch the insertion mode to
+ "in body" and abort these steps. */
+ } elseif ($node->nodeName === 'body') {
$this->mode = self::IN_BODY;
break;
- /* 13. If node is a frameset element, then switch the insertion
- mode to "in frameset" and abort these steps. (innerHTML case) */
- } elseif($node->nodeName === 'frameset') {
+ /* 13. If node is a frameset element, then switch the insertion
+ mode to "in frameset" and abort these steps. (innerHTML case) */
+ } elseif ($node->nodeName === 'frameset') {
$this->mode = self::IN_FRAME;
break;
- /* 14. If node is an html element, then: if the head element
- pointer is null, switch the insertion mode to "before head",
- otherwise, switch the insertion mode to "after head". In either
- case, abort these steps. (innerHTML case) */
- } elseif($node->nodeName === 'html') {
+ /* 14. If node is an html element, then: if the head element
+ pointer is null, switch the insertion mode to "before head",
+ otherwise, switch the insertion mode to "after head". In either
+ case, abort these steps. (innerHTML case) */
+ } elseif ($node->nodeName === 'html') {
$this->mode = ($this->head_pointer === null)
? self::BEFOR_HEAD
: self::AFTER_HEAD;
break;
- /* 15. If last is true, then set the insertion mode to "in body"
- and abort these steps. (innerHTML case) */
- } elseif($last) {
+ /* 15. If last is true, then set the insertion mode to "in body"
+ and abort these steps. (innerHTML case) */
+ } elseif ($last) {
$this->mode = self::IN_BODY;
break;
}
}
}
- private function closeCell() {
+ private function closeCell()
+ {
/* If the stack of open elements has a td or th element in table scope,
then act as if an end tag token with that tag name had been seen. */
- foreach(array('td', 'th') as $cell) {
- if($this->elementInScope($cell, true)) {
- $this->inCell(array(
- 'name' => $cell,
- 'type' => HTML5::ENDTAG
- ));
+ foreach (array('td', 'th') as $cell) {
+ if ($this->elementInScope($cell, true)) {
+ $this->inCell(
+ array(
+ 'name' => $cell,
+ 'type' => HTML5::ENDTAG
+ )
+ );
break;
}
}
}
- public function save() {
+ public function save()
+ {
return $this->dom;
}
}
-?>
diff --git a/library/HTMLPurifier/Node.php b/library/HTMLPurifier/Node.php
new file mode 100644
index 000000000..3995fec9f
--- /dev/null
+++ b/library/HTMLPurifier/Node.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Abstract base node class that all others inherit from.
+ *
+ * Why do we not use the DOM extension? (1) It is not always available,
+ * (2) it has funny constraints on the data it can represent,
+ * whereas we want a maximally flexible representation, and (3) its
+ * interface is a bit cumbersome.
+ */
+abstract class HTMLPurifier_Node
+{
+ /**
+ * Line number of the start token in the source document
+ * @type int
+ */
+ public $line;
+
+ /**
+ * Column number of the start token in the source document. Null if unknown.
+ * @type int
+ */
+ public $col;
+
+ /**
+ * Lookup array of processing that this token is exempt from.
+ * Currently, valid values are "ValidateAttributes".
+ * @type array
+ */
+ public $armor = array();
+
+ /**
+ * When true, this node should be ignored as non-existent.
+ *
+ * Who is responsible for ignoring dead nodes? FixNesting is
+ * responsible for removing them before passing on to child
+ * validators.
+ */
+ public $dead = false;
+
+ /**
+ * Returns a pair of start and end tokens, where the end token
+ * is null if it is not necessary. Does not include children.
+ * @type array
+ */
+ abstract public function toTokenPair();
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Node/Comment.php b/library/HTMLPurifier/Node/Comment.php
new file mode 100644
index 000000000..38ba19394
--- /dev/null
+++ b/library/HTMLPurifier/Node/Comment.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * Concrete comment node class.
+ */
+class HTMLPurifier_Node_Comment extends HTMLPurifier_Node
+{
+ /**
+ * Character data within comment.
+ * @type string
+ */
+ public $data;
+
+ /**
+ * @type bool
+ */
+ public $is_whitespace = true;
+
+ /**
+ * Transparent constructor.
+ *
+ * @param string $data String comment data.
+ * @param int $line
+ * @param int $col
+ */
+ public function __construct($data, $line = null, $col = null)
+ {
+ $this->data = $data;
+ $this->line = $line;
+ $this->col = $col;
+ }
+
+ public function toTokenPair() {
+ return array(new HTMLPurifier_Token_Comment($this->data, $this->line, $this->col), null);
+ }
+}
diff --git a/library/HTMLPurifier/Node/Element.php b/library/HTMLPurifier/Node/Element.php
new file mode 100644
index 000000000..6cbf56dad
--- /dev/null
+++ b/library/HTMLPurifier/Node/Element.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Concrete element node class.
+ */
+class HTMLPurifier_Node_Element extends HTMLPurifier_Node
+{
+ /**
+ * The lower-case name of the tag, like 'a', 'b' or 'blockquote'.
+ *
+ * @note Strictly speaking, XML tags are case sensitive, so we shouldn't
+ * be lower-casing them, but these tokens cater to HTML tags, which are
+ * insensitive.
+ * @type string
+ */
+ public $name;
+
+ /**
+ * Associative array of the node's attributes.
+ * @type array
+ */
+ public $attr = array();
+
+ /**
+ * List of child elements.
+ * @type array
+ */
+ public $children = array();
+
+ /**
+ * Does this use the <a></a> form or the </a> form, i.e.
+ * is it a pair of start/end tokens or an empty token.
+ * @bool
+ */
+ public $empty = false;
+
+ public $endCol = null, $endLine = null, $endArmor = array();
+
+ public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array()) {
+ $this->name = $name;
+ $this->attr = $attr;
+ $this->line = $line;
+ $this->col = $col;
+ $this->armor = $armor;
+ }
+
+ public function toTokenPair() {
+ // XXX inefficiency here, normalization is not necessary
+ if ($this->empty) {
+ return array(new HTMLPurifier_Token_Empty($this->name, $this->attr, $this->line, $this->col, $this->armor), null);
+ } else {
+ $start = new HTMLPurifier_Token_Start($this->name, $this->attr, $this->line, $this->col, $this->armor);
+ $end = new HTMLPurifier_Token_End($this->name, array(), $this->endLine, $this->endCol, $this->endArmor);
+ //$end->start = $start;
+ return array($start, $end);
+ }
+ }
+}
+
diff --git a/library/HTMLPurifier/Node/Text.php b/library/HTMLPurifier/Node/Text.php
new file mode 100644
index 000000000..aec916647
--- /dev/null
+++ b/library/HTMLPurifier/Node/Text.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Concrete text token class.
+ *
+ * Text tokens comprise of regular parsed character data (PCDATA) and raw
+ * character data (from the CDATA sections). Internally, their
+ * data is parsed with all entities expanded. Surprisingly, the text token
+ * does have a "tag name" called #PCDATA, which is how the DTD represents it
+ * in permissible child nodes.
+ */
+class HTMLPurifier_Node_Text extends HTMLPurifier_Node
+{
+
+ /**
+ * PCDATA tag name compatible with DTD, see
+ * HTMLPurifier_ChildDef_Custom for details.
+ * @type string
+ */
+ public $name = '#PCDATA';
+
+ /**
+ * @type string
+ */
+ public $data;
+ /**< Parsed character data of text. */
+
+ /**
+ * @type bool
+ */
+ public $is_whitespace;
+
+ /**< Bool indicating if node is whitespace. */
+
+ /**
+ * Constructor, accepts data and determines if it is whitespace.
+ * @param string $data String parsed character data.
+ * @param int $line
+ * @param int $col
+ */
+ public function __construct($data, $is_whitespace, $line = null, $col = null)
+ {
+ $this->data = $data;
+ $this->is_whitespace = $is_whitespace;
+ $this->line = $line;
+ $this->col = $col;
+ }
+
+ public function toTokenPair() {
+ return array(new HTMLPurifier_Token_Text($this->data, $this->line, $this->col), null);
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/PercentEncoder.php b/library/HTMLPurifier/PercentEncoder.php
index a43c44f4c..18c8bbb00 100644
--- a/library/HTMLPurifier/PercentEncoder.php
+++ b/library/HTMLPurifier/PercentEncoder.php
@@ -13,17 +13,26 @@ class HTMLPurifier_PercentEncoder
/**
* Reserved characters to preserve when using encode().
+ * @type array
*/
protected $preserve = array();
/**
* String of characters that should be preserved while using encode().
+ * @param bool $preserve
*/
- public function __construct($preserve = false) {
+ public function __construct($preserve = false)
+ {
// unreserved letters, ought to const-ify
- for ($i = 48; $i <= 57; $i++) $this->preserve[$i] = true; // digits
- for ($i = 65; $i <= 90; $i++) $this->preserve[$i] = true; // upper-case
- for ($i = 97; $i <= 122; $i++) $this->preserve[$i] = true; // lower-case
+ for ($i = 48; $i <= 57; $i++) { // digits
+ $this->preserve[$i] = true;
+ }
+ for ($i = 65; $i <= 90; $i++) { // upper-case
+ $this->preserve[$i] = true;
+ }
+ for ($i = 97; $i <= 122; $i++) { // lower-case
+ $this->preserve[$i] = true;
+ }
$this->preserve[45] = true; // Dash -
$this->preserve[46] = true; // Period .
$this->preserve[95] = true; // Underscore _
@@ -44,13 +53,14 @@ class HTMLPurifier_PercentEncoder
* Assumes that the string has already been normalized, making any
* and all percent escape sequences valid. Percents will not be
* re-escaped, regardless of their status in $preserve
- * @param $string String to be encoded
- * @return Encoded string.
+ * @param string $string String to be encoded
+ * @return string Encoded string.
*/
- public function encode($string) {
+ public function encode($string)
+ {
$ret = '';
for ($i = 0, $c = strlen($string); $i < $c; $i++) {
- if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])]) ) {
+ if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])])) {
$ret .= '%' . sprintf('%02X', $int);
} else {
$ret .= $string[$i];
@@ -64,10 +74,14 @@ class HTMLPurifier_PercentEncoder
* @warning This function is affected by $preserve, even though the
* usual desired behavior is for this not to preserve those
* characters. Be careful when reusing instances of PercentEncoder!
- * @param $string String to normalize
+ * @param string $string String to normalize
+ * @return string
*/
- public function normalize($string) {
- if ($string == '') return '';
+ public function normalize($string)
+ {
+ if ($string == '') {
+ return '';
+ }
$parts = explode('%', $string);
$ret = array_shift($parts);
foreach ($parts as $part) {
@@ -92,7 +106,6 @@ class HTMLPurifier_PercentEncoder
}
return $ret;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Printer.php b/library/HTMLPurifier/Printer.php
index e7eb82e83..549e4cea1 100644
--- a/library/HTMLPurifier/Printer.php
+++ b/library/HTMLPurifier/Printer.php
@@ -7,25 +7,30 @@ class HTMLPurifier_Printer
{
/**
- * Instance of HTMLPurifier_Generator for HTML generation convenience funcs
+ * For HTML generation convenience funcs.
+ * @type HTMLPurifier_Generator
*/
protected $generator;
/**
- * Instance of HTMLPurifier_Config, for easy access
+ * For easy access.
+ * @type HTMLPurifier_Config
*/
protected $config;
/**
* Initialize $generator.
*/
- public function __construct() {
+ public function __construct()
+ {
}
/**
* Give generator necessary configuration if possible
+ * @param HTMLPurifier_Config $config
*/
- public function prepareGenerator($config) {
+ public function prepareGenerator($config)
+ {
$all = $config->getAll();
$context = new HTMLPurifier_Context();
$this->generator = new HTMLPurifier_Generator($config, $context);
@@ -39,45 +44,62 @@ class HTMLPurifier_Printer
/**
* Returns a start tag
- * @param $tag Tag name
- * @param $attr Attribute array
+ * @param string $tag Tag name
+ * @param array $attr Attribute array
+ * @return string
*/
- protected function start($tag, $attr = array()) {
+ protected function start($tag, $attr = array())
+ {
return $this->generator->generateFromToken(
- new HTMLPurifier_Token_Start($tag, $attr ? $attr : array())
- );
+ new HTMLPurifier_Token_Start($tag, $attr ? $attr : array())
+ );
}
/**
- * Returns an end teg
- * @param $tag Tag name
+ * Returns an end tag
+ * @param string $tag Tag name
+ * @return string
*/
- protected function end($tag) {
+ protected function end($tag)
+ {
return $this->generator->generateFromToken(
- new HTMLPurifier_Token_End($tag)
- );
+ new HTMLPurifier_Token_End($tag)
+ );
}
/**
* Prints a complete element with content inside
- * @param $tag Tag name
- * @param $contents Element contents
- * @param $attr Tag attributes
- * @param $escape Bool whether or not to escape contents
+ * @param string $tag Tag name
+ * @param string $contents Element contents
+ * @param array $attr Tag attributes
+ * @param bool $escape whether or not to escape contents
+ * @return string
*/
- protected function element($tag, $contents, $attr = array(), $escape = true) {
+ protected function element($tag, $contents, $attr = array(), $escape = true)
+ {
return $this->start($tag, $attr) .
- ($escape ? $this->escape($contents) : $contents) .
- $this->end($tag);
+ ($escape ? $this->escape($contents) : $contents) .
+ $this->end($tag);
}
- protected function elementEmpty($tag, $attr = array()) {
+ /**
+ * @param string $tag
+ * @param array $attr
+ * @return string
+ */
+ protected function elementEmpty($tag, $attr = array())
+ {
return $this->generator->generateFromToken(
new HTMLPurifier_Token_Empty($tag, $attr)
);
}
- protected function text($text) {
+ /**
+ * @param string $text
+ * @return string
+ */
+ protected function text($text)
+ {
return $this->generator->generateFromToken(
new HTMLPurifier_Token_Text($text)
);
@@ -85,24 +107,29 @@ class HTMLPurifier_Printer
/**
* Prints a simple key/value row in a table.
- * @param $name Key
- * @param $value Value
+ * @param string $name Key
+ * @param mixed $value Value
+ * @return string
*/
- protected function row($name, $value) {
- if (is_bool($value)) $value = $value ? 'On' : 'Off';
+ protected function row($name, $value)
+ {
+ if (is_bool($value)) {
+ $value = $value ? 'On' : 'Off';
+ }
return
$this->start('tr') . "\n" .
- $this->element('th', $name) . "\n" .
- $this->element('td', $value) . "\n" .
- $this->end('tr')
- ;
+ $this->element('th', $name) . "\n" .
+ $this->element('td', $value) . "\n" .
+ $this->end('tr');
}
/**
* Escapes a string for HTML output.
- * @param $string String to escape
+ * @param string $string String to escape
+ * @return string
*/
- protected function escape($string) {
+ protected function escape($string)
+ {
$string = HTMLPurifier_Encoder::cleanUTF8($string);
$string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8');
return $string;
@@ -110,32 +137,46 @@ class HTMLPurifier_Printer
/**
* Takes a list of strings and turns them into a single list
- * @param $array List of strings
- * @param $polite Bool whether or not to add an end before the last
+ * @param string[] $array List of strings
+ * @param bool $polite Bool whether or not to add an end before the last
+ * @return string
*/
- protected function listify($array, $polite = false) {
- if (empty($array)) return 'None';
+ protected function listify($array, $polite = false)
+ {
+ if (empty($array)) {
+ return 'None';
+ }
$ret = '';
$i = count($array);
foreach ($array as $value) {
$i--;
$ret .= $value;
- if ($i > 0 && !($polite && $i == 1)) $ret .= ', ';
- if ($polite && $i == 1) $ret .= 'and ';
+ if ($i > 0 && !($polite && $i == 1)) {
+ $ret .= ', ';
+ }
+ if ($polite && $i == 1) {
+ $ret .= 'and ';
+ }
}
return $ret;
}
/**
* Retrieves the class of an object without prefixes, as well as metadata
- * @param $obj Object to determine class of
- * @param $prefix Further prefix to remove
+ * @param object $obj Object to determine class of
+ * @param string $sec_prefix Further prefix to remove
+ * @return string
*/
- protected function getClass($obj, $sec_prefix = '') {
+ protected function getClass($obj, $sec_prefix = '')
+ {
static $five = null;
- if ($five === null) $five = version_compare(PHP_VERSION, '5', '>=');
+ if ($five === null) {
+ $five = version_compare(PHP_VERSION, '5', '>=');
+ }
$prefix = 'HTMLPurifier_' . $sec_prefix;
- if (!$five) $prefix = strtolower($prefix);
+ if (!$five) {
+ $prefix = strtolower($prefix);
+ }
$class = str_replace($prefix, '', get_class($obj));
$lclass = strtolower($class);
$class .= '(';
@@ -164,13 +205,14 @@ class HTMLPurifier_Printer
break;
case 'css_importantdecorator':
$class .= $this->getClass($obj->def, $sec_prefix);
- if ($obj->allow) $class .= ', !important';
+ if ($obj->allow) {
+ $class .= ', !important';
+ }
break;
}
$class .= ')';
return $class;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Printer/CSSDefinition.php b/library/HTMLPurifier/Printer/CSSDefinition.php
index 81f986590..29505fe12 100644
--- a/library/HTMLPurifier/Printer/CSSDefinition.php
+++ b/library/HTMLPurifier/Printer/CSSDefinition.php
@@ -2,10 +2,17 @@
class HTMLPurifier_Printer_CSSDefinition extends HTMLPurifier_Printer
{
-
+ /**
+ * @type HTMLPurifier_CSSDefinition
+ */
protected $def;
- public function render($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return string
+ */
+ public function render($config)
+ {
$this->def = $config->getCSSDefinition();
$ret = '';
@@ -32,7 +39,6 @@ class HTMLPurifier_Printer_CSSDefinition extends HTMLPurifier_Printer
return $ret;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Printer/ConfigForm.php b/library/HTMLPurifier/Printer/ConfigForm.php
index 02aa65689..36100ce73 100644
--- a/library/HTMLPurifier/Printer/ConfigForm.php
+++ b/library/HTMLPurifier/Printer/ConfigForm.php
@@ -7,17 +7,20 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
{
/**
- * Printers for specific fields
+ * Printers for specific fields.
+ * @type HTMLPurifier_Printer[]
*/
protected $fields = array();
/**
- * Documentation URL, can have fragment tagged on end
+ * Documentation URL, can have fragment tagged on end.
+ * @type string
*/
protected $docURL;
/**
- * Name of form element to stuff config in
+ * Name of form element to stuff config in.
+ * @type string
*/
protected $name;
@@ -25,24 +28,27 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
* Whether or not to compress directive names, clipping them off
* after a certain amount of letters. False to disable or integer letters
* before clipping.
+ * @type bool
*/
protected $compress = false;
/**
- * @param $name Form element name for directives to be stuffed into
- * @param $doc_url String documentation URL, will have fragment tagged on
- * @param $compress Integer max length before compressing a directive name, set to false to turn off
+ * @param string $name Form element name for directives to be stuffed into
+ * @param string $doc_url String documentation URL, will have fragment tagged on
+ * @param bool $compress Integer max length before compressing a directive name, set to false to turn off
*/
public function __construct(
- $name, $doc_url = null, $compress = false
+ $name,
+ $doc_url = null,
+ $compress = false
) {
parent::__construct();
$this->docURL = $doc_url;
- $this->name = $name;
+ $this->name = $name;
$this->compress = $compress;
// initialize sub-printers
- $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default();
- $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool();
+ $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default();
+ $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool();
}
/**
@@ -50,32 +56,42 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
* @param $cols Integer columns of textarea, null to use default
* @param $rows Integer rows of textarea, null to use default
*/
- public function setTextareaDimensions($cols = null, $rows = null) {
- if ($cols) $this->fields['default']->cols = $cols;
- if ($rows) $this->fields['default']->rows = $rows;
+ public function setTextareaDimensions($cols = null, $rows = null)
+ {
+ if ($cols) {
+ $this->fields['default']->cols = $cols;
+ }
+ if ($rows) {
+ $this->fields['default']->rows = $rows;
+ }
}
/**
* Retrieves styling, in case it is not accessible by webserver
*/
- public static function getCSS() {
+ public static function getCSS()
+ {
return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css');
}
/**
* Retrieves JavaScript, in case it is not accessible by webserver
*/
- public static function getJavaScript() {
+ public static function getJavaScript()
+ {
return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js');
}
/**
* Returns HTML output for a configuration form
- * @param $config Configuration object of current form state, or an array
+ * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array
* where [0] has an HTML namespace and [1] is being rendered.
- * @param $allowed Optional namespace(s) and directives to restrict form to.
+ * @param array|bool $allowed Optional namespace(s) and directives to restrict form to.
+ * @param bool $render_controls
+ * @return string
*/
- public function render($config, $allowed = true, $render_controls = true) {
+ public function render($config, $allowed = true, $render_controls = true)
+ {
if (is_array($config) && isset($config[0])) {
$gen_config = $config[0];
$config = $config[1];
@@ -91,29 +107,29 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
$all = array();
foreach ($allowed as $key) {
list($ns, $directive) = $key;
- $all[$ns][$directive] = $config->get($ns .'.'. $directive);
+ $all[$ns][$directive] = $config->get($ns . '.' . $directive);
}
$ret = '';
$ret .= $this->start('table', array('class' => 'hp-config'));
$ret .= $this->start('thead');
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive'));
- $ret .= $this->element('th', 'Value', array('class' => 'hp-value'));
+ $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive'));
+ $ret .= $this->element('th', 'Value', array('class' => 'hp-value'));
$ret .= $this->end('tr');
$ret .= $this->end('thead');
foreach ($all as $ns => $directives) {
$ret .= $this->renderNamespace($ns, $directives);
}
if ($render_controls) {
- $ret .= $this->start('tbody');
- $ret .= $this->start('tr');
- $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls'));
- $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit'));
- $ret .= '[<a href="?">Reset</a>]';
- $ret .= $this->end('td');
- $ret .= $this->end('tr');
- $ret .= $this->end('tbody');
+ $ret .= $this->start('tbody');
+ $ret .= $this->start('tr');
+ $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls'));
+ $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit'));
+ $ret .= '[<a href="?">Reset</a>]';
+ $ret .= $this->end('td');
+ $ret .= $this->end('tr');
+ $ret .= $this->end('tbody');
}
$ret .= $this->end('table');
return $ret;
@@ -122,13 +138,15 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
/**
* Renders a single namespace
* @param $ns String namespace name
- * @param $directive Associative array of directives to values
+ * @param array $directives array of directives to values
+ * @return string
*/
- protected function renderNamespace($ns, $directives) {
+ protected function renderNamespace($ns, $directives)
+ {
$ret = '';
$ret .= $this->start('tbody', array('class' => 'namespace'));
$ret .= $this->start('tr');
- $ret .= $this->element('th', $ns, array('colspan' => 2));
+ $ret .= $this->element('th', $ns, array('colspan' => 2));
$ret .= $this->end('tr');
$ret .= $this->end('tbody');
$ret .= $this->start('tbody');
@@ -139,40 +157,44 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
$url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL);
$ret .= $this->start('a', array('href' => $url));
}
- $attr = array('for' => "{$this->name}:$ns.$directive");
-
- // crop directive name if it's too long
- if (!$this->compress || (strlen($directive) < $this->compress)) {
- $directive_disp = $directive;
- } else {
- $directive_disp = substr($directive, 0, $this->compress - 2) . '...';
- $attr['title'] = $directive;
- }
+ $attr = array('for' => "{$this->name}:$ns.$directive");
+
+ // crop directive name if it's too long
+ if (!$this->compress || (strlen($directive) < $this->compress)) {
+ $directive_disp = $directive;
+ } else {
+ $directive_disp = substr($directive, 0, $this->compress - 2) . '...';
+ $attr['title'] = $directive;
+ }
- $ret .= $this->element(
- 'label',
- $directive_disp,
- // component printers must create an element with this id
- $attr
- );
- if ($this->docURL) $ret .= $this->end('a');
+ $ret .= $this->element(
+ 'label',
+ $directive_disp,
+ // component printers must create an element with this id
+ $attr
+ );
+ if ($this->docURL) {
+ $ret .= $this->end('a');
+ }
$ret .= $this->end('th');
$ret .= $this->start('td');
- $def = $this->config->def->info["$ns.$directive"];
- if (is_int($def)) {
- $allow_null = $def < 0;
- $type = abs($def);
- } else {
- $type = $def->type;
- $allow_null = isset($def->allow_null);
- }
- if (!isset($this->fields[$type])) $type = 0; // default
- $type_obj = $this->fields[$type];
- if ($allow_null) {
- $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj);
- }
- $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config));
+ $def = $this->config->def->info["$ns.$directive"];
+ if (is_int($def)) {
+ $allow_null = $def < 0;
+ $type = abs($def);
+ } else {
+ $type = $def->type;
+ $allow_null = isset($def->allow_null);
+ }
+ if (!isset($this->fields[$type])) {
+ $type = 0;
+ } // default
+ $type_obj = $this->fields[$type];
+ if ($allow_null) {
+ $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj);
+ }
+ $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config));
$ret .= $this->end('td');
$ret .= $this->end('tr');
}
@@ -185,19 +207,33 @@ class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer
/**
* Printer decorator for directives that accept null
*/
-class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer {
+class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
+{
/**
* Printer being decorated
+ * @type HTMLPurifier_Printer
*/
protected $obj;
+
/**
- * @param $obj Printer to decorate
+ * @param HTMLPurifier_Printer $obj Printer to decorate
*/
- public function __construct($obj) {
+ public function __construct($obj)
+ {
parent::__construct();
$this->obj = $obj;
}
- public function render($ns, $directive, $value, $name, $config) {
+
+ /**
+ * @param string $ns
+ * @param string $directive
+ * @param string $value
+ * @param string $name
+ * @param HTMLPurifier_Config|array $config
+ * @return string
+ */
+ public function render($ns, $directive, $value, $name, $config)
+ {
if (is_array($config) && isset($config[0])) {
$gen_config = $config[0];
$config = $config[1];
@@ -215,15 +251,19 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
'type' => 'checkbox',
'value' => '1',
'class' => 'null-toggle',
- 'name' => "$name"."[Null_$ns.$directive]",
+ 'name' => "$name" . "[Null_$ns.$directive]",
'id' => "$name:Null_$ns.$directive",
'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!!
);
if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) {
// modify inline javascript slightly
- $attr['onclick'] = "toggleWriteability('$name:Yes_$ns.$directive',checked);toggleWriteability('$name:No_$ns.$directive',checked)";
+ $attr['onclick'] =
+ "toggleWriteability('$name:Yes_$ns.$directive',checked);" .
+ "toggleWriteability('$name:No_$ns.$directive',checked)";
+ }
+ if ($value === null) {
+ $attr['checked'] = 'checked';
}
- if ($value === null) $attr['checked'] = 'checked';
$ret .= $this->elementEmpty('input', $attr);
$ret .= $this->text(' or ');
$ret .= $this->elementEmpty('br');
@@ -235,10 +275,28 @@ class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer
/**
* Swiss-army knife configuration form field printer
*/
-class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
+class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer
+{
+ /**
+ * @type int
+ */
public $cols = 18;
+
+ /**
+ * @type int
+ */
public $rows = 5;
- public function render($ns, $directive, $value, $name, $config) {
+
+ /**
+ * @param string $ns
+ * @param string $directive
+ * @param string $value
+ * @param string $name
+ * @param HTMLPurifier_Config|array $config
+ * @return string
+ */
+ public function render($ns, $directive, $value, $name, $config)
+ {
if (is_array($config) && isset($config[0])) {
$gen_config = $config[0];
$config = $config[1];
@@ -262,6 +320,7 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
foreach ($array as $val => $b) {
$value[] = $val;
}
+ //TODO does this need a break?
case HTMLPurifier_VarParser::ALIST:
$value = implode(PHP_EOL, $value);
break;
@@ -281,25 +340,27 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
$value = serialize($value);
}
$attr = array(
- 'name' => "$name"."[$ns.$directive]",
+ 'name' => "$name" . "[$ns.$directive]",
'id' => "$name:$ns.$directive"
);
- if ($value === null) $attr['disabled'] = 'disabled';
+ if ($value === null) {
+ $attr['disabled'] = 'disabled';
+ }
if (isset($def->allowed)) {
$ret .= $this->start('select', $attr);
foreach ($def->allowed as $val => $b) {
$attr = array();
- if ($value == $val) $attr['selected'] = 'selected';
+ if ($value == $val) {
+ $attr['selected'] = 'selected';
+ }
$ret .= $this->element('option', $val, $attr);
}
$ret .= $this->end('select');
- } elseif (
- $type === HTMLPurifier_VarParser::TEXT ||
- $type === HTMLPurifier_VarParser::ITEXT ||
- $type === HTMLPurifier_VarParser::ALIST ||
- $type === HTMLPurifier_VarParser::HASH ||
- $type === HTMLPurifier_VarParser::LOOKUP
- ) {
+ } elseif ($type === HTMLPurifier_VarParser::TEXT ||
+ $type === HTMLPurifier_VarParser::ITEXT ||
+ $type === HTMLPurifier_VarParser::ALIST ||
+ $type === HTMLPurifier_VarParser::HASH ||
+ $type === HTMLPurifier_VarParser::LOOKUP) {
$attr['cols'] = $this->cols;
$attr['rows'] = $this->rows;
$ret .= $this->start('textarea', $attr);
@@ -317,8 +378,18 @@ class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer {
/**
* Bool form field printer
*/
-class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer {
- public function render($ns, $directive, $value, $name, $config) {
+class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer
+{
+ /**
+ * @param string $ns
+ * @param string $directive
+ * @param string $value
+ * @param string $name
+ * @param HTMLPurifier_Config|array $config
+ * @return string
+ */
+ public function render($ns, $directive, $value, $name, $config)
+ {
if (is_array($config) && isset($config[0])) {
$gen_config = $config[0];
$config = $config[1];
@@ -336,12 +407,16 @@ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer {
$attr = array(
'type' => 'radio',
- 'name' => "$name"."[$ns.$directive]",
+ 'name' => "$name" . "[$ns.$directive]",
'id' => "$name:Yes_$ns.$directive",
'value' => '1'
);
- if ($value === true) $attr['checked'] = 'checked';
- if ($value === null) $attr['disabled'] = 'disabled';
+ if ($value === true) {
+ $attr['checked'] = 'checked';
+ }
+ if ($value === null) {
+ $attr['disabled'] = 'disabled';
+ }
$ret .= $this->elementEmpty('input', $attr);
$ret .= $this->start('label', array('for' => "$name:No_$ns.$directive"));
@@ -351,12 +426,16 @@ class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer {
$attr = array(
'type' => 'radio',
- 'name' => "$name"."[$ns.$directive]",
+ 'name' => "$name" . "[$ns.$directive]",
'id' => "$name:No_$ns.$directive",
'value' => '0'
);
- if ($value === false) $attr['checked'] = 'checked';
- if ($value === null) $attr['disabled'] = 'disabled';
+ if ($value === false) {
+ $attr['checked'] = 'checked';
+ }
+ if ($value === null) {
+ $attr['disabled'] = 'disabled';
+ }
$ret .= $this->elementEmpty('input', $attr);
$ret .= $this->end('div');
diff --git a/library/HTMLPurifier/Printer/HTMLDefinition.php b/library/HTMLPurifier/Printer/HTMLDefinition.php
index 8a8f126b8..5f2f2f8a7 100644
--- a/library/HTMLPurifier/Printer/HTMLDefinition.php
+++ b/library/HTMLPurifier/Printer/HTMLDefinition.php
@@ -4,11 +4,16 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
{
/**
- * Instance of HTMLPurifier_HTMLDefinition, for easy access
+ * @type HTMLPurifier_HTMLDefinition, for easy access
*/
protected $def;
- public function render($config) {
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return string
+ */
+ public function render($config)
+ {
$ret = '';
$this->config =& $config;
@@ -28,8 +33,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/**
* Renders the Doctype table
+ * @return string
*/
- protected function renderDoctype() {
+ protected function renderDoctype()
+ {
$doctype = $this->def->doctype;
$ret = '';
$ret .= $this->start('table');
@@ -45,8 +52,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/**
* Renders environment table, which is miscellaneous info
+ * @return string
*/
- protected function renderEnvironment() {
+ protected function renderEnvironment()
+ {
$def = $this->def;
$ret = '';
@@ -59,28 +68,28 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
$ret .= $this->row('Block wrap name', $def->info_block_wrapper);
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Global attributes');
- $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr),0,0);
+ $ret .= $this->element('th', 'Global attributes');
+ $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0);
$ret .= $this->end('tr');
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Tag transforms');
- $list = array();
- foreach ($def->info_tag_transform as $old => $new) {
- $new = $this->getClass($new, 'TagTransform_');
- $list[] = "<$old> with $new";
- }
- $ret .= $this->element('td', $this->listify($list));
+ $ret .= $this->element('th', 'Tag transforms');
+ $list = array();
+ foreach ($def->info_tag_transform as $old => $new) {
+ $new = $this->getClass($new, 'TagTransform_');
+ $list[] = "<$old> with $new";
+ }
+ $ret .= $this->element('td', $this->listify($list));
$ret .= $this->end('tr');
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Pre-AttrTransform');
- $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre));
+ $ret .= $this->element('th', 'Pre-AttrTransform');
+ $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre));
$ret .= $this->end('tr');
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Post-AttrTransform');
- $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post));
+ $ret .= $this->element('th', 'Post-AttrTransform');
+ $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post));
$ret .= $this->end('tr');
$ret .= $this->end('table');
@@ -89,8 +98,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/**
* Renders the Content Sets table
+ * @return string
*/
- protected function renderContentSets() {
+ protected function renderContentSets()
+ {
$ret = '';
$ret .= $this->start('table');
$ret .= $this->element('caption', 'Content Sets');
@@ -106,8 +117,10 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/**
* Renders the Elements ($info) table
+ * @return string
*/
- protected function renderInfo() {
+ protected function renderInfo()
+ {
$ret = '';
$ret .= $this->start('table');
$ret .= $this->element('caption', 'Elements ($info)');
@@ -118,39 +131,39 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
$ret .= $this->end('tr');
foreach ($this->def->info as $name => $def) {
$ret .= $this->start('tr');
- $ret .= $this->element('th', "<$name>", array('class'=>'heavy', 'colspan' => 2));
+ $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2));
$ret .= $this->end('tr');
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Inline content');
- $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No');
+ $ret .= $this->element('th', 'Inline content');
+ $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No');
$ret .= $this->end('tr');
if (!empty($def->excludes)) {
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Excludes');
- $ret .= $this->element('td', $this->listifyTagLookup($def->excludes));
+ $ret .= $this->element('th', 'Excludes');
+ $ret .= $this->element('td', $this->listifyTagLookup($def->excludes));
$ret .= $this->end('tr');
}
if (!empty($def->attr_transform_pre)) {
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Pre-AttrTransform');
- $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre));
+ $ret .= $this->element('th', 'Pre-AttrTransform');
+ $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre));
$ret .= $this->end('tr');
}
if (!empty($def->attr_transform_post)) {
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Post-AttrTransform');
- $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post));
+ $ret .= $this->element('th', 'Post-AttrTransform');
+ $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post));
$ret .= $this->end('tr');
}
if (!empty($def->auto_close)) {
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Auto closed by');
- $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close));
+ $ret .= $this->element('th', 'Auto closed by');
+ $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close));
$ret .= $this->end('tr');
}
$ret .= $this->start('tr');
- $ret .= $this->element('th', 'Allowed attributes');
- $ret .= $this->element('td',$this->listifyAttr($def->attr), array(), 0);
+ $ret .= $this->element('th', 'Allowed attributes');
+ $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0);
$ret .= $this->end('tr');
if (!empty($def->required_attr)) {
@@ -165,64 +178,94 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/**
* Renders a row describing the allowed children of an element
- * @param $def HTMLPurifier_ChildDef of pertinent element
+ * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element
+ * @return string
*/
- protected function renderChildren($def) {
+ protected function renderChildren($def)
+ {
$context = new HTMLPurifier_Context();
$ret = '';
$ret .= $this->start('tr');
- $elements = array();
- $attr = array();
- if (isset($def->elements)) {
- if ($def->type == 'strictblockquote') {
- $def->validateChildren(array(), $this->config, $context);
- }
- $elements = $def->elements;
+ $elements = array();
+ $attr = array();
+ if (isset($def->elements)) {
+ if ($def->type == 'strictblockquote') {
+ $def->validateChildren(array(), $this->config, $context);
}
- if ($def->type == 'chameleon') {
- $attr['rowspan'] = 2;
- } elseif ($def->type == 'empty') {
- $elements = array();
- } elseif ($def->type == 'table') {
- $elements = array_flip(array('col', 'caption', 'colgroup', 'thead',
- 'tfoot', 'tbody', 'tr'));
- }
- $ret .= $this->element('th', 'Allowed children', $attr);
-
- if ($def->type == 'chameleon') {
-
- $ret .= $this->element('td',
- '<em>Block</em>: ' .
- $this->escape($this->listifyTagLookup($def->block->elements)),0,0);
- $ret .= $this->end('tr');
- $ret .= $this->start('tr');
- $ret .= $this->element('td',
- '<em>Inline</em>: ' .
- $this->escape($this->listifyTagLookup($def->inline->elements)),0,0);
-
- } elseif ($def->type == 'custom') {
+ $elements = $def->elements;
+ }
+ if ($def->type == 'chameleon') {
+ $attr['rowspan'] = 2;
+ } elseif ($def->type == 'empty') {
+ $elements = array();
+ } elseif ($def->type == 'table') {
+ $elements = array_flip(
+ array(
+ 'col',
+ 'caption',
+ 'colgroup',
+ 'thead',
+ 'tfoot',
+ 'tbody',
+ 'tr'
+ )
+ );
+ }
+ $ret .= $this->element('th', 'Allowed children', $attr);
- $ret .= $this->element('td', '<em>'.ucfirst($def->type).'</em>: ' .
- $def->dtd_regex);
+ if ($def->type == 'chameleon') {
- } else {
- $ret .= $this->element('td',
- '<em>'.ucfirst($def->type).'</em>: ' .
- $this->escape($this->listifyTagLookup($elements)),0,0);
- }
+ $ret .= $this->element(
+ 'td',
+ '<em>Block</em>: ' .
+ $this->escape($this->listifyTagLookup($def->block->elements)),
+ null,
+ 0
+ );
+ $ret .= $this->end('tr');
+ $ret .= $this->start('tr');
+ $ret .= $this->element(
+ 'td',
+ '<em>Inline</em>: ' .
+ $this->escape($this->listifyTagLookup($def->inline->elements)),
+ null,
+ 0
+ );
+
+ } elseif ($def->type == 'custom') {
+
+ $ret .= $this->element(
+ 'td',
+ '<em>' . ucfirst($def->type) . '</em>: ' .
+ $def->dtd_regex
+ );
+
+ } else {
+ $ret .= $this->element(
+ 'td',
+ '<em>' . ucfirst($def->type) . '</em>: ' .
+ $this->escape($this->listifyTagLookup($elements)),
+ null,
+ 0
+ );
+ }
$ret .= $this->end('tr');
return $ret;
}
/**
* Listifies a tag lookup table.
- * @param $array Tag lookup array in form of array('tagname' => true)
+ * @param array $array Tag lookup array in form of array('tagname' => true)
+ * @return string
*/
- protected function listifyTagLookup($array) {
+ protected function listifyTagLookup($array)
+ {
ksort($array);
$list = array();
foreach ($array as $name => $discard) {
- if ($name !== '#PCDATA' && !isset($this->def->info[$name])) continue;
+ if ($name !== '#PCDATA' && !isset($this->def->info[$name])) {
+ continue;
+ }
$list[] = $name;
}
return $this->listify($list);
@@ -230,13 +273,15 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/**
* Listifies a list of objects by retrieving class names and internal state
- * @param $array List of objects
+ * @param array $array List of objects
+ * @return string
* @todo Also add information about internal state
*/
- protected function listifyObjectList($array) {
+ protected function listifyObjectList($array)
+ {
ksort($array);
$list = array();
- foreach ($array as $discard => $obj) {
+ foreach ($array as $obj) {
$list[] = $this->getClass($obj, 'AttrTransform_');
}
return $this->listify($list);
@@ -244,13 +289,17 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/**
* Listifies a hash of attributes to AttrDef classes
- * @param $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef)
+ * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef)
+ * @return string
*/
- protected function listifyAttr($array) {
+ protected function listifyAttr($array)
+ {
ksort($array);
$list = array();
foreach ($array as $name => $obj) {
- if ($obj === false) continue;
+ if ($obj === false) {
+ continue;
+ }
$list[] = "$name&nbsp;=&nbsp;<i>" . $this->getClass($obj, 'AttrDef_') . '</i>';
}
return $this->listify($list);
@@ -258,15 +307,18 @@ class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
/**
* Creates a heavy header row
+ * @param string $text
+ * @param int $num
+ * @return string
*/
- protected function heavyHeader($text, $num = 1) {
+ protected function heavyHeader($text, $num = 1)
+ {
$ret = '';
$ret .= $this->start('tr');
$ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy'));
$ret .= $this->end('tr');
return $ret;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/PropertyList.php b/library/HTMLPurifier/PropertyList.php
index 2b99fb7bc..189348fd9 100644
--- a/library/HTMLPurifier/PropertyList.php
+++ b/library/HTMLPurifier/PropertyList.php
@@ -6,61 +6,93 @@
class HTMLPurifier_PropertyList
{
/**
- * Internal data-structure for properties
+ * Internal data-structure for properties.
+ * @type array
*/
protected $data = array();
/**
- * Parent plist
+ * Parent plist.
+ * @type HTMLPurifier_PropertyList
*/
protected $parent;
+ /**
+ * Cache.
+ * @type array
+ */
protected $cache;
- public function __construct($parent = null) {
+ /**
+ * @param HTMLPurifier_PropertyList $parent Parent plist
+ */
+ public function __construct($parent = null)
+ {
$this->parent = $parent;
}
/**
* Recursively retrieves the value for a key
+ * @param string $name
+ * @throws HTMLPurifier_Exception
*/
- public function get($name) {
- if ($this->has($name)) return $this->data[$name];
+ public function get($name)
+ {
+ if ($this->has($name)) {
+ return $this->data[$name];
+ }
// possible performance bottleneck, convert to iterative if necessary
- if ($this->parent) return $this->parent->get($name);
+ if ($this->parent) {
+ return $this->parent->get($name);
+ }
throw new HTMLPurifier_Exception("Key '$name' not found");
}
/**
* Sets the value of a key, for this plist
+ * @param string $name
+ * @param mixed $value
*/
- public function set($name, $value) {
+ public function set($name, $value)
+ {
$this->data[$name] = $value;
}
/**
* Returns true if a given key exists
+ * @param string $name
+ * @return bool
*/
- public function has($name) {
+ public function has($name)
+ {
return array_key_exists($name, $this->data);
}
/**
* Resets a value to the value of it's parent, usually the default. If
* no value is specified, the entire plist is reset.
+ * @param string $name
*/
- public function reset($name = null) {
- if ($name == null) $this->data = array();
- else unset($this->data[$name]);
+ public function reset($name = null)
+ {
+ if ($name == null) {
+ $this->data = array();
+ } else {
+ unset($this->data[$name]);
+ }
}
/**
* Squashes this property list and all of its property lists into a single
* array, and returns the array. This value is cached by default.
- * @param $force If true, ignores the cache and regenerates the array.
+ * @param bool $force If true, ignores the cache and regenerates the array.
+ * @return array
*/
- public function squash($force = false) {
- if ($this->cache !== null && !$force) return $this->cache;
+ public function squash($force = false)
+ {
+ if ($this->cache !== null && !$force) {
+ return $this->cache;
+ }
if ($this->parent) {
return $this->cache = array_merge($this->parent->squash($force), $this->data);
} else {
@@ -70,15 +102,19 @@ class HTMLPurifier_PropertyList
/**
* Returns the parent plist.
+ * @return HTMLPurifier_PropertyList
*/
- public function getParent() {
+ public function getParent()
+ {
return $this->parent;
}
/**
* Sets the parent plist.
+ * @param HTMLPurifier_PropertyList $plist Parent plist
*/
- public function setParent($plist) {
+ public function setParent($plist)
+ {
$this->parent = $plist;
}
}
diff --git a/library/HTMLPurifier/PropertyListIterator.php b/library/HTMLPurifier/PropertyListIterator.php
index 8f250443e..15b330ea3 100644
--- a/library/HTMLPurifier/PropertyListIterator.php
+++ b/library/HTMLPurifier/PropertyListIterator.php
@@ -6,27 +6,37 @@
class HTMLPurifier_PropertyListIterator extends FilterIterator
{
+ /**
+ * @type int
+ */
protected $l;
+ /**
+ * @type string
+ */
protected $filter;
/**
- * @param $data Array of data to iterate over
- * @param $filter Optional prefix to only allow values of
+ * @param Iterator $iterator Array of data to iterate over
+ * @param string $filter Optional prefix to only allow values of
*/
- public function __construct(Iterator $iterator, $filter = null) {
+ public function __construct(Iterator $iterator, $filter = null)
+ {
parent::__construct($iterator);
$this->l = strlen($filter);
$this->filter = $filter;
}
- public function accept() {
+ /**
+ * @return bool
+ */
+ public function accept()
+ {
$key = $this->getInnerIterator()->key();
- if( strncmp($key, $this->filter, $this->l) !== 0 ) {
+ if (strncmp($key, $this->filter, $this->l) !== 0) {
return false;
}
return true;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Queue.php b/library/HTMLPurifier/Queue.php
new file mode 100644
index 000000000..f58db9042
--- /dev/null
+++ b/library/HTMLPurifier/Queue.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * A simple array-backed queue, based off of the classic Okasaki
+ * persistent amortized queue. The basic idea is to maintain two
+ * stacks: an input stack and an output stack. When the output
+ * stack runs out, reverse the input stack and use it as the output
+ * stack.
+ *
+ * We don't use the SPL implementation because it's only supported
+ * on PHP 5.3 and later.
+ *
+ * Exercise: Prove that push/pop on this queue take amortized O(1) time.
+ *
+ * Exercise: Extend this queue to be a deque, while preserving amortized
+ * O(1) time. Some care must be taken on rebalancing to avoid quadratic
+ * behaviour caused by repeatedly shuffling data from the input stack
+ * to the output stack and back.
+ */
+class HTMLPurifier_Queue {
+ private $input;
+ private $output;
+
+ public function __construct($input = array()) {
+ $this->input = $input;
+ $this->output = array();
+ }
+
+ /**
+ * Shifts an element off the front of the queue.
+ */
+ public function shift() {
+ if (empty($this->output)) {
+ $this->output = array_reverse($this->input);
+ $this->input = array();
+ }
+ if (empty($this->output)) {
+ return NULL;
+ }
+ return array_pop($this->output);
+ }
+
+ /**
+ * Pushes an element onto the front of the queue.
+ */
+ public function push($x) {
+ array_push($this->input, $x);
+ }
+
+ /**
+ * Checks if it's empty.
+ */
+ public function isEmpty() {
+ return empty($this->input) && empty($this->output);
+ }
+}
diff --git a/library/HTMLPurifier/Strategy.php b/library/HTMLPurifier/Strategy.php
index 246286521..e1ff3b72d 100644
--- a/library/HTMLPurifier/Strategy.php
+++ b/library/HTMLPurifier/Strategy.php
@@ -15,12 +15,12 @@ abstract class HTMLPurifier_Strategy
/**
* Executes the strategy on the tokens.
*
- * @param $tokens Array of HTMLPurifier_Token objects to be operated on.
- * @param $config Configuration options
- * @returns Processed array of token objects.
+ * @param HTMLPurifier_Token[] $tokens Array of HTMLPurifier_Token objects to be operated on.
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_Token[] Processed array of token objects.
*/
abstract public function execute($tokens, $config, $context);
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Strategy/Composite.php b/library/HTMLPurifier/Strategy/Composite.php
index 816490b79..d7d35ce7d 100644
--- a/library/HTMLPurifier/Strategy/Composite.php
+++ b/library/HTMLPurifier/Strategy/Composite.php
@@ -8,18 +8,23 @@ abstract class HTMLPurifier_Strategy_Composite extends HTMLPurifier_Strategy
/**
* List of strategies to run tokens through.
+ * @type HTMLPurifier_Strategy[]
*/
protected $strategies = array();
- abstract public function __construct();
-
- public function execute($tokens, $config, $context) {
+ /**
+ * @param HTMLPurifier_Token[] $tokens
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_Token[]
+ */
+ public function execute($tokens, $config, $context)
+ {
foreach ($this->strategies as $strategy) {
$tokens = $strategy->execute($tokens, $config, $context);
}
return $tokens;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Strategy/Core.php b/library/HTMLPurifier/Strategy/Core.php
index d90e15860..4414c17d6 100644
--- a/library/HTMLPurifier/Strategy/Core.php
+++ b/library/HTMLPurifier/Strategy/Core.php
@@ -5,14 +5,13 @@
*/
class HTMLPurifier_Strategy_Core extends HTMLPurifier_Strategy_Composite
{
-
- public function __construct() {
+ public function __construct()
+ {
$this->strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements();
$this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed();
$this->strategies[] = new HTMLPurifier_Strategy_FixNesting();
$this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes();
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Strategy/FixNesting.php b/library/HTMLPurifier/Strategy/FixNesting.php
index f81802391..6fa673db9 100644
--- a/library/HTMLPurifier/Strategy/FixNesting.php
+++ b/library/HTMLPurifier/Strategy/FixNesting.php
@@ -10,12 +10,12 @@
* document type definitions, such as the chameleon nature of ins/del
* tags and global child exclusions.
*
- * The first major objective of this strategy is to iterate through all the
- * nodes (not tokens) of the list of tokens and determine whether or not
- * their children conform to the element's definition. If they do not, the
- * child definition may optionally supply an amended list of elements that
- * is valid or require that the entire node be deleted (and the previous
- * node rescanned).
+ * The first major objective of this strategy is to iterate through all
+ * the nodes and determine whether or not their children conform to the
+ * element's definition. If they do not, the child definition may
+ * optionally supply an amended list of elements that is valid or
+ * require that the entire node be deleted (and the previous node
+ * rescanned).
*
* The second objective is to ensure that explicitly excluded elements of
* an element do not appear in its children. Code that accomplishes this
@@ -25,24 +25,33 @@
* @note Whether or not unrecognized children are silently dropped or
* translated into text depends on the child definitions.
*
- * @todo Enable nodes to be bubbled out of the structure.
+ * @todo Enable nodes to be bubbled out of the structure. This is
+ * easier with our new algorithm.
*/
class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy
{
- public function execute($tokens, $config, $context) {
+ /**
+ * @param HTMLPurifier_Token[] $tokens
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array|HTMLPurifier_Token[]
+ */
+ public function execute($tokens, $config, $context)
+ {
+
//####################################################################//
// Pre-processing
+ // O(n) pass to convert to a tree, so that we can efficiently
+ // refer to substrings
+ $top_node = HTMLPurifier_Arborize::arborize($tokens, $config, $context);
+
// get a copy of the HTML definition
$definition = $config->getHTMLDefinition();
- // insert implicit "parent" node, will be removed at end.
- // DEFINITION CALL
- $parent_name = $definition->info_parent;
- array_unshift($tokens, new HTMLPurifier_Token_Start($parent_name));
- $tokens[] = new HTMLPurifier_Token_End($parent_name);
+ $excludes_enabled = !$config->get('Core.DisableExcludes');
// setup the context variable 'IsInline', for chameleon processing
// is 'false' when we are not inline, 'true' when it must always
@@ -57,272 +66,116 @@ class HTMLPurifier_Strategy_FixNesting extends HTMLPurifier_Strategy
//####################################################################//
// Loop initialization
- // stack that contains the indexes of all parents,
- // $stack[count($stack)-1] being the current parent
- $stack = array();
-
// stack that contains all elements that are excluded
// it is organized by parent elements, similar to $stack,
// but it is only populated when an element with exclusions is
// processed, i.e. there won't be empty exclusions.
- $exclude_stack = array();
+ $exclude_stack = array($definition->info_parent_def->excludes);
// variable that contains the start token while we are processing
// nodes. This enables error reporting to do its job
- $start_token = false;
- $context->register('CurrentToken', $start_token);
+ $node = $top_node;
+ // dummy token
+ list($token, $d) = $node->toTokenPair();
+ $context->register('CurrentNode', $node);
+ $context->register('CurrentToken', $token);
//####################################################################//
// Loop
- // iterate through all start nodes. Determining the start node
- // is complicated so it has been omitted from the loop construct
- for ($i = 0, $size = count($tokens) ; $i < $size; ) {
-
- //################################################################//
- // Gather information on children
-
- // child token accumulator
- $child_tokens = array();
-
- // scroll to the end of this node, report number, and collect
- // all children
- for ($j = $i, $depth = 0; ; $j++) {
- if ($tokens[$j] instanceof HTMLPurifier_Token_Start) {
- $depth++;
- // skip token assignment on first iteration, this is the
- // token we currently are on
- if ($depth == 1) continue;
- } elseif ($tokens[$j] instanceof HTMLPurifier_Token_End) {
- $depth--;
- // skip token assignment on last iteration, this is the
- // end token of the token we're currently on
- if ($depth == 0) break;
- }
- $child_tokens[] = $tokens[$j];
- }
-
- // $i is index of start token
- // $j is index of end token
-
- $start_token = $tokens[$i]; // to make token available via CurrentToken
-
- //################################################################//
- // Gather information on parent
-
- // calculate parent information
- if ($count = count($stack)) {
- $parent_index = $stack[$count-1];
- $parent_name = $tokens[$parent_index]->name;
- if ($parent_index == 0) {
- $parent_def = $definition->info_parent_def;
- } else {
- $parent_def = $definition->info[$parent_name];
- }
- } else {
- // processing as if the parent were the "root" node
- // unknown info, it won't be used anyway, in the future,
- // we may want to enforce one element only (this is
- // necessary for HTML Purifier to clean entire documents
- $parent_index = $parent_name = $parent_def = null;
- }
-
- // calculate context
- if ($is_inline === false) {
- // check if conditions make it inline
- if (!empty($parent_def) && $parent_def->descendants_are_inline) {
- $is_inline = $count - 1;
- }
- } else {
- // check if we're out of inline
- if ($count === $is_inline) {
- $is_inline = false;
- }
- }
-
- //################################################################//
- // Determine whether element is explicitly excluded SGML-style
-
- // determine whether or not element is excluded by checking all
- // parent exclusions. The array should not be very large, two
- // elements at most.
- $excluded = false;
- if (!empty($exclude_stack)) {
- foreach ($exclude_stack as $lookup) {
- if (isset($lookup[$tokens[$i]->name])) {
- $excluded = true;
- // no need to continue processing
- break;
- }
+ // We need to implement a post-order traversal iteratively, to
+ // avoid running into stack space limits. This is pretty tricky
+ // to reason about, so we just manually stack-ify the recursive
+ // variant:
+ //
+ // function f($node) {
+ // foreach ($node->children as $child) {
+ // f($child);
+ // }
+ // validate($node);
+ // }
+ //
+ // Thus, we will represent a stack frame as array($node,
+ // $is_inline, stack of children)
+ // e.g. array_reverse($node->children) - already processed
+ // children.
+
+ $parent_def = $definition->info_parent_def;
+ $stack = array(
+ array($top_node,
+ $parent_def->descendants_are_inline,
+ $parent_def->excludes, // exclusions
+ 0)
+ );
+
+ while (!empty($stack)) {
+ list($node, $is_inline, $excludes, $ix) = array_pop($stack);
+ // recursive call
+ $go = false;
+ $def = empty($stack) ? $definition->info_parent_def : $definition->info[$node->name];
+ while (isset($node->children[$ix])) {
+ $child = $node->children[$ix++];
+ if ($child instanceof HTMLPurifier_Node_Element) {
+ $go = true;
+ $stack[] = array($node, $is_inline, $excludes, $ix);
+ $stack[] = array($child,
+ // ToDo: I don't think it matters if it's def or
+ // child_def, but double check this...
+ $is_inline || $def->descendants_are_inline,
+ empty($def->excludes) ? $excludes
+ : array_merge($excludes, $def->excludes),
+ 0);
+ break;
}
- }
-
- //################################################################//
- // Perform child validation
-
- if ($excluded) {
- // there is an exclusion, remove the entire node
- $result = false;
- $excludes = array(); // not used, but good to initialize anyway
+ };
+ if ($go) continue;
+ list($token, $d) = $node->toTokenPair();
+ // base case
+ if ($excludes_enabled && isset($excludes[$node->name])) {
+ $node->dead = true;
+ if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded');
} else {
- // DEFINITION CALL
- if ($i === 0) {
- // special processing for the first node
- $def = $definition->info_parent_def;
- } else {
- $def = $definition->info[$tokens[$i]->name];
-
+ // XXX I suppose it would be slightly more efficient to
+ // avoid the allocation here and have children
+ // strategies handle it
+ $children = array();
+ foreach ($node->children as $child) {
+ if (!$child->dead) $children[] = $child;
}
-
- if (!empty($def->child)) {
- // have DTD child def validate children
- $result = $def->child->validateChildren(
- $child_tokens, $config, $context);
+ $result = $def->child->validateChildren($children, $config, $context);
+ if ($result === true) {
+ // nop
+ $node->children = $children;
+ } elseif ($result === false) {
+ $node->dead = true;
+ if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node removed');
} else {
- // weird, no child definition, get rid of everything
- $result = false;
- }
-
- // determine whether or not this element has any exclusions
- $excludes = $def->excludes;
- }
-
- // $result is now a bool or array
-
- //################################################################//
- // Process result by interpreting $result
-
- if ($result === true || $child_tokens === $result) {
- // leave the node as is
-
- // register start token as a parental node start
- $stack[] = $i;
-
- // register exclusions if there are any
- if (!empty($excludes)) $exclude_stack[] = $excludes;
-
- // move cursor to next possible start node
- $i++;
-
- } elseif($result === false) {
- // remove entire node
-
- if ($e) {
- if ($excluded) {
- $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded');
- } else {
- $e->send(E_ERROR, 'Strategy_FixNesting: Node removed');
- }
- }
-
- // calculate length of inner tokens and current tokens
- $length = $j - $i + 1;
-
- // perform removal
- array_splice($tokens, $i, $length);
-
- // update size
- $size -= $length;
-
- // there is no start token to register,
- // current node is now the next possible start node
- // unless it turns out that we need to do a double-check
-
- // this is a rought heuristic that covers 100% of HTML's
- // cases and 99% of all other cases. A child definition
- // that would be tricked by this would be something like:
- // ( | a b c) where it's all or nothing. Fortunately,
- // our current implementation claims that that case would
- // not allow empty, even if it did
- if (!$parent_def->child->allow_empty) {
- // we need to do a double-check
- $i = $parent_index;
- array_pop($stack);
- }
-
- // PROJECTED OPTIMIZATION: Process all children elements before
- // reprocessing parent node.
-
- } else {
- // replace node with $result
-
- // calculate length of inner tokens
- $length = $j - $i - 1;
-
- if ($e) {
- if (empty($result) && $length) {
- $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed');
- } else {
- $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized');
+ $node->children = $result;
+ if ($e) {
+ // XXX This will miss mutations of internal nodes. Perhaps defer to the child validators
+ if (empty($result) && !empty($children)) {
+ $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed');
+ } else if ($result != $children) {
+ $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized');
+ }
}
}
-
- // perform replacement
- array_splice($tokens, $i + 1, $length, $result);
-
- // update size
- $size -= $length;
- $size += count($result);
-
- // register start token as a parental node start
- $stack[] = $i;
-
- // register exclusions if there are any
- if (!empty($excludes)) $exclude_stack[] = $excludes;
-
- // move cursor to next possible start node
- $i++;
-
}
-
- //################################################################//
- // Scroll to next start node
-
- // We assume, at this point, that $i is the index of the token
- // that is the first possible new start point for a node.
-
- // Test if the token indeed is a start tag, if not, move forward
- // and test again.
- $size = count($tokens);
- while ($i < $size and !$tokens[$i] instanceof HTMLPurifier_Token_Start) {
- if ($tokens[$i] instanceof HTMLPurifier_Token_End) {
- // pop a token index off the stack if we ended a node
- array_pop($stack);
- // pop an exclusion lookup off exclusion stack if
- // we ended node and that node had exclusions
- if ($i == 0 || $i == $size - 1) {
- // use specialized var if it's the super-parent
- $s_excludes = $definition->info_parent_def->excludes;
- } else {
- $s_excludes = $definition->info[$tokens[$i]->name]->excludes;
- }
- if ($s_excludes) {
- array_pop($exclude_stack);
- }
- }
- $i++;
- }
-
}
//####################################################################//
// Post-processing
- // remove implicit parent tokens at the beginning and end
- array_shift($tokens);
- array_pop($tokens);
-
// remove context variables
$context->destroy('IsInline');
+ $context->destroy('CurrentNode');
$context->destroy('CurrentToken');
//####################################################################//
// Return
- return $tokens;
-
+ return HTMLPurifier_Arborize::flatten($node, $config, $context);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Strategy/MakeWellFormed.php b/library/HTMLPurifier/Strategy/MakeWellFormed.php
index c73658400..e389e0011 100644
--- a/library/HTMLPurifier/Strategy/MakeWellFormed.php
+++ b/library/HTMLPurifier/Strategy/MakeWellFormed.php
@@ -2,66 +2,97 @@
/**
* Takes tokens makes them well-formed (balance end tags, etc.)
+ *
+ * Specification of the armor attributes this strategy uses:
+ *
+ * - MakeWellFormed_TagClosedError: This armor field is used to
+ * suppress tag closed errors for certain tokens [TagClosedSuppress],
+ * in particular, if a tag was generated automatically by HTML
+ * Purifier, we may rely on our infrastructure to close it for us
+ * and shouldn't report an error to the user [TagClosedAuto].
*/
class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
{
/**
* Array stream of tokens being processed.
+ * @type HTMLPurifier_Token[]
*/
protected $tokens;
/**
- * Current index in $tokens.
+ * Current token.
+ * @type HTMLPurifier_Token
*/
- protected $t;
+ protected $token;
+
+ /**
+ * Zipper managing the true state.
+ * @type HTMLPurifier_Zipper
+ */
+ protected $zipper;
/**
* Current nesting of elements.
+ * @type array
*/
protected $stack;
/**
* Injectors active in this stream processing.
+ * @type HTMLPurifier_Injector[]
*/
protected $injectors;
/**
* Current instance of HTMLPurifier_Config.
+ * @type HTMLPurifier_Config
*/
protected $config;
/**
* Current instance of HTMLPurifier_Context.
+ * @type HTMLPurifier_Context
*/
protected $context;
- public function execute($tokens, $config, $context) {
-
+ /**
+ * @param HTMLPurifier_Token[] $tokens
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_Token[]
+ * @throws HTMLPurifier_Exception
+ */
+ public function execute($tokens, $config, $context)
+ {
$definition = $config->getHTMLDefinition();
// local variables
$generator = new HTMLPurifier_Generator($config, $context);
$escape_invalid_tags = $config->get('Core.EscapeInvalidTags');
+ // used for autoclose early abortion
+ $global_parent_allowed_elements = $definition->info_parent_def->child->getAllowedElements($config);
$e = $context->get('ErrorCollector', true);
- $t = false; // token index
$i = false; // injector index
- $token = false; // the current token
- $reprocess = false; // whether or not to reprocess the same token
+ list($zipper, $token) = HTMLPurifier_Zipper::fromArray($tokens);
+ if ($token === NULL) {
+ return array();
+ }
+ $reprocess = false; // whether or not to reprocess the same token
$stack = array();
// member variables
- $this->stack =& $stack;
- $this->t =& $t;
- $this->tokens =& $tokens;
- $this->config = $config;
+ $this->stack =& $stack;
+ $this->tokens =& $tokens;
+ $this->token =& $token;
+ $this->zipper =& $zipper;
+ $this->config = $config;
$this->context = $context;
// context variables
$context->register('CurrentNesting', $stack);
- $context->register('InputIndex', $t);
- $context->register('InputTokens', $tokens);
- $context->register('CurrentToken', $token);
+ $context->register('InputZipper', $zipper);
+ $context->register('CurrentToken', $token);
// -- begin INJECTOR --
@@ -73,9 +104,13 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
unset($injectors['Custom']); // special case
foreach ($injectors as $injector => $b) {
// XXX: Fix with a legitimate lookup table of enabled filters
- if (strpos($injector, '.') !== false) continue;
+ if (strpos($injector, '.') !== false) {
+ continue;
+ }
$injector = "HTMLPurifier_Injector_$injector";
- if (!$b) continue;
+ if (!$b) {
+ continue;
+ }
$this->injectors[] = new $injector;
}
foreach ($def_injectors as $injector) {
@@ -83,7 +118,9 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
$this->injectors[] = $injector;
}
foreach ($custom_injectors as $injector) {
- if (!$injector) continue;
+ if (!$injector) {
+ continue;
+ }
if (is_string($injector)) {
$injector = "HTMLPurifier_Injector_$injector";
$injector = new $injector;
@@ -95,14 +132,16 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// variables for performance reasons
foreach ($this->injectors as $ix => $injector) {
$error = $injector->prepare($config, $context);
- if (!$error) continue;
+ if (!$error) {
+ continue;
+ }
array_splice($this->injectors, $ix, 1); // rm the injector
trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING);
}
// -- end INJECTOR --
- // a note on punting:
+ // a note on reprocessing:
// In order to reduce code duplication, whenever some code needs
// to make HTML changes in order to make things "correct", the
// new HTML gets sent through the purifier, regardless of its
@@ -111,70 +150,75 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// punt ($reprocess = true; continue;) and it does that for us.
// isset is in loop because $tokens size changes during loop exec
- for (
- $t = 0;
- $t == 0 || isset($tokens[$t - 1]);
- // only increment if we don't need to reprocess
- $reprocess ? $reprocess = false : $t++
- ) {
+ for (;;
+ // only increment if we don't need to reprocess
+ $reprocess ? $reprocess = false : $token = $zipper->next($token)) {
// check for a rewind
- if (is_int($i) && $i >= 0) {
+ if (is_int($i)) {
// possibility: disable rewinding if the current token has a
// rewind set on it already. This would offer protection from
// infinite loop, but might hinder some advanced rewinding.
- $rewind_to = $this->injectors[$i]->getRewind();
- if (is_int($rewind_to) && $rewind_to < $t) {
- if ($rewind_to < 0) $rewind_to = 0;
- while ($t > $rewind_to) {
- $t--;
- $prev = $tokens[$t];
+ $rewind_offset = $this->injectors[$i]->getRewindOffset();
+ if (is_int($rewind_offset)) {
+ for ($j = 0; $j < $rewind_offset; $j++) {
+ if (empty($zipper->front)) break;
+ $token = $zipper->prev($token);
// indicate that other injectors should not process this token,
// but we need to reprocess it
- unset($prev->skip[$i]);
- $prev->rewind = $i;
- if ($prev instanceof HTMLPurifier_Token_Start) array_pop($this->stack);
- elseif ($prev instanceof HTMLPurifier_Token_End) $this->stack[] = $prev->start;
+ unset($token->skip[$i]);
+ $token->rewind = $i;
+ if ($token instanceof HTMLPurifier_Token_Start) {
+ array_pop($this->stack);
+ } elseif ($token instanceof HTMLPurifier_Token_End) {
+ $this->stack[] = $token->start;
+ }
}
}
$i = false;
}
// handle case of document end
- if (!isset($tokens[$t])) {
+ if ($token === NULL) {
// kill processing if stack is empty
- if (empty($this->stack)) break;
+ if (empty($this->stack)) {
+ break;
+ }
// peek
$top_nesting = array_pop($this->stack);
$this->stack[] = $top_nesting;
- // send error
+ // send error [TagClosedSuppress]
if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) {
$e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting);
}
// append, don't splice, since this is the end
- $tokens[] = new HTMLPurifier_Token_End($top_nesting->name);
+ $token = new HTMLPurifier_Token_End($top_nesting->name);
// punt!
$reprocess = true;
continue;
}
- $token = $tokens[$t];
-
- //echo '<br>'; printTokens($tokens, $t); printTokens($this->stack);
+ //echo '<br>'; printZipper($zipper, $token);//printTokens($this->stack);
//flush();
// quick-check: if it's not a tag, no need to process
if (empty($token->is_tag)) {
if ($token instanceof HTMLPurifier_Token_Text) {
foreach ($this->injectors as $i => $injector) {
- if (isset($token->skip[$i])) continue;
- if ($token->rewind !== null && $token->rewind !== $i) continue;
- $injector->handleText($token);
- $this->processToken($token, $i);
+ if (isset($token->skip[$i])) {
+ continue;
+ }
+ if ($token->rewind !== null && $token->rewind !== $i) {
+ continue;
+ }
+ // XXX fuckup
+ $r = $token;
+ $injector->handleText($r);
+ $token = $this->processToken($r, $i);
$reprocess = true;
break;
}
@@ -193,12 +237,22 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
$ok = false;
if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) {
// claims to be a start tag but is empty
- $token = new HTMLPurifier_Token_Empty($token->name, $token->attr);
+ $token = new HTMLPurifier_Token_Empty(
+ $token->name,
+ $token->attr,
+ $token->line,
+ $token->col,
+ $token->armor
+ );
$ok = true;
} elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) {
// claims to be empty but really is a start tag
- $this->swap(new HTMLPurifier_Token_End($token->name));
- $this->insertBefore(new HTMLPurifier_Token_Start($token->name, $token->attr));
+ // NB: this assignment is required
+ $old_token = $token;
+ $token = new HTMLPurifier_Token_End($token->name);
+ $token = $this->insertBefore(
+ new HTMLPurifier_Token_Start($old_token->name, $old_token->attr, $old_token->line, $old_token->col, $old_token->armor)
+ );
// punt (since we had to modify the input stream in a non-trivial way)
$reprocess = true;
continue;
@@ -211,55 +265,96 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// ...unless they also have to close their parent
if (!empty($this->stack)) {
+ // Performance note: you might think that it's rather
+ // inefficient, recalculating the autoclose information
+ // for every tag that a token closes (since when we
+ // do an autoclose, we push a new token into the
+ // stream and then /process/ that, before
+ // re-processing this token.) But this is
+ // necessary, because an injector can make an
+ // arbitrary transformations to the autoclosing
+ // tokens we introduce, so things may have changed
+ // in the meantime. Also, doing the inefficient thing is
+ // "easy" to reason about (for certain perverse definitions
+ // of "easy")
+
$parent = array_pop($this->stack);
$this->stack[] = $parent;
+ $parent_def = null;
+ $parent_elements = null;
+ $autoclose = false;
if (isset($definition->info[$parent->name])) {
- $elements = $definition->info[$parent->name]->child->getAllowedElements($config);
- $autoclose = !isset($elements[$token->name]);
- } else {
- $autoclose = false;
+ $parent_def = $definition->info[$parent->name];
+ $parent_elements = $parent_def->child->getAllowedElements($config);
+ $autoclose = !isset($parent_elements[$token->name]);
}
if ($autoclose && $definition->info[$token->name]->wrap) {
- // Check if an element can be wrapped by another
- // element to make it valid in a context (for
+ // Check if an element can be wrapped by another
+ // element to make it valid in a context (for
// example, <ul><ul> needs a <li> in between)
$wrapname = $definition->info[$token->name]->wrap;
$wrapdef = $definition->info[$wrapname];
$elements = $wrapdef->child->getAllowedElements($config);
- $parent_elements = $definition->info[$parent->name]->child->getAllowedElements($config);
if (isset($elements[$token->name]) && isset($parent_elements[$wrapname])) {
$newtoken = new HTMLPurifier_Token_Start($wrapname);
- $this->insertBefore($newtoken);
+ $token = $this->insertBefore($newtoken);
$reprocess = true;
continue;
}
}
$carryover = false;
- if ($autoclose && $definition->info[$parent->name]->formatting) {
+ if ($autoclose && $parent_def->formatting) {
$carryover = true;
}
if ($autoclose) {
- // errors need to be updated
- $new_token = new HTMLPurifier_Token_End($parent->name);
- $new_token->start = $parent;
- if ($carryover) {
- $element = clone $parent;
- $element->armor['MakeWellFormed_TagClosedError'] = true;
- $element->carryover = true;
- $this->processToken(array($new_token, $token, $element));
- } else {
- $this->insertBefore($new_token);
+ // check if this autoclose is doomed to fail
+ // (this rechecks $parent, which his harmless)
+ $autoclose_ok = isset($global_parent_allowed_elements[$token->name]);
+ if (!$autoclose_ok) {
+ foreach ($this->stack as $ancestor) {
+ $elements = $definition->info[$ancestor->name]->child->getAllowedElements($config);
+ if (isset($elements[$token->name])) {
+ $autoclose_ok = true;
+ break;
+ }
+ if ($definition->info[$token->name]->wrap) {
+ $wrapname = $definition->info[$token->name]->wrap;
+ $wrapdef = $definition->info[$wrapname];
+ $wrap_elements = $wrapdef->child->getAllowedElements($config);
+ if (isset($wrap_elements[$token->name]) && isset($elements[$wrapname])) {
+ $autoclose_ok = true;
+ break;
+ }
+ }
+ }
}
- if ($e && !isset($parent->armor['MakeWellFormed_TagClosedError'])) {
- if (!$carryover) {
- $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', $parent);
+ if ($autoclose_ok) {
+ // errors need to be updated
+ $new_token = new HTMLPurifier_Token_End($parent->name);
+ $new_token->start = $parent;
+ // [TagClosedSuppress]
+ if ($e && !isset($parent->armor['MakeWellFormed_TagClosedError'])) {
+ if (!$carryover) {
+ $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag auto closed', $parent);
+ } else {
+ $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag carryover', $parent);
+ }
+ }
+ if ($carryover) {
+ $element = clone $parent;
+ // [TagClosedAuto]
+ $element->armor['MakeWellFormed_TagClosedError'] = true;
+ $element->carryover = true;
+ $token = $this->processToken(array($new_token, $token, $element));
} else {
- $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag carryover', $parent);
+ $token = $this->insertBefore($new_token);
}
+ } else {
+ $token = $this->remove();
}
$reprocess = true;
continue;
@@ -271,20 +366,26 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
if ($ok) {
foreach ($this->injectors as $i => $injector) {
- if (isset($token->skip[$i])) continue;
- if ($token->rewind !== null && $token->rewind !== $i) continue;
- $injector->handleElement($token);
- $this->processToken($token, $i);
+ if (isset($token->skip[$i])) {
+ continue;
+ }
+ if ($token->rewind !== null && $token->rewind !== $i) {
+ continue;
+ }
+ $r = $token;
+ $injector->handleElement($r);
+ $token = $this->processToken($r, $i);
$reprocess = true;
break;
}
if (!$reprocess) {
// ah, nothing interesting happened; do normal processing
- $this->swap($token);
if ($token instanceof HTMLPurifier_Token_Start) {
$this->stack[] = $token;
} elseif ($token instanceof HTMLPurifier_Token_End) {
- throw new HTMLPurifier_Exception('Improper handling of end tag in start code; possible error in MakeWellFormed');
+ throw new HTMLPurifier_Exception(
+ 'Improper handling of end tag in start code; possible error in MakeWellFormed'
+ );
}
}
continue;
@@ -298,13 +399,15 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// make sure that we have something open
if (empty($this->stack)) {
if ($escape_invalid_tags) {
- if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text');
- $this->swap(new HTMLPurifier_Token_Text(
- $generator->generateFromToken($token)
- ));
+ if ($e) {
+ $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag to text');
+ }
+ $token = new HTMLPurifier_Token_Text($generator->generateFromToken($token));
} else {
- $this->remove();
- if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed');
+ if ($e) {
+ $e->send(E_WARNING, 'Strategy_MakeWellFormed: Unnecessary end tag removed');
+ }
+ $token = $this->remove();
}
$reprocess = true;
continue;
@@ -318,10 +421,15 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
if ($current_parent->name == $token->name) {
$token->start = $current_parent;
foreach ($this->injectors as $i => $injector) {
- if (isset($token->skip[$i])) continue;
- if ($token->rewind !== null && $token->rewind !== $i) continue;
- $injector->handleEnd($token);
- $this->processToken($token, $i);
+ if (isset($token->skip[$i])) {
+ continue;
+ }
+ if ($token->rewind !== null && $token->rewind !== $i) {
+ continue;
+ }
+ $r = $token;
+ $injector->handleEnd($r);
+ $token = $this->processToken($r, $i);
$this->stack[] = $current_parent;
$reprocess = true;
break;
@@ -349,13 +457,15 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
// we didn't find the tag, so remove
if ($skipped_tags === false) {
if ($escape_invalid_tags) {
- $this->swap(new HTMLPurifier_Token_Text(
- $generator->generateFromToken($token)
- ));
- if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text');
+ if ($e) {
+ $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag to text');
+ }
+ $token = new HTMLPurifier_Token_Text($generator->generateFromToken($token));
} else {
- $this->remove();
- if ($e) $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed');
+ if ($e) {
+ $e->send(E_WARNING, 'Strategy_MakeWellFormed: Stray end tag removed');
+ }
+ $token = $this->remove();
}
$reprocess = true;
continue;
@@ -366,7 +476,7 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
if ($e) {
for ($j = $c - 1; $j > 0; $j--) {
// notice we exclude $j == 0, i.e. the current ending tag, from
- // the errors...
+ // the errors... [TagClosedSuppress]
if (!isset($skipped_tags[$j]->armor['MakeWellFormed_TagClosedError'])) {
$e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by element end', $skipped_tags[$j]);
}
@@ -381,24 +491,24 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
$new_token->start = $skipped_tags[$j];
array_unshift($replace, $new_token);
if (isset($definition->info[$new_token->name]) && $definition->info[$new_token->name]->formatting) {
+ // [TagClosedAuto]
$element = clone $skipped_tags[$j];
$element->carryover = true;
$element->armor['MakeWellFormed_TagClosedError'] = true;
$replace[] = $element;
}
}
- $this->processToken($replace);
+ $token = $this->processToken($replace);
$reprocess = true;
continue;
}
- $context->destroy('CurrentNesting');
- $context->destroy('InputTokens');
- $context->destroy('InputIndex');
$context->destroy('CurrentToken');
+ $context->destroy('CurrentNesting');
+ $context->destroy('InputZipper');
- unset($this->injectors, $this->stack, $this->tokens, $this->t);
- return $tokens;
+ unset($this->injectors, $this->stack, $this->tokens);
+ return $zipper->toArray($token);
}
/**
@@ -417,25 +527,38 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
* If $token is an integer, that number of tokens (with the first token
* being the current one) will be deleted.
*
- * @param $token Token substitution value
- * @param $injector Injector that performed the substitution; default is if
+ * @param HTMLPurifier_Token|array|int|bool $token Token substitution value
+ * @param HTMLPurifier_Injector|int $injector Injector that performed the substitution; default is if
* this is not an injector related operation.
+ * @throws HTMLPurifier_Exception
*/
- protected function processToken($token, $injector = -1) {
-
+ protected function processToken($token, $injector = -1)
+ {
// normalize forms of token
- if (is_object($token)) $token = array(1, $token);
- if (is_int($token)) $token = array($token);
- if ($token === false) $token = array(1);
- if (!is_array($token)) throw new HTMLPurifier_Exception('Invalid token type from injector');
- if (!is_int($token[0])) array_unshift($token, 1);
- if ($token[0] === 0) throw new HTMLPurifier_Exception('Deleting zero tokens is not valid');
+ if (is_object($token)) {
+ $token = array(1, $token);
+ }
+ if (is_int($token)) {
+ $token = array($token);
+ }
+ if ($token === false) {
+ $token = array(1);
+ }
+ if (!is_array($token)) {
+ throw new HTMLPurifier_Exception('Invalid token type from injector');
+ }
+ if (!is_int($token[0])) {
+ array_unshift($token, 1);
+ }
+ if ($token[0] === 0) {
+ throw new HTMLPurifier_Exception('Deleting zero tokens is not valid');
+ }
// $token is now an array with the following form:
// array(number nodes to delete, new node 1, new node 2, ...)
$delete = array_shift($token);
- $old = array_splice($this->tokens, $this->t, $delete, $token);
+ list($old, $r) = $this->zipper->splice($this->token, $delete, $token);
if ($injector > -1) {
// determine appropriate skips
@@ -446,30 +569,32 @@ class HTMLPurifier_Strategy_MakeWellFormed extends HTMLPurifier_Strategy
}
}
- }
+ return $r;
- /**
- * Inserts a token before the current token. Cursor now points to this token
- */
- private function insertBefore($token) {
- array_splice($this->tokens, $this->t, 0, array($token));
}
/**
- * Removes current token. Cursor now points to new token occupying previously
- * occupied space.
+ * Inserts a token before the current token. Cursor now points to
+ * this token. You must reprocess after this.
+ * @param HTMLPurifier_Token $token
*/
- private function remove() {
- array_splice($this->tokens, $this->t, 1);
+ private function insertBefore($token)
+ {
+ // NB not $this->zipper->insertBefore(), due to positioning
+ // differences
+ $splice = $this->zipper->splice($this->token, 0, array($token));
+
+ return $splice[1];
}
/**
- * Swap current token with new token. Cursor points to new token (no change).
+ * Removes current token. Cursor now points to new token occupying previously
+ * occupied space. You must reprocess after this.
*/
- private function swap($token) {
- $this->tokens[$this->t] = $token;
+ private function remove()
+ {
+ return $this->zipper->delete();
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Strategy/RemoveForeignElements.php b/library/HTMLPurifier/Strategy/RemoveForeignElements.php
index cf3a33e40..1a8149ecc 100644
--- a/library/HTMLPurifier/Strategy/RemoveForeignElements.php
+++ b/library/HTMLPurifier/Strategy/RemoveForeignElements.php
@@ -11,19 +11,29 @@
class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
{
- public function execute($tokens, $config, $context) {
+ /**
+ * @param HTMLPurifier_Token[] $tokens
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return array|HTMLPurifier_Token[]
+ */
+ public function execute($tokens, $config, $context)
+ {
$definition = $config->getHTMLDefinition();
$generator = new HTMLPurifier_Generator($config, $context);
$result = array();
$escape_invalid_tags = $config->get('Core.EscapeInvalidTags');
- $remove_invalid_img = $config->get('Core.RemoveInvalidImg');
+ $remove_invalid_img = $config->get('Core.RemoveInvalidImg');
// currently only used to determine if comments should be kept
$trusted = $config->get('HTML.Trusted');
+ $comment_lookup = $config->get('HTML.AllowedComments');
+ $comment_regexp = $config->get('HTML.AllowedCommentsRegexp');
+ $check_comments = $comment_lookup !== array() || $comment_regexp !== null;
$remove_script_contents = $config->get('Core.RemoveScriptContents');
- $hidden_elements = $config->get('Core.HiddenElements');
+ $hidden_elements = $config->get('Core.HiddenElements');
// remove script contents compatibility
if ($remove_script_contents === true) {
@@ -48,34 +58,31 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
$e =& $context->get('ErrorCollector');
}
- foreach($tokens as $token) {
+ foreach ($tokens as $token) {
if ($remove_until) {
if (empty($token->is_tag) || $token->name !== $remove_until) {
continue;
}
}
- if (!empty( $token->is_tag )) {
+ if (!empty($token->is_tag)) {
// DEFINITION CALL
// before any processing, try to transform the element
- if (
- isset($definition->info_tag_transform[$token->name])
- ) {
+ if (isset($definition->info_tag_transform[$token->name])) {
$original_name = $token->name;
// there is a transformation for this tag
// DEFINITION CALL
$token = $definition->
- info_tag_transform[$token->name]->
- transform($token, $config, $context);
- if ($e) $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Tag transform', $original_name);
+ info_tag_transform[$token->name]->transform($token, $config, $context);
+ if ($e) {
+ $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Tag transform', $original_name);
+ }
}
if (isset($definition->info[$token->name])) {
-
// mostly everything's good, but
// we need to make sure required attributes are in order
- if (
- ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) &&
+ if (($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) &&
$definition->info[$token->name]->required_attr &&
($token->name != 'img' || $remove_invalid_img) // ensure config option still works
) {
@@ -88,7 +95,13 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
}
}
if (!$ok) {
- if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Missing required attribute', $name);
+ if ($e) {
+ $e->send(
+ E_ERROR,
+ 'Strategy_RemoveForeignElements: Missing required attribute',
+ $name
+ );
+ }
continue;
}
$token->armor['ValidateAttributes'] = true;
@@ -102,7 +115,9 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
} elseif ($escape_invalid_tags) {
// invalid tag, generate HTML representation and insert in
- if ($e) $e->send(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text');
+ if ($e) {
+ $e->send(E_WARNING, 'Strategy_RemoveForeignElements: Foreign element to text');
+ }
$token = new HTMLPurifier_Token_Text(
$generator->generateFromToken($token)
);
@@ -117,9 +132,13 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
} else {
$remove_until = false;
}
- if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed');
+ if ($e) {
+ $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign meta element removed');
+ }
} else {
- if ($e) $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign element removed');
+ if ($e) {
+ $e->send(E_ERROR, 'Strategy_RemoveForeignElements: Foreign element removed');
+ }
}
continue;
}
@@ -128,26 +147,46 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
if ($textify_comments !== false) {
$data = $token->data;
$token = new HTMLPurifier_Token_Text($data);
- } elseif ($trusted) {
- // keep, but perform comment cleaning
+ } elseif ($trusted || $check_comments) {
+ // always cleanup comments
+ $trailing_hyphen = false;
if ($e) {
// perform check whether or not there's a trailing hyphen
if (substr($token->data, -1) == '-') {
- $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed');
+ $trailing_hyphen = true;
}
}
$token->data = rtrim($token->data, '-');
$found_double_hyphen = false;
while (strpos($token->data, '--') !== false) {
- if ($e && !$found_double_hyphen) {
- $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Hyphens in comment collapsed');
- }
- $found_double_hyphen = true; // prevent double-erroring
+ $found_double_hyphen = true;
$token->data = str_replace('--', '-', $token->data);
}
+ if ($trusted || !empty($comment_lookup[trim($token->data)]) ||
+ ($comment_regexp !== null && preg_match($comment_regexp, trim($token->data)))) {
+ // OK good
+ if ($e) {
+ if ($trailing_hyphen) {
+ $e->send(
+ E_NOTICE,
+ 'Strategy_RemoveForeignElements: Trailing hyphen in comment removed'
+ );
+ }
+ if ($found_double_hyphen) {
+ $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Hyphens in comment collapsed');
+ }
+ }
+ } else {
+ if ($e) {
+ $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed');
+ }
+ continue;
+ }
} else {
// strip comments
- if ($e) $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed');
+ if ($e) {
+ $e->send(E_NOTICE, 'Strategy_RemoveForeignElements: Comment removed');
+ }
continue;
}
} elseif ($token instanceof HTMLPurifier_Token_Text) {
@@ -160,12 +199,9 @@ class HTMLPurifier_Strategy_RemoveForeignElements extends HTMLPurifier_Strategy
// we removed tokens until the end, throw error
$e->send(E_ERROR, 'Strategy_RemoveForeignElements: Token removed to end', $remove_until);
}
-
$context->destroy('CurrentToken');
-
return $result;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Strategy/ValidateAttributes.php b/library/HTMLPurifier/Strategy/ValidateAttributes.php
index c3328a9d4..fbb3d27c8 100644
--- a/library/HTMLPurifier/Strategy/ValidateAttributes.php
+++ b/library/HTMLPurifier/Strategy/ValidateAttributes.php
@@ -7,8 +7,14 @@
class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy
{
- public function execute($tokens, $config, $context) {
-
+ /**
+ * @param HTMLPurifier_Token[] $tokens
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_Token[]
+ */
+ public function execute($tokens, $config, $context)
+ {
// setup validator
$validator = new HTMLPurifier_AttrValidator();
@@ -19,21 +25,21 @@ class HTMLPurifier_Strategy_ValidateAttributes extends HTMLPurifier_Strategy
// only process tokens that have attributes,
// namely start and empty tags
- if (!$token instanceof HTMLPurifier_Token_Start && !$token instanceof HTMLPurifier_Token_Empty) continue;
+ if (!$token instanceof HTMLPurifier_Token_Start && !$token instanceof HTMLPurifier_Token_Empty) {
+ continue;
+ }
// skip tokens that are armored
- if (!empty($token->armor['ValidateAttributes'])) continue;
+ if (!empty($token->armor['ValidateAttributes'])) {
+ continue;
+ }
// note that we have no facilities here for removing tokens
$validator->validateToken($token, $config, $context);
-
- $tokens[$key] = $token; // for PHP 4
}
$context->destroy('CurrentToken');
-
return $tokens;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/StringHash.php b/library/HTMLPurifier/StringHash.php
index 62085c5c2..c07370197 100644
--- a/library/HTMLPurifier/StringHash.php
+++ b/library/HTMLPurifier/StringHash.php
@@ -10,28 +10,36 @@
*/
class HTMLPurifier_StringHash extends ArrayObject
{
+ /**
+ * @type array
+ */
protected $accessed = array();
/**
* Retrieves a value, and logs the access.
+ * @param mixed $index
+ * @return mixed
*/
- public function offsetGet($index) {
+ public function offsetGet($index)
+ {
$this->accessed[$index] = true;
return parent::offsetGet($index);
}
/**
* Returns a lookup array of all array indexes that have been accessed.
- * @return Array in form array($index => true).
+ * @return array in form array($index => true).
*/
- public function getAccessed() {
+ public function getAccessed()
+ {
return $this->accessed;
}
/**
* Resets the access array.
*/
- public function resetAccessed() {
+ public function resetAccessed()
+ {
$this->accessed = array();
}
}
diff --git a/library/HTMLPurifier/StringHashParser.php b/library/HTMLPurifier/StringHashParser.php
index f3e70c712..7c73f8083 100644
--- a/library/HTMLPurifier/StringHashParser.php
+++ b/library/HTMLPurifier/StringHashParser.php
@@ -28,15 +28,25 @@
class HTMLPurifier_StringHashParser
{
+ /**
+ * @type string
+ */
public $default = 'ID';
/**
* Parses a file that contains a single string-hash.
+ * @param string $file
+ * @return array
*/
- public function parseFile($file) {
- if (!file_exists($file)) return false;
+ public function parseFile($file)
+ {
+ if (!file_exists($file)) {
+ return false;
+ }
$fh = fopen($file, 'r');
- if (!$fh) return false;
+ if (!$fh) {
+ return false;
+ }
$ret = $this->parseHandle($fh);
fclose($fh);
return $ret;
@@ -44,12 +54,19 @@ class HTMLPurifier_StringHashParser
/**
* Parses a file that contains multiple string-hashes delimited by '----'
+ * @param string $file
+ * @return array
*/
- public function parseMultiFile($file) {
- if (!file_exists($file)) return false;
+ public function parseMultiFile($file)
+ {
+ if (!file_exists($file)) {
+ return false;
+ }
$ret = array();
$fh = fopen($file, 'r');
- if (!$fh) return false;
+ if (!$fh) {
+ return false;
+ }
while (!feof($fh)) {
$ret[] = $this->parseHandle($fh);
}
@@ -62,26 +79,36 @@ class HTMLPurifier_StringHashParser
* @note While it's possible to simulate in-memory parsing by using
* custom stream wrappers, if such a use-case arises we should
* factor out the file handle into its own class.
- * @param $fh File handle with pointer at start of valid string-hash
+ * @param resource $fh File handle with pointer at start of valid string-hash
* block.
+ * @return array
*/
- protected function parseHandle($fh) {
+ protected function parseHandle($fh)
+ {
$state = false;
$single = false;
$ret = array();
do {
$line = fgets($fh);
- if ($line === false) break;
+ if ($line === false) {
+ break;
+ }
$line = rtrim($line, "\n\r");
- if (!$state && $line === '') continue;
- if ($line === '----') break;
+ if (!$state && $line === '') {
+ continue;
+ }
+ if ($line === '----') {
+ break;
+ }
if (strncmp('--#', $line, 3) === 0) {
// Comment
continue;
} elseif (strncmp('--', $line, 2) === 0) {
// Multiline declaration
$state = trim($line, '- ');
- if (!isset($ret[$state])) $ret[$state] = '';
+ if (!isset($ret[$state])) {
+ $ret[$state] = '';
+ }
continue;
} elseif (!$state) {
$single = true;
@@ -104,7 +131,6 @@ class HTMLPurifier_StringHashParser
} while (!feof($fh));
return $ret;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/TagTransform.php b/library/HTMLPurifier/TagTransform.php
index 210a44721..7b8d83343 100644
--- a/library/HTMLPurifier/TagTransform.php
+++ b/library/HTMLPurifier/TagTransform.php
@@ -8,14 +8,15 @@ abstract class HTMLPurifier_TagTransform
/**
* Tag name to transform the tag to.
+ * @type string
*/
public $transform_to;
/**
* Transforms the obsolete tag into the valid tag.
- * @param $tag Tag to be transformed.
- * @param $config Mandatory HTMLPurifier_Config object
- * @param $context Mandatory HTMLPurifier_Context object
+ * @param HTMLPurifier_Token_Tag $tag Tag to be transformed.
+ * @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object
+ * @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object
*/
abstract public function transform($tag, $config, $context);
@@ -23,14 +24,14 @@ abstract class HTMLPurifier_TagTransform
* Prepends CSS properties to the style attribute, creating the
* attribute if it doesn't exist.
* @warning Copied over from AttrTransform, be sure to keep in sync
- * @param $attr Attribute array to process (passed by reference)
- * @param $css CSS to prepend
+ * @param array $attr Attribute array to process (passed by reference)
+ * @param string $css CSS to prepend
*/
- protected function prependCSS(&$attr, $css) {
+ protected function prependCSS(&$attr, $css)
+ {
$attr['style'] = isset($attr['style']) ? $attr['style'] : '';
$attr['style'] = $css . $attr['style'];
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/TagTransform/Font.php b/library/HTMLPurifier/TagTransform/Font.php
index ed2463786..7853d90bc 100644
--- a/library/HTMLPurifier/TagTransform/Font.php
+++ b/library/HTMLPurifier/TagTransform/Font.php
@@ -17,9 +17,14 @@
*/
class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
{
-
+ /**
+ * @type string
+ */
public $transform_to = 'span';
+ /**
+ * @type array
+ */
protected $_size_lookup = array(
'0' => 'xx-small',
'1' => 'xx-small',
@@ -37,8 +42,14 @@ class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
'+4' => '300%'
);
- public function transform($tag, $config, $context) {
-
+ /**
+ * @param HTMLPurifier_Token_Tag $tag
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_Token_End|string
+ */
+ public function transform($tag, $config, $context)
+ {
if ($tag instanceof HTMLPurifier_Token_End) {
$new_tag = clone $tag;
$new_tag->name = $this->transform_to;
@@ -63,17 +74,25 @@ class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
// handle size transform
if (isset($attr['size'])) {
// normalize large numbers
- if ($attr['size']{0} == '+' || $attr['size']{0} == '-') {
- $size = (int) $attr['size'];
- if ($size < -2) $attr['size'] = '-2';
- if ($size > 4) $attr['size'] = '+4';
- } else {
- $size = (int) $attr['size'];
- if ($size > 7) $attr['size'] = '7';
+ if ($attr['size'] !== '') {
+ if ($attr['size']{0} == '+' || $attr['size']{0} == '-') {
+ $size = (int)$attr['size'];
+ if ($size < -2) {
+ $attr['size'] = '-2';
+ }
+ if ($size > 4) {
+ $attr['size'] = '+4';
+ }
+ } else {
+ $size = (int)$attr['size'];
+ if ($size > 7) {
+ $attr['size'] = '7';
+ }
+ }
}
if (isset($this->_size_lookup[$attr['size']])) {
$prepend_style .= 'font-size:' .
- $this->_size_lookup[$attr['size']] . ';';
+ $this->_size_lookup[$attr['size']] . ';';
}
unset($attr['size']);
}
@@ -89,7 +108,6 @@ class HTMLPurifier_TagTransform_Font extends HTMLPurifier_TagTransform
$new_tag->attr = $attr;
return $new_tag;
-
}
}
diff --git a/library/HTMLPurifier/TagTransform/Simple.php b/library/HTMLPurifier/TagTransform/Simple.php
index 0e36130f2..71bf10b91 100644
--- a/library/HTMLPurifier/TagTransform/Simple.php
+++ b/library/HTMLPurifier/TagTransform/Simple.php
@@ -7,19 +7,29 @@
*/
class HTMLPurifier_TagTransform_Simple extends HTMLPurifier_TagTransform
{
-
+ /**
+ * @type string
+ */
protected $style;
/**
- * @param $transform_to Tag name to transform to.
- * @param $style CSS style to add to the tag
+ * @param string $transform_to Tag name to transform to.
+ * @param string $style CSS style to add to the tag
*/
- public function __construct($transform_to, $style = null) {
+ public function __construct($transform_to, $style = null)
+ {
$this->transform_to = $transform_to;
$this->style = $style;
}
- public function transform($tag, $config, $context) {
+ /**
+ * @param HTMLPurifier_Token_Tag $tag
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return string
+ */
+ public function transform($tag, $config, $context)
+ {
$new_tag = clone $tag;
$new_tag->name = $this->transform_to;
if (!is_null($this->style) &&
@@ -29,7 +39,6 @@ class HTMLPurifier_TagTransform_Simple extends HTMLPurifier_TagTransform
}
return $new_tag;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Token.php b/library/HTMLPurifier/Token.php
index 7900e6cb1..85b85e072 100644
--- a/library/HTMLPurifier/Token.php
+++ b/library/HTMLPurifier/Token.php
@@ -3,55 +3,98 @@
/**
* Abstract base token class that all others inherit from.
*/
-class HTMLPurifier_Token {
- public $line; /**< Line number node was on in source document. Null if unknown. */
- public $col; /**< Column of line node was on in source document. Null if unknown. */
+abstract class HTMLPurifier_Token
+{
+ /**
+ * Line number node was on in source document. Null if unknown.
+ * @type int
+ */
+ public $line;
+
+ /**
+ * Column of line node was on in source document. Null if unknown.
+ * @type int
+ */
+ public $col;
/**
* Lookup array of processing that this token is exempt from.
* Currently, valid values are "ValidateAttributes" and
* "MakeWellFormed_TagClosedError"
+ * @type array
*/
public $armor = array();
/**
* Used during MakeWellFormed.
+ * @type
*/
public $skip;
+
+ /**
+ * @type
+ */
public $rewind;
+
+ /**
+ * @type
+ */
public $carryover;
- public function __get($n) {
- if ($n === 'type') {
- trigger_error('Deprecated type property called; use instanceof', E_USER_NOTICE);
- switch (get_class($this)) {
- case 'HTMLPurifier_Token_Start': return 'start';
- case 'HTMLPurifier_Token_Empty': return 'empty';
- case 'HTMLPurifier_Token_End': return 'end';
- case 'HTMLPurifier_Token_Text': return 'text';
- case 'HTMLPurifier_Token_Comment': return 'comment';
- default: return null;
+ /**
+ * @param string $n
+ * @return null|string
+ */
+ public function __get($n)
+ {
+ if ($n === 'type') {
+ trigger_error('Deprecated type property called; use instanceof', E_USER_NOTICE);
+ switch (get_class($this)) {
+ case 'HTMLPurifier_Token_Start':
+ return 'start';
+ case 'HTMLPurifier_Token_Empty':
+ return 'empty';
+ case 'HTMLPurifier_Token_End':
+ return 'end';
+ case 'HTMLPurifier_Token_Text':
+ return 'text';
+ case 'HTMLPurifier_Token_Comment':
+ return 'comment';
+ default:
+ return null;
+ }
}
- }
}
/**
* Sets the position of the token in the source document.
+ * @param int $l
+ * @param int $c
*/
- public function position($l = null, $c = null) {
+ public function position($l = null, $c = null)
+ {
$this->line = $l;
- $this->col = $c;
+ $this->col = $c;
}
/**
* Convenience function for DirectLex settings line/col position.
+ * @param int $l
+ * @param int $c
*/
- public function rawPosition($l, $c) {
- if ($c === -1) $l++;
+ public function rawPosition($l, $c)
+ {
+ if ($c === -1) {
+ $l++;
+ }
$this->line = $l;
- $this->col = $c;
+ $this->col = $c;
}
+ /**
+ * Converts a token into its corresponding node.
+ */
+ abstract public function toNode();
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Token/Comment.php b/library/HTMLPurifier/Token/Comment.php
index dc6bdcabb..23453c705 100644
--- a/library/HTMLPurifier/Token/Comment.php
+++ b/library/HTMLPurifier/Token/Comment.php
@@ -5,17 +5,33 @@
*/
class HTMLPurifier_Token_Comment extends HTMLPurifier_Token
{
- public $data; /**< Character data within comment. */
+ /**
+ * Character data within comment.
+ * @type string
+ */
+ public $data;
+
+ /**
+ * @type bool
+ */
public $is_whitespace = true;
+
/**
* Transparent constructor.
*
- * @param $data String comment data.
+ * @param string $data String comment data.
+ * @param int $line
+ * @param int $col
*/
- public function __construct($data, $line = null, $col = null) {
+ public function __construct($data, $line = null, $col = null)
+ {
$this->data = $data;
$this->line = $line;
- $this->col = $col;
+ $this->col = $col;
+ }
+
+ public function toNode() {
+ return new HTMLPurifier_Node_Comment($this->data, $this->line, $this->col);
}
}
diff --git a/library/HTMLPurifier/Token/Empty.php b/library/HTMLPurifier/Token/Empty.php
index 2a82b47ad..78a95f555 100644
--- a/library/HTMLPurifier/Token/Empty.php
+++ b/library/HTMLPurifier/Token/Empty.php
@@ -5,7 +5,11 @@
*/
class HTMLPurifier_Token_Empty extends HTMLPurifier_Token_Tag
{
-
+ public function toNode() {
+ $n = parent::toNode();
+ $n->empty = true;
+ return $n;
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Token/End.php b/library/HTMLPurifier/Token/End.php
index 353e79daf..59b38fdc5 100644
--- a/library/HTMLPurifier/Token/End.php
+++ b/library/HTMLPurifier/Token/End.php
@@ -10,10 +10,15 @@
class HTMLPurifier_Token_End extends HTMLPurifier_Token_Tag
{
/**
- * Token that started this node. Added by MakeWellFormed. Please
- * do not edit this!
+ * Token that started this node.
+ * Added by MakeWellFormed. Please do not edit this!
+ * @type HTMLPurifier_Token
*/
public $start;
+
+ public function toNode() {
+ throw new Exception("HTMLPurifier_Token_End->toNode not supported!");
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Token/Start.php b/library/HTMLPurifier/Token/Start.php
index e0e14fc62..019f317ad 100644
--- a/library/HTMLPurifier/Token/Start.php
+++ b/library/HTMLPurifier/Token/Start.php
@@ -5,7 +5,6 @@
*/
class HTMLPurifier_Token_Start extends HTMLPurifier_Token_Tag
{
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Token/Tag.php b/library/HTMLPurifier/Token/Tag.php
index 798be028e..d643fa64e 100644
--- a/library/HTMLPurifier/Token/Tag.php
+++ b/library/HTMLPurifier/Token/Tag.php
@@ -3,13 +3,14 @@
/**
* Abstract class of a tag token (start, end or empty), and its behavior.
*/
-class HTMLPurifier_Token_Tag extends HTMLPurifier_Token
+abstract class HTMLPurifier_Token_Tag extends HTMLPurifier_Token
{
/**
* Static bool marker that indicates the class is a tag.
*
* This allows us to check objects with <tt>!empty($obj->is_tag)</tt>
* without having to use a function call <tt>is_a()</tt>.
+ * @type bool
*/
public $is_tag = true;
@@ -19,21 +20,27 @@ class HTMLPurifier_Token_Tag extends HTMLPurifier_Token
* @note Strictly speaking, XML tags are case sensitive, so we shouldn't
* be lower-casing them, but these tokens cater to HTML tags, which are
* insensitive.
+ * @type string
*/
public $name;
/**
* Associative array of the tag's attributes.
+ * @type array
*/
public $attr = array();
/**
* Non-overloaded constructor, which lower-cases passed tag name.
*
- * @param $name String name.
- * @param $attr Associative array of attributes.
+ * @param string $name String name.
+ * @param array $attr Associative array of attributes.
+ * @param int $line
+ * @param int $col
+ * @param array $armor
*/
- public function __construct($name, $attr = array(), $line = null, $col = null) {
+ public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array())
+ {
$this->name = ctype_lower($name) ? $name : strtolower($name);
foreach ($attr as $key => $value) {
// normalization only necessary when key is not lowercase
@@ -49,7 +56,12 @@ class HTMLPurifier_Token_Tag extends HTMLPurifier_Token
}
$this->attr = $attr;
$this->line = $line;
- $this->col = $col;
+ $this->col = $col;
+ $this->armor = $armor;
+ }
+
+ public function toNode() {
+ return new HTMLPurifier_Node_Element($this->name, $this->attr, $this->line, $this->col, $this->armor);
}
}
diff --git a/library/HTMLPurifier/Token/Text.php b/library/HTMLPurifier/Token/Text.php
index 82efd823d..f26a1c211 100644
--- a/library/HTMLPurifier/Token/Text.php
+++ b/library/HTMLPurifier/Token/Text.php
@@ -12,22 +12,42 @@
class HTMLPurifier_Token_Text extends HTMLPurifier_Token
{
- public $name = '#PCDATA'; /**< PCDATA tag name compatible with DTD. */
- public $data; /**< Parsed character data of text. */
- public $is_whitespace; /**< Bool indicating if node is whitespace. */
+ /**
+ * @type string
+ */
+ public $name = '#PCDATA';
+ /**< PCDATA tag name compatible with DTD. */
+
+ /**
+ * @type string
+ */
+ public $data;
+ /**< Parsed character data of text. */
+
+ /**
+ * @type bool
+ */
+ public $is_whitespace;
+
+ /**< Bool indicating if node is whitespace. */
/**
* Constructor, accepts data and determines if it is whitespace.
- *
- * @param $data String parsed character data.
+ * @param string $data String parsed character data.
+ * @param int $line
+ * @param int $col
*/
- public function __construct($data, $line = null, $col = null) {
+ public function __construct($data, $line = null, $col = null)
+ {
$this->data = $data;
$this->is_whitespace = ctype_space($data);
$this->line = $line;
- $this->col = $col;
+ $this->col = $col;
}
+ public function toNode() {
+ return new HTMLPurifier_Node_Text($this->data, $this->is_whitespace, $this->line, $this->col);
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/TokenFactory.php b/library/HTMLPurifier/TokenFactory.php
index 7cf48fb41..dea2446b9 100644
--- a/library/HTMLPurifier/TokenFactory.php
+++ b/library/HTMLPurifier/TokenFactory.php
@@ -13,32 +13,53 @@
*/
class HTMLPurifier_TokenFactory
{
+ // p stands for prototype
/**
- * Prototypes that will be cloned.
- * @private
+ * @type HTMLPurifier_Token_Start
*/
- // p stands for prototype
- private $p_start, $p_end, $p_empty, $p_text, $p_comment;
+ private $p_start;
+
+ /**
+ * @type HTMLPurifier_Token_End
+ */
+ private $p_end;
+
+ /**
+ * @type HTMLPurifier_Token_Empty
+ */
+ private $p_empty;
+
+ /**
+ * @type HTMLPurifier_Token_Text
+ */
+ private $p_text;
+
+ /**
+ * @type HTMLPurifier_Token_Comment
+ */
+ private $p_comment;
/**
* Generates blank prototypes for cloning.
*/
- public function __construct() {
- $this->p_start = new HTMLPurifier_Token_Start('', array());
- $this->p_end = new HTMLPurifier_Token_End('');
- $this->p_empty = new HTMLPurifier_Token_Empty('', array());
- $this->p_text = new HTMLPurifier_Token_Text('');
- $this->p_comment= new HTMLPurifier_Token_Comment('');
+ public function __construct()
+ {
+ $this->p_start = new HTMLPurifier_Token_Start('', array());
+ $this->p_end = new HTMLPurifier_Token_End('');
+ $this->p_empty = new HTMLPurifier_Token_Empty('', array());
+ $this->p_text = new HTMLPurifier_Token_Text('');
+ $this->p_comment = new HTMLPurifier_Token_Comment('');
}
/**
* Creates a HTMLPurifier_Token_Start.
- * @param $name Tag name
- * @param $attr Associative array of attributes
- * @return Generated HTMLPurifier_Token_Start
+ * @param string $name Tag name
+ * @param array $attr Associative array of attributes
+ * @return HTMLPurifier_Token_Start Generated HTMLPurifier_Token_Start
*/
- public function createStart($name, $attr = array()) {
+ public function createStart($name, $attr = array())
+ {
$p = clone $this->p_start;
$p->__construct($name, $attr);
return $p;
@@ -46,10 +67,11 @@ class HTMLPurifier_TokenFactory
/**
* Creates a HTMLPurifier_Token_End.
- * @param $name Tag name
- * @return Generated HTMLPurifier_Token_End
+ * @param string $name Tag name
+ * @return HTMLPurifier_Token_End Generated HTMLPurifier_Token_End
*/
- public function createEnd($name) {
+ public function createEnd($name)
+ {
$p = clone $this->p_end;
$p->__construct($name);
return $p;
@@ -57,11 +79,12 @@ class HTMLPurifier_TokenFactory
/**
* Creates a HTMLPurifier_Token_Empty.
- * @param $name Tag name
- * @param $attr Associative array of attributes
- * @return Generated HTMLPurifier_Token_Empty
+ * @param string $name Tag name
+ * @param array $attr Associative array of attributes
+ * @return HTMLPurifier_Token_Empty Generated HTMLPurifier_Token_Empty
*/
- public function createEmpty($name, $attr = array()) {
+ public function createEmpty($name, $attr = array())
+ {
$p = clone $this->p_empty;
$p->__construct($name, $attr);
return $p;
@@ -69,10 +92,11 @@ class HTMLPurifier_TokenFactory
/**
* Creates a HTMLPurifier_Token_Text.
- * @param $data Data of text token
- * @return Generated HTMLPurifier_Token_Text
+ * @param string $data Data of text token
+ * @return HTMLPurifier_Token_Text Generated HTMLPurifier_Token_Text
*/
- public function createText($data) {
+ public function createText($data)
+ {
$p = clone $this->p_text;
$p->__construct($data);
return $p;
@@ -80,15 +104,15 @@ class HTMLPurifier_TokenFactory
/**
* Creates a HTMLPurifier_Token_Comment.
- * @param $data Data of comment token
- * @return Generated HTMLPurifier_Token_Comment
+ * @param string $data Data of comment token
+ * @return HTMLPurifier_Token_Comment Generated HTMLPurifier_Token_Comment
*/
- public function createComment($data) {
+ public function createComment($data)
+ {
$p = clone $this->p_comment;
$p->__construct($data);
return $p;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URI.php b/library/HTMLPurifier/URI.php
index 8b50d0d18..a5e7ae298 100644
--- a/library/HTMLPurifier/URI.php
+++ b/library/HTMLPurifier/URI.php
@@ -10,17 +10,57 @@
*/
class HTMLPurifier_URI
{
+ /**
+ * @type string
+ */
+ public $scheme;
- public $scheme, $userinfo, $host, $port, $path, $query, $fragment;
+ /**
+ * @type string
+ */
+ public $userinfo;
/**
+ * @type string
+ */
+ public $host;
+
+ /**
+ * @type int
+ */
+ public $port;
+
+ /**
+ * @type string
+ */
+ public $path;
+
+ /**
+ * @type string
+ */
+ public $query;
+
+ /**
+ * @type string
+ */
+ public $fragment;
+
+ /**
+ * @param string $scheme
+ * @param string $userinfo
+ * @param string $host
+ * @param int $port
+ * @param string $path
+ * @param string $query
+ * @param string $fragment
* @note Automatically normalizes scheme and port
*/
- public function __construct($scheme, $userinfo, $host, $port, $path, $query, $fragment) {
+ public function __construct($scheme, $userinfo, $host, $port, $path, $query, $fragment)
+ {
$this->scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme);
$this->userinfo = $userinfo;
$this->host = $host;
- $this->port = is_null($port) ? $port : (int) $port;
+ $this->port = is_null($port) ? $port : (int)$port;
$this->path = $path;
$this->query = $query;
$this->fragment = $fragment;
@@ -28,19 +68,22 @@ class HTMLPurifier_URI
/**
* Retrieves a scheme object corresponding to the URI's scheme/default
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
- * @return Scheme object appropriate for validating this URI
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_URIScheme Scheme object appropriate for validating this URI
*/
- public function getSchemeObj($config, $context) {
+ public function getSchemeObj($config, $context)
+ {
$registry = HTMLPurifier_URISchemeRegistry::instance();
if ($this->scheme !== null) {
$scheme_obj = $registry->getScheme($this->scheme, $config, $context);
- if (!$scheme_obj) return false; // invalid scheme, clean it out
+ if (!$scheme_obj) {
+ return false;
+ } // invalid scheme, clean it out
} else {
// no scheme: retrieve the default one
$def = $config->getDefinition('URI');
- $scheme_obj = $registry->getScheme($def->defaultScheme, $config, $context);
+ $scheme_obj = $def->getDefaultScheme($config, $context);
if (!$scheme_obj) {
// something funky happened to the default scheme object
trigger_error(
@@ -56,30 +99,39 @@ class HTMLPurifier_URI
/**
* Generic validation method applicable for all schemes. May modify
* this URI in order to get it into a compliant form.
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
- * @return True if validation/filtering succeeds, false if failure
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool True if validation/filtering succeeds, false if failure
*/
- public function validate($config, $context) {
-
+ public function validate($config, $context)
+ {
// ABNF definitions from RFC 3986
$chars_sub_delims = '!$&\'()*+,;=';
$chars_gen_delims = ':/?#[]@';
$chars_pchar = $chars_sub_delims . ':@';
- // validate scheme (MUST BE FIRST!)
- if (!is_null($this->scheme) && is_null($this->host)) {
- $def = $config->getDefinition('URI');
- if ($def->defaultScheme === $this->scheme) {
- $this->scheme = null;
- }
- }
-
// validate host
if (!is_null($this->host)) {
$host_def = new HTMLPurifier_AttrDef_URI_Host();
$this->host = $host_def->validate($this->host, $config, $context);
- if ($this->host === false) $this->host = null;
+ if ($this->host === false) {
+ $this->host = null;
+ }
+ }
+
+ // validate scheme
+ // NOTE: It's not appropriate to check whether or not this
+ // scheme is in our registry, since a URIFilter may convert a
+ // URI that we don't allow into one we do. So instead, we just
+ // check if the scheme can be dropped because there is no host
+ // and it is our default scheme.
+ if (!is_null($this->scheme) && is_null($this->host) || $this->host === '') {
+ // support for relative paths is pretty abysmal when the
+ // scheme is present, so axe it when possible
+ $def = $config->getDefinition('URI');
+ if ($def->defaultScheme === $this->scheme) {
+ $this->scheme = null;
+ }
}
// validate username
@@ -90,38 +142,55 @@ class HTMLPurifier_URI
// validate port
if (!is_null($this->port)) {
- if ($this->port < 1 || $this->port > 65535) $this->port = null;
+ if ($this->port < 1 || $this->port > 65535) {
+ $this->port = null;
+ }
}
// validate path
- $path_parts = array();
$segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/');
- if (!is_null($this->host)) {
+ if (!is_null($this->host)) { // this catches $this->host === ''
// path-abempty (hier and relative)
+ // http://www.example.com/my/path
+ // //www.example.com/my/path (looks odd, but works, and
+ // recognized by most browsers)
+ // (this set is valid or invalid on a scheme by scheme
+ // basis, so we'll deal with it later)
+ // file:///my/path
+ // ///my/path
$this->path = $segments_encoder->encode($this->path);
- } elseif ($this->path !== '' && $this->path[0] === '/') {
- // path-absolute (hier and relative)
- if (strlen($this->path) >= 2 && $this->path[1] === '/') {
- // This shouldn't ever happen!
- $this->path = '';
- } else {
+ } elseif ($this->path !== '') {
+ if ($this->path[0] === '/') {
+ // path-absolute (hier and relative)
+ // http:/my/path
+ // /my/path
+ if (strlen($this->path) >= 2 && $this->path[1] === '/') {
+ // This could happen if both the host gets stripped
+ // out
+ // http://my/path
+ // //my/path
+ $this->path = '';
+ } else {
+ $this->path = $segments_encoder->encode($this->path);
+ }
+ } elseif (!is_null($this->scheme)) {
+ // path-rootless (hier)
+ // http:my/path
+ // Short circuit evaluation means we don't need to check nz
$this->path = $segments_encoder->encode($this->path);
- }
- } elseif (!is_null($this->scheme) && $this->path !== '') {
- // path-rootless (hier)
- // Short circuit evaluation means we don't need to check nz
- $this->path = $segments_encoder->encode($this->path);
- } elseif (is_null($this->scheme) && $this->path !== '') {
- // path-noscheme (relative)
- // (once again, not checking nz)
- $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@');
- $c = strpos($this->path, '/');
- if ($c !== false) {
- $this->path =
- $segment_nc_encoder->encode(substr($this->path, 0, $c)) .
- $segments_encoder->encode(substr($this->path, $c));
} else {
- $this->path = $segment_nc_encoder->encode($this->path);
+ // path-noscheme (relative)
+ // my/path
+ // (once again, not checking nz)
+ $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@');
+ $c = strpos($this->path, '/');
+ if ($c !== false) {
+ $this->path =
+ $segment_nc_encoder->encode(substr($this->path, 0, $c)) .
+ $segments_encoder->encode(substr($this->path, $c));
+ } else {
+ $this->path = $segment_nc_encoder->encode($this->path);
+ }
}
} else {
// path-empty (hier and relative)
@@ -138,36 +207,108 @@ class HTMLPurifier_URI
if (!is_null($this->fragment)) {
$this->fragment = $qf_encoder->encode($this->fragment);
}
-
return true;
-
}
/**
* Convert URI back to string
- * @return String URI appropriate for output
+ * @return string URI appropriate for output
*/
- public function toString() {
+ public function toString()
+ {
// reconstruct authority
$authority = null;
+ // there is a rendering difference between a null authority
+ // (http:foo-bar) and an empty string authority
+ // (http:///foo-bar).
if (!is_null($this->host)) {
$authority = '';
- if(!is_null($this->userinfo)) $authority .= $this->userinfo . '@';
+ if (!is_null($this->userinfo)) {
+ $authority .= $this->userinfo . '@';
+ }
$authority .= $this->host;
- if(!is_null($this->port)) $authority .= ':' . $this->port;
+ if (!is_null($this->port)) {
+ $authority .= ':' . $this->port;
+ }
}
- // reconstruct the result
+ // Reconstruct the result
+ // One might wonder about parsing quirks from browsers after
+ // this reconstruction. Unfortunately, parsing behavior depends
+ // on what *scheme* was employed (file:///foo is handled *very*
+ // differently than http:///foo), so unfortunately we have to
+ // defer to the schemes to do the right thing.
$result = '';
- if (!is_null($this->scheme)) $result .= $this->scheme . ':';
- if (!is_null($authority)) $result .= '//' . $authority;
+ if (!is_null($this->scheme)) {
+ $result .= $this->scheme . ':';
+ }
+ if (!is_null($authority)) {
+ $result .= '//' . $authority;
+ }
$result .= $this->path;
- if (!is_null($this->query)) $result .= '?' . $this->query;
- if (!is_null($this->fragment)) $result .= '#' . $this->fragment;
+ if (!is_null($this->query)) {
+ $result .= '?' . $this->query;
+ }
+ if (!is_null($this->fragment)) {
+ $result .= '#' . $this->fragment;
+ }
return $result;
}
+ /**
+ * Returns true if this URL might be considered a 'local' URL given
+ * the current context. This is true when the host is null, or
+ * when it matches the host supplied to the configuration.
+ *
+ * Note that this does not do any scheme checking, so it is mostly
+ * only appropriate for metadata that doesn't care about protocol
+ * security. isBenign is probably what you actually want.
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function isLocal($config, $context)
+ {
+ if ($this->host === null) {
+ return true;
+ }
+ $uri_def = $config->getDefinition('URI');
+ if ($uri_def->host === $this->host) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this URL should be considered a 'benign' URL,
+ * that is:
+ *
+ * - It is a local URL (isLocal), and
+ * - It has a equal or better level of security
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function isBenign($config, $context)
+ {
+ if (!$this->isLocal($config, $context)) {
+ return false;
+ }
+
+ $scheme_obj = $this->getSchemeObj($config, $context);
+ if (!$scheme_obj) {
+ return false;
+ } // conservative approach
+
+ $current_scheme_obj = $config->getDefinition('URI')->getDefaultScheme($config, $context);
+ if ($current_scheme_obj->secure) {
+ if (!$scheme_obj->secure) {
+ return false;
+ }
+ }
+ return true;
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIDefinition.php b/library/HTMLPurifier/URIDefinition.php
index ea2b8fe24..e0bd8bcca 100644
--- a/library/HTMLPurifier/URIDefinition.php
+++ b/library/HTMLPurifier/URIDefinition.php
@@ -23,19 +23,24 @@ class HTMLPurifier_URIDefinition extends HTMLPurifier_Definition
*/
public $defaultScheme;
- public function __construct() {
+ public function __construct()
+ {
$this->registerFilter(new HTMLPurifier_URIFilter_DisableExternal());
$this->registerFilter(new HTMLPurifier_URIFilter_DisableExternalResources());
+ $this->registerFilter(new HTMLPurifier_URIFilter_DisableResources());
$this->registerFilter(new HTMLPurifier_URIFilter_HostBlacklist());
+ $this->registerFilter(new HTMLPurifier_URIFilter_SafeIframe());
$this->registerFilter(new HTMLPurifier_URIFilter_MakeAbsolute());
$this->registerFilter(new HTMLPurifier_URIFilter_Munge());
}
- public function registerFilter($filter) {
+ public function registerFilter($filter)
+ {
$this->registeredFilters[$filter->name] = $filter;
}
- public function addFilter($filter, $config) {
+ public function addFilter($filter, $config)
+ {
$r = $filter->prepare($config);
if ($r === false) return; // null is ok, for backwards compat
if ($filter->post) {
@@ -45,22 +50,29 @@ class HTMLPurifier_URIDefinition extends HTMLPurifier_Definition
}
}
- protected function doSetup($config) {
+ protected function doSetup($config)
+ {
$this->setupMemberVariables($config);
$this->setupFilters($config);
}
- protected function setupFilters($config) {
+ protected function setupFilters($config)
+ {
foreach ($this->registeredFilters as $name => $filter) {
- $conf = $config->get('URI.' . $name);
- if ($conf !== false && $conf !== null) {
+ if ($filter->always_load) {
$this->addFilter($filter, $config);
+ } else {
+ $conf = $config->get('URI.' . $name);
+ if ($conf !== false && $conf !== null) {
+ $this->addFilter($filter, $config);
+ }
}
}
unset($this->registeredFilters);
}
- protected function setupMemberVariables($config) {
+ protected function setupMemberVariables($config)
+ {
$this->host = $config->get('URI.Host');
$base_uri = $config->get('URI.Base');
if (!is_null($base_uri)) {
@@ -72,7 +84,13 @@ class HTMLPurifier_URIDefinition extends HTMLPurifier_Definition
if (is_null($this->defaultScheme)) $this->defaultScheme = $config->get('URI.DefaultScheme');
}
- public function filter(&$uri, $config, $context) {
+ public function getDefaultScheme($config, $context)
+ {
+ return HTMLPurifier_URISchemeRegistry::instance()->getScheme($this->defaultScheme, $config, $context);
+ }
+
+ public function filter(&$uri, $config, $context)
+ {
foreach ($this->filters as $name => $f) {
$result = $f->filter($uri, $config, $context);
if (!$result) return false;
@@ -80,7 +98,8 @@ class HTMLPurifier_URIDefinition extends HTMLPurifier_Definition
return true;
}
- public function postFilter(&$uri, $config, $context) {
+ public function postFilter(&$uri, $config, $context)
+ {
foreach ($this->postFilters as $name => $f) {
$result = $f->filter($uri, $config, $context);
if (!$result) return false;
diff --git a/library/HTMLPurifier/URIFilter.php b/library/HTMLPurifier/URIFilter.php
index c116f93df..09724e9f4 100644
--- a/library/HTMLPurifier/URIFilter.php
+++ b/library/HTMLPurifier/URIFilter.php
@@ -4,7 +4,21 @@
* Chainable filters for custom URI processing.
*
* These filters can perform custom actions on a URI filter object,
- * including transformation or blacklisting.
+ * including transformation or blacklisting. A filter named Foo
+ * must have a corresponding configuration directive %URI.Foo,
+ * unless always_load is specified to be true.
+ *
+ * The following contexts may be available while URIFilters are being
+ * processed:
+ *
+ * - EmbeddedURI: true if URI is an embedded resource that will
+ * be loaded automatically on page load
+ * - CurrentToken: a reference to the token that is currently
+ * being processed
+ * - CurrentAttr: the name of the attribute that is currently being
+ * processed
+ * - CurrentCSSProperty: the name of the CSS property that is
+ * currently being processed (if applicable)
*
* @warning This filter is called before scheme object validation occurs.
* Make sure, if you require a specific scheme object, you
@@ -15,31 +29,46 @@ abstract class HTMLPurifier_URIFilter
{
/**
- * Unique identifier of filter
+ * Unique identifier of filter.
+ * @type string
*/
public $name;
/**
* True if this filter should be run after scheme validation.
+ * @type bool
*/
public $post = false;
/**
- * Performs initialization for the filter
+ * True if this filter should always be loaded.
+ * This permits a filter to be named Foo without the corresponding
+ * %URI.Foo directive existing.
+ * @type bool
+ */
+ public $always_load = false;
+
+ /**
+ * Performs initialization for the filter. If the filter returns
+ * false, this means that it shouldn't be considered active.
+ * @param HTMLPurifier_Config $config
+ * @return bool
*/
- public function prepare($config) {return true;}
+ public function prepare($config)
+ {
+ return true;
+ }
/**
* Filter a URI object
- * @param $uri Reference to URI object variable
- * @param $config Instance of HTMLPurifier_Config
- * @param $context Instance of HTMLPurifier_Context
+ * @param HTMLPurifier_URI $uri Reference to URI object variable
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
* @return bool Whether or not to continue processing: false indicates
* URL is no good, true indicates continue processing. Note that
* all changes are committed directly on the URI object
*/
abstract public function filter(&$uri, $config, $context);
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIFilter/DisableExternal.php b/library/HTMLPurifier/URIFilter/DisableExternal.php
index d8a39a501..ced1b1376 100644
--- a/library/HTMLPurifier/URIFilter/DisableExternal.php
+++ b/library/HTMLPurifier/URIFilter/DisableExternal.php
@@ -2,19 +2,50 @@
class HTMLPurifier_URIFilter_DisableExternal extends HTMLPurifier_URIFilter
{
+ /**
+ * @type string
+ */
public $name = 'DisableExternal';
+
+ /**
+ * @type array
+ */
protected $ourHostParts = false;
- public function prepare($config) {
+
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return void
+ */
+ public function prepare($config)
+ {
$our_host = $config->getDefinition('URI')->host;
- if ($our_host !== null) $this->ourHostParts = array_reverse(explode('.', $our_host));
+ if ($our_host !== null) {
+ $this->ourHostParts = array_reverse(explode('.', $our_host));
+ }
}
- public function filter(&$uri, $config, $context) {
- if (is_null($uri->host)) return true;
- if ($this->ourHostParts === false) return false;
+
+ /**
+ * @param HTMLPurifier_URI $uri Reference
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function filter(&$uri, $config, $context)
+ {
+ if (is_null($uri->host)) {
+ return true;
+ }
+ if ($this->ourHostParts === false) {
+ return false;
+ }
$host_parts = array_reverse(explode('.', $uri->host));
foreach ($this->ourHostParts as $i => $x) {
- if (!isset($host_parts[$i])) return false;
- if ($host_parts[$i] != $this->ourHostParts[$i]) return false;
+ if (!isset($host_parts[$i])) {
+ return false;
+ }
+ if ($host_parts[$i] != $this->ourHostParts[$i]) {
+ return false;
+ }
}
return true;
}
diff --git a/library/HTMLPurifier/URIFilter/DisableExternalResources.php b/library/HTMLPurifier/URIFilter/DisableExternalResources.php
index 881abc43c..c6562169e 100644
--- a/library/HTMLPurifier/URIFilter/DisableExternalResources.php
+++ b/library/HTMLPurifier/URIFilter/DisableExternalResources.php
@@ -2,9 +2,22 @@
class HTMLPurifier_URIFilter_DisableExternalResources extends HTMLPurifier_URIFilter_DisableExternal
{
+ /**
+ * @type string
+ */
public $name = 'DisableExternalResources';
- public function filter(&$uri, $config, $context) {
- if (!$context->get('EmbeddedURI', true)) return true;
+
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function filter(&$uri, $config, $context)
+ {
+ if (!$context->get('EmbeddedURI', true)) {
+ return true;
+ }
return parent::filter($uri, $config, $context);
}
}
diff --git a/library/HTMLPurifier/URIFilter/DisableResources.php b/library/HTMLPurifier/URIFilter/DisableResources.php
new file mode 100644
index 000000000..d5c412c44
--- /dev/null
+++ b/library/HTMLPurifier/URIFilter/DisableResources.php
@@ -0,0 +1,22 @@
+<?php
+
+class HTMLPurifier_URIFilter_DisableResources extends HTMLPurifier_URIFilter
+{
+ /**
+ * @type string
+ */
+ public $name = 'DisableResources';
+
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function filter(&$uri, $config, $context)
+ {
+ return !$context->get('EmbeddedURI', true);
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIFilter/HostBlacklist.php b/library/HTMLPurifier/URIFilter/HostBlacklist.php
index 045aa0992..a6645c17e 100644
--- a/library/HTMLPurifier/URIFilter/HostBlacklist.php
+++ b/library/HTMLPurifier/URIFilter/HostBlacklist.php
@@ -1,15 +1,40 @@
<?php
+// It's not clear to me whether or not Punycode means that hostnames
+// do not have canonical forms anymore. As far as I can tell, it's
+// not a problem (punycoding should be identity when no Unicode
+// points are involved), but I'm not 100% sure
class HTMLPurifier_URIFilter_HostBlacklist extends HTMLPurifier_URIFilter
{
+ /**
+ * @type string
+ */
public $name = 'HostBlacklist';
+
+ /**
+ * @type array
+ */
protected $blacklist = array();
- public function prepare($config) {
+
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function prepare($config)
+ {
$this->blacklist = $config->get('URI.HostBlacklist');
return true;
}
- public function filter(&$uri, $config, $context) {
- foreach($this->blacklist as $blacklisted_host_fragment) {
+
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function filter(&$uri, $config, $context)
+ {
+ foreach ($this->blacklist as $blacklisted_host_fragment) {
if (strpos($uri->host, $blacklisted_host_fragment) !== false) {
return false;
}
diff --git a/library/HTMLPurifier/URIFilter/MakeAbsolute.php b/library/HTMLPurifier/URIFilter/MakeAbsolute.php
index f46ab2630..c507bbff8 100644
--- a/library/HTMLPurifier/URIFilter/MakeAbsolute.php
+++ b/library/HTMLPurifier/URIFilter/MakeAbsolute.php
@@ -4,14 +4,35 @@
class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter
{
+ /**
+ * @type string
+ */
public $name = 'MakeAbsolute';
+
+ /**
+ * @type
+ */
protected $base;
+
+ /**
+ * @type array
+ */
protected $basePathStack = array();
- public function prepare($config) {
+
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function prepare($config)
+ {
$def = $config->getDefinition('URI');
$this->base = $def->base;
if (is_null($this->base)) {
- trigger_error('URI.MakeAbsolute is being ignored due to lack of value for URI.Base configuration', E_USER_WARNING);
+ trigger_error(
+ 'URI.MakeAbsolute is being ignored due to lack of ' .
+ 'value for URI.Base configuration',
+ E_USER_WARNING
+ );
return false;
}
$this->base->fragment = null; // fragment is invalid for base URI
@@ -21,19 +42,29 @@ class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter
$this->basePathStack = $stack;
return true;
}
- public function filter(&$uri, $config, $context) {
- if (is_null($this->base)) return true; // abort early
- if (
- $uri->path === '' && is_null($uri->scheme) &&
- is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment)
- ) {
+
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function filter(&$uri, $config, $context)
+ {
+ if (is_null($this->base)) {
+ return true;
+ } // abort early
+ if ($uri->path === '' && is_null($uri->scheme) &&
+ is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment)) {
// reference to current document
$uri = clone $this->base;
return true;
}
if (!is_null($uri->scheme)) {
// absolute URI already: don't change
- if (!is_null($uri->host)) return true;
+ if (!is_null($uri->host)) {
+ return true;
+ }
$scheme_obj = $uri->getSchemeObj($config, $context);
if (!$scheme_obj) {
// scheme not recognized
@@ -66,22 +97,33 @@ class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter
}
// re-combine
$uri->scheme = $this->base->scheme;
- if (is_null($uri->userinfo)) $uri->userinfo = $this->base->userinfo;
- if (is_null($uri->host)) $uri->host = $this->base->host;
- if (is_null($uri->port)) $uri->port = $this->base->port;
+ if (is_null($uri->userinfo)) {
+ $uri->userinfo = $this->base->userinfo;
+ }
+ if (is_null($uri->host)) {
+ $uri->host = $this->base->host;
+ }
+ if (is_null($uri->port)) {
+ $uri->port = $this->base->port;
+ }
return true;
}
/**
* Resolve dots and double-dots in a path stack
+ * @param array $stack
+ * @return array
*/
- private function _collapseStack($stack) {
+ private function _collapseStack($stack)
+ {
$result = array();
$is_folder = false;
for ($i = 0; isset($stack[$i]); $i++) {
$is_folder = false;
// absorb an internally duplicated slash
- if ($stack[$i] == '' && $i && isset($stack[$i+1])) continue;
+ if ($stack[$i] == '' && $i && isset($stack[$i + 1])) {
+ continue;
+ }
if ($stack[$i] == '..') {
if (!empty($result)) {
$segment = array_pop($result);
@@ -106,7 +148,9 @@ class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter
}
$result[] = $stack[$i];
}
- if ($is_folder) $result[] = '';
+ if ($is_folder) {
+ $result[] = '';
+ }
return $result;
}
}
diff --git a/library/HTMLPurifier/URIFilter/Munge.php b/library/HTMLPurifier/URIFilter/Munge.php
index efa10a645..6e03315a1 100644
--- a/library/HTMLPurifier/URIFilter/Munge.php
+++ b/library/HTMLPurifier/URIFilter/Munge.php
@@ -2,31 +2,79 @@
class HTMLPurifier_URIFilter_Munge extends HTMLPurifier_URIFilter
{
+ /**
+ * @type string
+ */
public $name = 'Munge';
+
+ /**
+ * @type bool
+ */
public $post = true;
- private $target, $parser, $doEmbed, $secretKey;
+ /**
+ * @type string
+ */
+ private $target;
+
+ /**
+ * @type HTMLPurifier_URIParser
+ */
+ private $parser;
+
+ /**
+ * @type bool
+ */
+ private $doEmbed;
+
+ /**
+ * @type string
+ */
+ private $secretKey;
+
+ /**
+ * @type array
+ */
protected $replace = array();
- public function prepare($config) {
- $this->target = $config->get('URI.' . $this->name);
- $this->parser = new HTMLPurifier_URIParser();
- $this->doEmbed = $config->get('URI.MungeResources');
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function prepare($config)
+ {
+ $this->target = $config->get('URI.' . $this->name);
+ $this->parser = new HTMLPurifier_URIParser();
+ $this->doEmbed = $config->get('URI.MungeResources');
$this->secretKey = $config->get('URI.MungeSecretKey');
+ if ($this->secretKey && !function_exists('hash_hmac')) {
+ throw new Exception("Cannot use %URI.MungeSecretKey without hash_hmac support.");
+ }
return true;
}
- public function filter(&$uri, $config, $context) {
- if ($context->get('EmbeddedURI', true) && !$this->doEmbed) return true;
- $scheme_obj = $uri->getSchemeObj($config, $context);
- if (!$scheme_obj) return true; // ignore unknown schemes, maybe another postfilter did it
- if (is_null($uri->host) || empty($scheme_obj->browsable)) {
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function filter(&$uri, $config, $context)
+ {
+ if ($context->get('EmbeddedURI', true) && !$this->doEmbed) {
return true;
}
- // don't redirect if target host is our host
- if ($uri->host === $config->getDefinition('URI')->host) {
+
+ $scheme_obj = $uri->getSchemeObj($config, $context);
+ if (!$scheme_obj) {
return true;
- }
+ } // ignore unknown schemes, maybe another postfilter did it
+ if (!$scheme_obj->browsable) {
+ return true;
+ } // ignore non-browseable schemes, since we can't munge those in a reasonable way
+ if ($uri->isBenign($config, $context)) {
+ return true;
+ } // don't redirect if a benign URL
$this->makeReplace($uri, $config, $context);
$this->replace = array_map('rawurlencode', $this->replace);
@@ -35,12 +83,20 @@ class HTMLPurifier_URIFilter_Munge extends HTMLPurifier_URIFilter
$new_uri = $this->parser->parse($new_uri);
// don't redirect if the target host is the same as the
// starting host
- if ($uri->host === $new_uri->host) return true;
+ if ($uri->host === $new_uri->host) {
+ return true;
+ }
$uri = $new_uri; // overwrite
return true;
}
- protected function makeReplace($uri, $config, $context) {
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ */
+ protected function makeReplace($uri, $config, $context)
+ {
$string = $uri->toString();
// always available
$this->replace['%s'] = $string;
@@ -50,9 +106,10 @@ class HTMLPurifier_URIFilter_Munge extends HTMLPurifier_URIFilter
$this->replace['%m'] = $context->get('CurrentAttr', true);
$this->replace['%p'] = $context->get('CurrentCSSProperty', true);
// not always available
- if ($this->secretKey) $this->replace['%t'] = sha1($this->secretKey . ':' . $string);
+ if ($this->secretKey) {
+ $this->replace['%t'] = hash_hmac("sha256", $string, $this->secretKey);
+ }
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIFilter/SafeIframe.php b/library/HTMLPurifier/URIFilter/SafeIframe.php
new file mode 100644
index 000000000..f609c47a3
--- /dev/null
+++ b/library/HTMLPurifier/URIFilter/SafeIframe.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * Implements safety checks for safe iframes.
+ *
+ * @warning This filter is *critical* for ensuring that %HTML.SafeIframe
+ * works safely.
+ */
+class HTMLPurifier_URIFilter_SafeIframe extends HTMLPurifier_URIFilter
+{
+ /**
+ * @type string
+ */
+ public $name = 'SafeIframe';
+
+ /**
+ * @type bool
+ */
+ public $always_load = true;
+
+ /**
+ * @type string
+ */
+ protected $regexp = null;
+
+ // XXX: The not so good bit about how this is all set up now is we
+ // can't check HTML.SafeIframe in the 'prepare' step: we have to
+ // defer till the actual filtering.
+ /**
+ * @param HTMLPurifier_Config $config
+ * @return bool
+ */
+ public function prepare($config)
+ {
+ $this->regexp = $config->get('URI.SafeIframeRegexp');
+ return true;
+ }
+
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function filter(&$uri, $config, $context)
+ {
+ // check if filter not applicable
+ if (!$config->get('HTML.SafeIframe')) {
+ return true;
+ }
+ // check if the filter should actually trigger
+ if (!$context->get('EmbeddedURI', true)) {
+ return true;
+ }
+ $token = $context->get('CurrentToken', true);
+ if (!($token && $token->name == 'iframe')) {
+ return true;
+ }
+ // check if we actually have some whitelists enabled
+ if ($this->regexp === null) {
+ return false;
+ }
+ // actually check the whitelists
+ return preg_match($this->regexp, $uri->toString());
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIParser.php b/library/HTMLPurifier/URIParser.php
index 7179e4ab8..0e7381a07 100644
--- a/library/HTMLPurifier/URIParser.php
+++ b/library/HTMLPurifier/URIParser.php
@@ -12,7 +12,8 @@ class HTMLPurifier_URIParser
*/
protected $percentEncoder;
- public function __construct() {
+ public function __construct()
+ {
$this->percentEncoder = new HTMLPurifier_PercentEncoder();
}
@@ -22,15 +23,15 @@ class HTMLPurifier_URIParser
* @return HTMLPurifier_URI representation of URI. This representation has
* not been validated yet and may not conform to RFC.
*/
- public function parse($uri) {
-
+ public function parse($uri)
+ {
$uri = $this->percentEncoder->normalize($uri);
// Regexp is as per Appendix B.
// Note that ["<>] are an addition to the RFC's recommended
// characters, because they represent external delimeters.
$r_URI = '!'.
- '(([^:/?#"<>]+):)?'. // 2. Scheme
+ '(([a-zA-Z0-9\.\+\-]+):)?'. // 2. Scheme
'(//([^/?#"<>]*))?'. // 4. Authority
'([^?#"<>]*)'. // 5. Path
'(\?([^#"<>]*))?'. // 7. Query
diff --git a/library/HTMLPurifier/URIScheme.php b/library/HTMLPurifier/URIScheme.php
index 039710fd1..fe9e82cf2 100644
--- a/library/HTMLPurifier/URIScheme.php
+++ b/library/HTMLPurifier/URIScheme.php
@@ -3,40 +3,100 @@
/**
* Validator for the components of a URI for a specific scheme
*/
-class HTMLPurifier_URIScheme
+abstract class HTMLPurifier_URIScheme
{
/**
- * Scheme's default port (integer)
+ * Scheme's default port (integer). If an explicit port number is
+ * specified that coincides with the default port, it will be
+ * elided.
+ * @type int
*/
public $default_port = null;
/**
- * Whether or not URIs of this schem are locatable by a browser
+ * Whether or not URIs of this scheme are locatable by a browser
* http and ftp are accessible, while mailto and news are not.
+ * @type bool
*/
public $browsable = false;
/**
+ * Whether or not data transmitted over this scheme is encrypted.
+ * https is secure, http is not.
+ * @type bool
+ */
+ public $secure = false;
+
+ /**
* Whether or not the URI always uses <hier_part>, resolves edge cases
* with making relative URIs absolute
+ * @type bool
*/
public $hierarchical = false;
/**
- * Validates the components of a URI
- * @note This implementation should be called by children if they define
- * a default port, as it does port processing.
- * @param $uri Instance of HTMLPurifier_URI
- * @param $config HTMLPurifier_Config object
- * @param $context HTMLPurifier_Context object
- * @return Bool success or failure
+ * Whether or not the URI may omit a hostname when the scheme is
+ * explicitly specified, ala file:///path/to/file. As of writing,
+ * 'file' is the only scheme that browsers support his properly.
+ * @type bool
*/
- public function validate(&$uri, $config, $context) {
- if ($this->default_port == $uri->port) $uri->port = null;
- return true;
- }
+ public $may_omit_host = false;
+
+ /**
+ * Validates the components of a URI for a specific scheme.
+ * @param HTMLPurifier_URI $uri Reference to a HTMLPurifier_URI object
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool success or failure
+ */
+ abstract public function doValidate(&$uri, $config, $context);
+ /**
+ * Public interface for validating components of a URI. Performs a
+ * bunch of default actions. Don't overload this method.
+ * @param HTMLPurifier_URI $uri Reference to a HTMLPurifier_URI object
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool success or failure
+ */
+ public function validate(&$uri, $config, $context)
+ {
+ if ($this->default_port == $uri->port) {
+ $uri->port = null;
+ }
+ // kludge: browsers do funny things when the scheme but not the
+ // authority is set
+ if (!$this->may_omit_host &&
+ // if the scheme is present, a missing host is always in error
+ (!is_null($uri->scheme) && ($uri->host === '' || is_null($uri->host))) ||
+ // if the scheme is not present, a *blank* host is in error,
+ // since this translates into '///path' which most browsers
+ // interpret as being 'http://path'.
+ (is_null($uri->scheme) && $uri->host === '')
+ ) {
+ do {
+ if (is_null($uri->scheme)) {
+ if (substr($uri->path, 0, 2) != '//') {
+ $uri->host = null;
+ break;
+ }
+ // URI is '////path', so we cannot nullify the
+ // host to preserve semantics. Try expanding the
+ // hostname instead (fall through)
+ }
+ // first see if we can manually insert a hostname
+ $host = $config->get('URI.Host');
+ if (!is_null($host)) {
+ $uri->host = $host;
+ } else {
+ // we can't do anything sensible, reject the URL.
+ return false;
+ }
+ } while (false);
+ }
+ return $this->doValidate($uri, $config, $context);
+ }
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIScheme/data.php b/library/HTMLPurifier/URIScheme/data.php
index b7f1989cb..6ebca4984 100644
--- a/library/HTMLPurifier/URIScheme/data.php
+++ b/library/HTMLPurifier/URIScheme/data.php
@@ -3,18 +3,38 @@
/**
* Implements data: URI for base64 encoded images supported by GD.
*/
-class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme {
-
+class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme
+{
+ /**
+ * @type bool
+ */
public $browsable = true;
+
+ /**
+ * @type array
+ */
public $allowed_types = array(
// you better write validation code for other types if you
// decide to allow them
'image/jpeg' => true,
'image/gif' => true,
'image/png' => true,
- );
+ );
+ // this is actually irrelevant since we only write out the path
+ // component
+ /**
+ * @type bool
+ */
+ public $may_omit_host = true;
- public function validate(&$uri, $config, $context) {
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function doValidate(&$uri, $config, $context)
+ {
$result = explode(',', $uri->path, 2);
$is_base64 = false;
$charset = null;
@@ -23,7 +43,7 @@ class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme {
list($metadata, $data) = $result;
// do some legwork on the metadata
$metas = explode(';', $metadata);
- while(!empty($metas)) {
+ while (!empty($metas)) {
$cur = array_shift($metas);
if ($cur == 'base64') {
$is_base64 = true;
@@ -32,10 +52,14 @@ class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme {
if (substr($cur, 0, 8) == 'charset=') {
// doesn't match if there are arbitrary spaces, but
// whatever dude
- if ($charset !== null) continue; // garbage
+ if ($charset !== null) {
+ continue;
+ } // garbage
$charset = substr($cur, 8); // not used
} else {
- if ($content_type !== null) continue; // garbage
+ if ($content_type !== null) {
+ continue;
+ } // garbage
$content_type = $cur;
}
}
@@ -61,11 +85,15 @@ class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme {
file_put_contents($file, $raw_data);
if (function_exists('exif_imagetype')) {
$image_code = exif_imagetype($file);
+ unlink($file);
} elseif (function_exists('getimagesize')) {
set_error_handler(array($this, 'muteErrorHandler'));
$info = getimagesize($file);
restore_error_handler();
- if ($info == false) return false;
+ unlink($file);
+ if ($info == false) {
+ return false;
+ }
$image_code = $info[2];
} else {
trigger_error("could not find exif_imagetype or getimagesize functions", E_USER_ERROR);
@@ -74,7 +102,9 @@ class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme {
if ($real_content_type != $content_type) {
// we're nice guys; if the content type is something else we
// support, change it over
- if (empty($this->allowed_types[$real_content_type])) return false;
+ if (empty($this->allowed_types[$real_content_type])) {
+ return false;
+ }
$content_type = $real_content_type;
}
// ok, it's kosher, rewrite what we need
@@ -87,7 +117,11 @@ class HTMLPurifier_URIScheme_data extends HTMLPurifier_URIScheme {
return true;
}
- public function muteErrorHandler($errno, $errstr) {}
-
+ /**
+ * @param int $errno
+ * @param string $errstr
+ */
+ public function muteErrorHandler($errno, $errstr)
+ {
+ }
}
-
diff --git a/library/HTMLPurifier/URIScheme/file.php b/library/HTMLPurifier/URIScheme/file.php
new file mode 100644
index 000000000..215be4ba8
--- /dev/null
+++ b/library/HTMLPurifier/URIScheme/file.php
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * Validates file as defined by RFC 1630 and RFC 1738.
+ */
+class HTMLPurifier_URIScheme_file extends HTMLPurifier_URIScheme
+{
+ /**
+ * Generally file:// URLs are not accessible from most
+ * machines, so placing them as an img src is incorrect.
+ * @type bool
+ */
+ public $browsable = false;
+
+ /**
+ * Basically the *only* URI scheme for which this is true, since
+ * accessing files on the local machine is very common. In fact,
+ * browsers on some operating systems don't understand the
+ * authority, though I hear it is used on Windows to refer to
+ * network shares.
+ * @type bool
+ */
+ public $may_omit_host = true;
+
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function doValidate(&$uri, $config, $context)
+ {
+ // Authentication method is not supported
+ $uri->userinfo = null;
+ // file:// makes no provisions for accessing the resource
+ $uri->port = null;
+ // While it seems to work on Firefox, the querystring has
+ // no possible effect and is thus stripped.
+ $uri->query = null;
+ return true;
+ }
+}
+
+// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIScheme/ftp.php b/library/HTMLPurifier/URIScheme/ftp.php
index 5849bf7ff..1eb43ee5c 100644
--- a/library/HTMLPurifier/URIScheme/ftp.php
+++ b/library/HTMLPurifier/URIScheme/ftp.php
@@ -3,15 +3,32 @@
/**
* Validates ftp (File Transfer Protocol) URIs as defined by generic RFC 1738.
*/
-class HTMLPurifier_URIScheme_ftp extends HTMLPurifier_URIScheme {
-
+class HTMLPurifier_URIScheme_ftp extends HTMLPurifier_URIScheme
+{
+ /**
+ * @type int
+ */
public $default_port = 21;
+
+ /**
+ * @type bool
+ */
public $browsable = true; // usually
+
+ /**
+ * @type bool
+ */
public $hierarchical = true;
- public function validate(&$uri, $config, $context) {
- parent::validate($uri, $config, $context);
- $uri->query = null;
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function doValidate(&$uri, $config, $context)
+ {
+ $uri->query = null;
// typecode check
$semicolon_pos = strrpos($uri->path, ';'); // reverse
@@ -34,10 +51,8 @@ class HTMLPurifier_URIScheme_ftp extends HTMLPurifier_URIScheme {
$uri->path = str_replace(';', '%3B', $uri->path);
$uri->path .= $type_ret;
}
-
return true;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIScheme/http.php b/library/HTMLPurifier/URIScheme/http.php
index b097a31d6..ce69ec438 100644
--- a/library/HTMLPurifier/URIScheme/http.php
+++ b/library/HTMLPurifier/URIScheme/http.php
@@ -3,18 +3,34 @@
/**
* Validates http (HyperText Transfer Protocol) as defined by RFC 2616
*/
-class HTMLPurifier_URIScheme_http extends HTMLPurifier_URIScheme {
-
+class HTMLPurifier_URIScheme_http extends HTMLPurifier_URIScheme
+{
+ /**
+ * @type int
+ */
public $default_port = 80;
+
+ /**
+ * @type bool
+ */
public $browsable = true;
+
+ /**
+ * @type bool
+ */
public $hierarchical = true;
- public function validate(&$uri, $config, $context) {
- parent::validate($uri, $config, $context);
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function doValidate(&$uri, $config, $context)
+ {
$uri->userinfo = null;
return true;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIScheme/https.php b/library/HTMLPurifier/URIScheme/https.php
index 29e380919..0e96882db 100644
--- a/library/HTMLPurifier/URIScheme/https.php
+++ b/library/HTMLPurifier/URIScheme/https.php
@@ -3,10 +3,16 @@
/**
* Validates https (Secure HTTP) according to http scheme.
*/
-class HTMLPurifier_URIScheme_https extends HTMLPurifier_URIScheme_http {
-
+class HTMLPurifier_URIScheme_https extends HTMLPurifier_URIScheme_http
+{
+ /**
+ * @type int
+ */
public $default_port = 443;
-
+ /**
+ * @type bool
+ */
+ public $secure = true;
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIScheme/mailto.php b/library/HTMLPurifier/URIScheme/mailto.php
index c1e2cd5aa..c3a6b602a 100644
--- a/library/HTMLPurifier/URIScheme/mailto.php
+++ b/library/HTMLPurifier/URIScheme/mailto.php
@@ -9,19 +9,32 @@
* @todo Filter allowed query parameters
*/
-class HTMLPurifier_URIScheme_mailto extends HTMLPurifier_URIScheme {
-
+class HTMLPurifier_URIScheme_mailto extends HTMLPurifier_URIScheme
+{
+ /**
+ * @type bool
+ */
public $browsable = false;
- public function validate(&$uri, $config, $context) {
- parent::validate($uri, $config, $context);
+ /**
+ * @type bool
+ */
+ public $may_omit_host = true;
+
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function doValidate(&$uri, $config, $context)
+ {
$uri->userinfo = null;
$uri->host = null;
$uri->port = null;
// we need to validate path against RFC 2368's addr-spec
return true;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIScheme/news.php b/library/HTMLPurifier/URIScheme/news.php
index f5f54f4f5..7490927d6 100644
--- a/library/HTMLPurifier/URIScheme/news.php
+++ b/library/HTMLPurifier/URIScheme/news.php
@@ -3,20 +3,33 @@
/**
* Validates news (Usenet) as defined by generic RFC 1738
*/
-class HTMLPurifier_URIScheme_news extends HTMLPurifier_URIScheme {
-
+class HTMLPurifier_URIScheme_news extends HTMLPurifier_URIScheme
+{
+ /**
+ * @type bool
+ */
public $browsable = false;
- public function validate(&$uri, $config, $context) {
- parent::validate($uri, $config, $context);
+ /**
+ * @type bool
+ */
+ public $may_omit_host = true;
+
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function doValidate(&$uri, $config, $context)
+ {
$uri->userinfo = null;
- $uri->host = null;
- $uri->port = null;
- $uri->query = null;
+ $uri->host = null;
+ $uri->port = null;
+ $uri->query = null;
// typecode check needed on path
return true;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URIScheme/nntp.php b/library/HTMLPurifier/URIScheme/nntp.php
index 5bf93ea78..f211d715e 100644
--- a/library/HTMLPurifier/URIScheme/nntp.php
+++ b/library/HTMLPurifier/URIScheme/nntp.php
@@ -3,18 +3,30 @@
/**
* Validates nntp (Network News Transfer Protocol) as defined by generic RFC 1738
*/
-class HTMLPurifier_URIScheme_nntp extends HTMLPurifier_URIScheme {
-
+class HTMLPurifier_URIScheme_nntp extends HTMLPurifier_URIScheme
+{
+ /**
+ * @type int
+ */
public $default_port = 119;
+
+ /**
+ * @type bool
+ */
public $browsable = false;
- public function validate(&$uri, $config, $context) {
- parent::validate($uri, $config, $context);
+ /**
+ * @param HTMLPurifier_URI $uri
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return bool
+ */
+ public function doValidate(&$uri, $config, $context)
+ {
$uri->userinfo = null;
- $uri->query = null;
+ $uri->query = null;
return true;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/URISchemeRegistry.php b/library/HTMLPurifier/URISchemeRegistry.php
index 576bf7b6d..4ac8a0b76 100644
--- a/library/HTMLPurifier/URISchemeRegistry.php
+++ b/library/HTMLPurifier/URISchemeRegistry.php
@@ -8,12 +8,14 @@ class HTMLPurifier_URISchemeRegistry
/**
* Retrieve sole instance of the registry.
- * @param $prototype Optional prototype to overload sole instance with,
+ * @param HTMLPurifier_URISchemeRegistry $prototype Optional prototype to overload sole instance with,
* or bool true to reset to default registry.
+ * @return HTMLPurifier_URISchemeRegistry
* @note Pass a registry object $prototype with a compatible interface and
* the function will copy it and return it all further times.
*/
- public static function instance($prototype = null) {
+ public static function instance($prototype = null)
+ {
static $instance = null;
if ($prototype !== null) {
$instance = $prototype;
@@ -25,17 +27,22 @@ class HTMLPurifier_URISchemeRegistry
/**
* Cache of retrieved schemes.
+ * @type HTMLPurifier_URIScheme[]
*/
protected $schemes = array();
/**
* Retrieves a scheme validator object
- * @param $scheme String scheme name like http or mailto
- * @param $config HTMLPurifier_Config object
- * @param $config HTMLPurifier_Context object
+ * @param string $scheme String scheme name like http or mailto
+ * @param HTMLPurifier_Config $config
+ * @param HTMLPurifier_Context $context
+ * @return HTMLPurifier_URIScheme
*/
- public function getScheme($scheme, $config, $context) {
- if (!$config) $config = HTMLPurifier_Config::createDefault();
+ public function getScheme($scheme, $config, $context)
+ {
+ if (!$config) {
+ $config = HTMLPurifier_Config::createDefault();
+ }
// important, otherwise attacker could include arbitrary file
$allowed_schemes = $config->get('URI.AllowedSchemes');
@@ -45,24 +52,30 @@ class HTMLPurifier_URISchemeRegistry
return;
}
- if (isset($this->schemes[$scheme])) return $this->schemes[$scheme];
- if (!isset($allowed_schemes[$scheme])) return;
+ if (isset($this->schemes[$scheme])) {
+ return $this->schemes[$scheme];
+ }
+ if (!isset($allowed_schemes[$scheme])) {
+ return;
+ }
$class = 'HTMLPurifier_URIScheme_' . $scheme;
- if (!class_exists($class)) return;
+ if (!class_exists($class)) {
+ return;
+ }
$this->schemes[$scheme] = new $class();
return $this->schemes[$scheme];
}
/**
* Registers a custom scheme to the cache, bypassing reflection.
- * @param $scheme Scheme name
- * @param $scheme_obj HTMLPurifier_URIScheme object
+ * @param string $scheme Scheme name
+ * @param HTMLPurifier_URIScheme $scheme_obj
*/
- public function register($scheme, $scheme_obj) {
+ public function register($scheme, $scheme_obj)
+ {
$this->schemes[$scheme] = $scheme_obj;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/UnitConverter.php b/library/HTMLPurifier/UnitConverter.php
index 545d42622..166f3bf30 100644
--- a/library/HTMLPurifier/UnitConverter.php
+++ b/library/HTMLPurifier/UnitConverter.php
@@ -37,20 +37,24 @@ class HTMLPurifier_UnitConverter
/**
* Minimum bcmath precision for output.
+ * @type int
*/
protected $outputPrecision;
/**
* Bcmath precision for internal calculations.
+ * @type int
*/
protected $internalPrecision;
/**
- * Whether or not BCMath is available
+ * Whether or not BCMath is available.
+ * @type bool
*/
private $bcmath;
- public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath = false) {
+ public function __construct($output_precision = 4, $internal_precision = 10, $force_no_bcmath = false)
+ {
$this->outputPrecision = $output_precision;
$this->internalPrecision = $internal_precision;
$this->bcmath = !$force_no_bcmath && function_exists('bcmul');
@@ -63,6 +67,7 @@ class HTMLPurifier_UnitConverter
* it before passing it here!
* @param string $to_unit
* Unit to convert to.
+ * @return HTMLPurifier_Length|bool
* @note
* About precision: This conversion function pays very special
* attention to the incoming precision of values and attempts
@@ -74,11 +79,13 @@ class HTMLPurifier_UnitConverter
* and this causes some decimals to be excluded, those
* decimals will be added on.
*/
- public function convert($length, $to_unit) {
-
- if (!$length->isValid()) return false;
+ public function convert($length, $to_unit)
+ {
+ if (!$length->isValid()) {
+ return false;
+ }
- $n = $length->getN();
+ $n = $length->getN();
$unit = $length->getUnit();
if ($n === '0' || $unit === false) {
@@ -87,21 +94,29 @@ class HTMLPurifier_UnitConverter
$state = $dest_state = false;
foreach (self::$units as $k => $x) {
- if (isset($x[$unit])) $state = $k;
- if (isset($x[$to_unit])) $dest_state = $k;
+ if (isset($x[$unit])) {
+ $state = $k;
+ }
+ if (isset($x[$to_unit])) {
+ $dest_state = $k;
+ }
+ }
+ if (!$state || !$dest_state) {
+ return false;
}
- if (!$state || !$dest_state) return false;
// Some calculations about the initial precision of the number;
// this will be useful when we need to do final rounding.
$sigfigs = $this->getSigFigs($n);
- if ($sigfigs < $this->outputPrecision) $sigfigs = $this->outputPrecision;
+ if ($sigfigs < $this->outputPrecision) {
+ $sigfigs = $this->outputPrecision;
+ }
// BCMath's internal precision deals only with decimals. Use
// our default if the initial number has no decimals, or increase
// it by how ever many decimals, thus, the number of guard digits
// will always be greater than or equal to internalPrecision.
- $log = (int) floor(log(abs($n), 10));
+ $log = (int)floor(log(abs($n), 10));
$cp = ($log < 0) ? $this->internalPrecision - $log : $this->internalPrecision; // internal precision
for ($i = 0; $i < 2; $i++) {
@@ -152,14 +167,18 @@ class HTMLPurifier_UnitConverter
}
// Post-condition: $unit == $to_unit
- if ($unit !== $to_unit) return false;
+ if ($unit !== $to_unit) {
+ return false;
+ }
// Useful for debugging:
//echo "<pre>n";
//echo "$n\nsigfigs = $sigfigs\nnew_log = $new_log\nlog = $log\nrp = $rp\n</pre>\n";
$n = $this->round($n, $sigfigs);
- if (strpos($n, '.') !== false) $n = rtrim($n, '0');
+ if (strpos($n, '.') !== false) {
+ $n = rtrim($n, '0');
+ }
$n = rtrim($n, '.');
return new HTMLPurifier_Length($n, $unit);
@@ -170,53 +189,84 @@ class HTMLPurifier_UnitConverter
* @param string $n Decimal number
* @return int number of sigfigs
*/
- public function getSigFigs($n) {
+ public function getSigFigs($n)
+ {
$n = ltrim($n, '0+-');
$dp = strpos($n, '.'); // decimal position
if ($dp === false) {
$sigfigs = strlen(rtrim($n, '0'));
} else {
$sigfigs = strlen(ltrim($n, '0.')); // eliminate extra decimal character
- if ($dp !== 0) $sigfigs--;
+ if ($dp !== 0) {
+ $sigfigs--;
+ }
}
return $sigfigs;
}
/**
* Adds two numbers, using arbitrary precision when available.
+ * @param string $s1
+ * @param string $s2
+ * @param int $scale
+ * @return string
*/
- private function add($s1, $s2, $scale) {
- if ($this->bcmath) return bcadd($s1, $s2, $scale);
- else return $this->scale($s1 + $s2, $scale);
+ private function add($s1, $s2, $scale)
+ {
+ if ($this->bcmath) {
+ return bcadd($s1, $s2, $scale);
+ } else {
+ return $this->scale((float)$s1 + (float)$s2, $scale);
+ }
}
/**
* Multiples two numbers, using arbitrary precision when available.
+ * @param string $s1
+ * @param string $s2
+ * @param int $scale
+ * @return string
*/
- private function mul($s1, $s2, $scale) {
- if ($this->bcmath) return bcmul($s1, $s2, $scale);
- else return $this->scale($s1 * $s2, $scale);
+ private function mul($s1, $s2, $scale)
+ {
+ if ($this->bcmath) {
+ return bcmul($s1, $s2, $scale);
+ } else {
+ return $this->scale((float)$s1 * (float)$s2, $scale);
+ }
}
/**
* Divides two numbers, using arbitrary precision when available.
+ * @param string $s1
+ * @param string $s2
+ * @param int $scale
+ * @return string
*/
- private function div($s1, $s2, $scale) {
- if ($this->bcmath) return bcdiv($s1, $s2, $scale);
- else return $this->scale($s1 / $s2, $scale);
+ private function div($s1, $s2, $scale)
+ {
+ if ($this->bcmath) {
+ return bcdiv($s1, $s2, $scale);
+ } else {
+ return $this->scale((float)$s1 / (float)$s2, $scale);
+ }
}
/**
* Rounds a number according to the number of sigfigs it should have,
* using arbitrary precision when available.
+ * @param float $n
+ * @param int $sigfigs
+ * @return string
*/
- private function round($n, $sigfigs) {
- $new_log = (int) floor(log(abs($n), 10)); // Number of digits left of decimal - 1
+ private function round($n, $sigfigs)
+ {
+ $new_log = (int)floor(log(abs($n), 10)); // Number of digits left of decimal - 1
$rp = $sigfigs - $new_log - 1; // Number of decimal places needed
$neg = $n < 0 ? '-' : ''; // Negative sign
if ($this->bcmath) {
if ($rp >= 0) {
- $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1);
+ $n = bcadd($n, $neg . '0.' . str_repeat('0', $rp) . '5', $rp + 1);
$n = bcdiv($n, '1', $rp);
} else {
// This algorithm partially depends on the standardized
@@ -232,23 +282,26 @@ class HTMLPurifier_UnitConverter
/**
* Scales a float to $scale digits right of decimal point, like BCMath.
+ * @param float $r
+ * @param int $scale
+ * @return string
*/
- private function scale($r, $scale) {
+ private function scale($r, $scale)
+ {
if ($scale < 0) {
// The f sprintf type doesn't support negative numbers, so we
// need to cludge things manually. First get the string.
- $r = sprintf('%.0f', (float) $r);
+ $r = sprintf('%.0f', (float)$r);
// Due to floating point precision loss, $r will more than likely
// look something like 4652999999999.9234. We grab one more digit
// than we need to precise from $r and then use that to round
// appropriately.
- $precise = (string) round(substr($r, 0, strlen($r) + $scale), -1);
+ $precise = (string)round(substr($r, 0, strlen($r) + $scale), -1);
// Now we return it, truncating the zero that was rounded off.
return substr($precise, 0, -1) . str_repeat('0', -$scale + 1);
}
- return sprintf('%.' . $scale . 'f', (float) $r);
+ return sprintf('%.' . $scale . 'f', (float)$r);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/VarParser.php b/library/HTMLPurifier/VarParser.php
index 68e72ae86..50cba6910 100644
--- a/library/HTMLPurifier/VarParser.php
+++ b/library/HTMLPurifier/VarParser.php
@@ -7,58 +7,59 @@
class HTMLPurifier_VarParser
{
- const STRING = 1;
- const ISTRING = 2;
- const TEXT = 3;
- const ITEXT = 4;
- const INT = 5;
- const FLOAT = 6;
- const BOOL = 7;
- const LOOKUP = 8;
- const ALIST = 9;
- const HASH = 10;
- const MIXED = 11;
+ const STRING = 1;
+ const ISTRING = 2;
+ const TEXT = 3;
+ const ITEXT = 4;
+ const INT = 5;
+ const FLOAT = 6;
+ const BOOL = 7;
+ const LOOKUP = 8;
+ const ALIST = 9;
+ const HASH = 10;
+ const MIXED = 11;
/**
* Lookup table of allowed types. Mainly for backwards compatibility, but
* also convenient for transforming string type names to the integer constants.
*/
- static public $types = array(
- 'string' => self::STRING,
- 'istring' => self::ISTRING,
- 'text' => self::TEXT,
- 'itext' => self::ITEXT,
- 'int' => self::INT,
- 'float' => self::FLOAT,
- 'bool' => self::BOOL,
- 'lookup' => self::LOOKUP,
- 'list' => self::ALIST,
- 'hash' => self::HASH,
- 'mixed' => self::MIXED
+ public static $types = array(
+ 'string' => self::STRING,
+ 'istring' => self::ISTRING,
+ 'text' => self::TEXT,
+ 'itext' => self::ITEXT,
+ 'int' => self::INT,
+ 'float' => self::FLOAT,
+ 'bool' => self::BOOL,
+ 'lookup' => self::LOOKUP,
+ 'list' => self::ALIST,
+ 'hash' => self::HASH,
+ 'mixed' => self::MIXED
);
/**
* Lookup table of types that are string, and can have aliases or
* allowed value lists.
*/
- static public $stringTypes = array(
- self::STRING => true,
- self::ISTRING => true,
- self::TEXT => true,
- self::ITEXT => true,
+ public static $stringTypes = array(
+ self::STRING => true,
+ self::ISTRING => true,
+ self::TEXT => true,
+ self::ITEXT => true,
);
/**
- * Validate a variable according to type. Throws
- * HTMLPurifier_VarParserException if invalid.
+ * Validate a variable according to type.
* It may return NULL as a valid type if $allow_null is true.
*
- * @param $var Variable to validate
- * @param $type Type of variable, see HTMLPurifier_VarParser->types
- * @param $allow_null Whether or not to permit null as a value
- * @return Validated and type-coerced variable
+ * @param mixed $var Variable to validate
+ * @param int $type Type of variable, see HTMLPurifier_VarParser->types
+ * @param bool $allow_null Whether or not to permit null as a value
+ * @return string Validated and type-coerced variable
+ * @throws HTMLPurifier_VarParserException
*/
- final public function parse($var, $type, $allow_null = false) {
+ final public function parse($var, $type, $allow_null = false)
+ {
if (is_string($type)) {
if (!isset(HTMLPurifier_VarParser::$types[$type])) {
throw new HTMLPurifier_VarParserException("Invalid type '$type'");
@@ -67,7 +68,9 @@ class HTMLPurifier_VarParser
}
}
$var = $this->parseImplementation($var, $type, $allow_null);
- if ($allow_null && $var === null) return null;
+ if ($allow_null && $var === null) {
+ return null;
+ }
// These are basic checks, to make sure nothing horribly wrong
// happened in our implementations.
switch ($type) {
@@ -75,27 +78,45 @@ class HTMLPurifier_VarParser
case (self::ISTRING):
case (self::TEXT):
case (self::ITEXT):
- if (!is_string($var)) break;
- if ($type == self::ISTRING || $type == self::ITEXT) $var = strtolower($var);
+ if (!is_string($var)) {
+ break;
+ }
+ if ($type == self::ISTRING || $type == self::ITEXT) {
+ $var = strtolower($var);
+ }
return $var;
case (self::INT):
- if (!is_int($var)) break;
+ if (!is_int($var)) {
+ break;
+ }
return $var;
case (self::FLOAT):
- if (!is_float($var)) break;
+ if (!is_float($var)) {
+ break;
+ }
return $var;
case (self::BOOL):
- if (!is_bool($var)) break;
+ if (!is_bool($var)) {
+ break;
+ }
return $var;
case (self::LOOKUP):
case (self::ALIST):
case (self::HASH):
- if (!is_array($var)) break;
+ if (!is_array($var)) {
+ break;
+ }
if ($type === self::LOOKUP) {
- foreach ($var as $k) if ($k !== true) $this->error('Lookup table contains value other than true');
+ foreach ($var as $k) {
+ if ($k !== true) {
+ $this->error('Lookup table contains value other than true');
+ }
+ }
} elseif ($type === self::ALIST) {
$keys = array_keys($var);
- if (array_keys($keys) !== $keys) $this->error('Indices for list are not uniform');
+ if (array_keys($keys) !== $keys) {
+ $this->error('Indices for list are not uniform');
+ }
}
return $var;
case (self::MIXED):
@@ -107,17 +128,24 @@ class HTMLPurifier_VarParser
}
/**
- * Actually implements the parsing. Base implementation is to not
+ * Actually implements the parsing. Base implementation does not
* do anything to $var. Subclasses should overload this!
+ * @param mixed $var
+ * @param int $type
+ * @param bool $allow_null
+ * @return string
*/
- protected function parseImplementation($var, $type, $allow_null) {
+ protected function parseImplementation($var, $type, $allow_null)
+ {
return $var;
}
/**
* Throws an exception.
+ * @throws HTMLPurifier_VarParserException
*/
- protected function error($msg) {
+ protected function error($msg)
+ {
throw new HTMLPurifier_VarParserException($msg);
}
@@ -126,29 +154,45 @@ class HTMLPurifier_VarParser
* @note This should not ever be called. It would be called if we
* extend the allowed values of HTMLPurifier_VarParser without
* updating subclasses.
+ * @param string $class
+ * @param int $type
+ * @throws HTMLPurifier_Exception
*/
- protected function errorInconsistent($class, $type) {
- throw new HTMLPurifier_Exception("Inconsistency in $class: ".HTMLPurifier_VarParser::getTypeName($type)." not implemented");
+ protected function errorInconsistent($class, $type)
+ {
+ throw new HTMLPurifier_Exception(
+ "Inconsistency in $class: " . HTMLPurifier_VarParser::getTypeName($type) .
+ " not implemented"
+ );
}
/**
* Generic error for if a type didn't work.
+ * @param mixed $var
+ * @param int $type
*/
- protected function errorGeneric($var, $type) {
+ protected function errorGeneric($var, $type)
+ {
$vtype = gettype($var);
- $this->error("Expected type ".HTMLPurifier_VarParser::getTypeName($type).", got $vtype");
+ $this->error("Expected type " . HTMLPurifier_VarParser::getTypeName($type) . ", got $vtype");
}
- static public function getTypeName($type) {
+ /**
+ * @param int $type
+ * @return string
+ */
+ public static function getTypeName($type)
+ {
static $lookup;
if (!$lookup) {
// Lazy load the alternative lookup table
$lookup = array_flip(HTMLPurifier_VarParser::$types);
}
- if (!isset($lookup[$type])) return 'unknown';
+ if (!isset($lookup[$type])) {
+ return 'unknown';
+ }
return $lookup[$type];
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/VarParser/Flexible.php b/library/HTMLPurifier/VarParser/Flexible.php
index c954250e9..b15016c5b 100644
--- a/library/HTMLPurifier/VarParser/Flexible.php
+++ b/library/HTMLPurifier/VarParser/Flexible.php
@@ -7,28 +7,41 @@
*/
class HTMLPurifier_VarParser_Flexible extends HTMLPurifier_VarParser
{
-
- protected function parseImplementation($var, $type, $allow_null) {
- if ($allow_null && $var === null) return null;
+ /**
+ * @param mixed $var
+ * @param int $type
+ * @param bool $allow_null
+ * @return array|bool|float|int|mixed|null|string
+ * @throws HTMLPurifier_VarParserException
+ */
+ protected function parseImplementation($var, $type, $allow_null)
+ {
+ if ($allow_null && $var === null) {
+ return null;
+ }
switch ($type) {
// Note: if code "breaks" from the switch, it triggers a generic
// exception to be thrown. Specific errors can be specifically
// done here.
- case self::MIXED :
- case self::ISTRING :
- case self::STRING :
- case self::TEXT :
- case self::ITEXT :
+ case self::MIXED:
+ case self::ISTRING:
+ case self::STRING:
+ case self::TEXT:
+ case self::ITEXT:
return $var;
- case self::INT :
- if (is_string($var) && ctype_digit($var)) $var = (int) $var;
+ case self::INT:
+ if (is_string($var) && ctype_digit($var)) {
+ $var = (int)$var;
+ }
return $var;
- case self::FLOAT :
- if ((is_string($var) && is_numeric($var)) || is_int($var)) $var = (float) $var;
+ case self::FLOAT:
+ if ((is_string($var) && is_numeric($var)) || is_int($var)) {
+ $var = (float)$var;
+ }
return $var;
- case self::BOOL :
+ case self::BOOL:
if (is_int($var) && ($var === 0 || $var === 1)) {
- $var = (bool) $var;
+ $var = (bool)$var;
} elseif (is_string($var)) {
if ($var == 'on' || $var == 'true' || $var == '1') {
$var = true;
@@ -39,48 +52,70 @@ class HTMLPurifier_VarParser_Flexible extends HTMLPurifier_VarParser
}
}
return $var;
- case self::ALIST :
- case self::HASH :
- case self::LOOKUP :
+ case self::ALIST:
+ case self::HASH:
+ case self::LOOKUP:
if (is_string($var)) {
// special case: technically, this is an array with
// a single empty string item, but having an empty
// array is more intuitive
- if ($var == '') return array();
+ if ($var == '') {
+ return array();
+ }
if (strpos($var, "\n") === false && strpos($var, "\r") === false) {
// simplistic string to array method that only works
// for simple lists of tag names or alphanumeric characters
- $var = explode(',',$var);
+ $var = explode(',', $var);
} else {
$var = preg_split('/(,|[\n\r]+)/', $var);
}
// remove spaces
- foreach ($var as $i => $j) $var[$i] = trim($j);
+ foreach ($var as $i => $j) {
+ $var[$i] = trim($j);
+ }
if ($type === self::HASH) {
// key:value,key2:value2
$nvar = array();
foreach ($var as $keypair) {
$c = explode(':', $keypair, 2);
- if (!isset($c[1])) continue;
- $nvar[$c[0]] = $c[1];
+ if (!isset($c[1])) {
+ continue;
+ }
+ $nvar[trim($c[0])] = trim($c[1]);
}
$var = $nvar;
}
}
- if (!is_array($var)) break;
+ if (!is_array($var)) {
+ break;
+ }
$keys = array_keys($var);
if ($keys === array_keys($keys)) {
- if ($type == self::ALIST) return $var;
- elseif ($type == self::LOOKUP) {
+ if ($type == self::ALIST) {
+ return $var;
+ } elseif ($type == self::LOOKUP) {
$new = array();
foreach ($var as $key) {
$new[$key] = true;
}
return $new;
- } else break;
+ } else {
+ break;
+ }
+ }
+ if ($type === self::ALIST) {
+ trigger_error("Array list did not have consecutive integer indexes", E_USER_WARNING);
+ return array_values($var);
}
if ($type === self::LOOKUP) {
foreach ($var as $key => $value) {
+ if ($value !== true) {
+ trigger_error(
+ "Lookup array has non-true value at key '$key'; " .
+ "maybe your input array was not indexed numerically",
+ E_USER_WARNING
+ );
+ }
$var[$key] = true;
}
}
@@ -90,7 +125,6 @@ class HTMLPurifier_VarParser_Flexible extends HTMLPurifier_VarParser
}
$this->errorGeneric($var, $type);
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/VarParser/Native.php b/library/HTMLPurifier/VarParser/Native.php
index b02a6de54..f11c318ef 100644
--- a/library/HTMLPurifier/VarParser/Native.php
+++ b/library/HTMLPurifier/VarParser/Native.php
@@ -8,11 +8,24 @@
class HTMLPurifier_VarParser_Native extends HTMLPurifier_VarParser
{
- protected function parseImplementation($var, $type, $allow_null) {
+ /**
+ * @param mixed $var
+ * @param int $type
+ * @param bool $allow_null
+ * @return null|string
+ */
+ protected function parseImplementation($var, $type, $allow_null)
+ {
return $this->evalExpression($var);
}
- protected function evalExpression($expr) {
+ /**
+ * @param string $expr
+ * @return mixed
+ * @throws HTMLPurifier_VarParserException
+ */
+ protected function evalExpression($expr)
+ {
$var = null;
$result = eval("\$var = $expr;");
if ($result === false) {
@@ -20,7 +33,6 @@ class HTMLPurifier_VarParser_Native extends HTMLPurifier_VarParser
}
return $var;
}
-
}
// vim: et sw=4 sts=4
diff --git a/library/HTMLPurifier/Zipper.php b/library/HTMLPurifier/Zipper.php
new file mode 100644
index 000000000..6e21ea070
--- /dev/null
+++ b/library/HTMLPurifier/Zipper.php
@@ -0,0 +1,157 @@
+<?php
+
+/**
+ * A zipper is a purely-functional data structure which contains
+ * a focus that can be efficiently manipulated. It is known as
+ * a "one-hole context". This mutable variant implements a zipper
+ * for a list as a pair of two arrays, laid out as follows:
+ *
+ * Base list: 1 2 3 4 [ ] 6 7 8 9
+ * Front list: 1 2 3 4
+ * Back list: 9 8 7 6
+ *
+ * User is expected to keep track of the "current element" and properly
+ * fill it back in as necessary. (ToDo: Maybe it's more user friendly
+ * to implicitly track the current element?)
+ *
+ * Nota bene: the current class gets confused if you try to store NULLs
+ * in the list.
+ */
+
+class HTMLPurifier_Zipper
+{
+ public $front, $back;
+
+ public function __construct($front, $back) {
+ $this->front = $front;
+ $this->back = $back;
+ }
+
+ /**
+ * Creates a zipper from an array, with a hole in the
+ * 0-index position.
+ * @param Array to zipper-ify.
+ * @return Tuple of zipper and element of first position.
+ */
+ static public function fromArray($array) {
+ $z = new self(array(), array_reverse($array));
+ $t = $z->delete(); // delete the "dummy hole"
+ return array($z, $t);
+ }
+
+ /**
+ * Convert zipper back into a normal array, optionally filling in
+ * the hole with a value. (Usually you should supply a $t, unless you
+ * are at the end of the array.)
+ */
+ public function toArray($t = NULL) {
+ $a = $this->front;
+ if ($t !== NULL) $a[] = $t;
+ for ($i = count($this->back)-1; $i >= 0; $i--) {
+ $a[] = $this->back[$i];
+ }
+ return $a;
+ }
+
+ /**
+ * Move hole to the next element.
+ * @param $t Element to fill hole with
+ * @return Original contents of new hole.
+ */
+ public function next($t) {
+ if ($t !== NULL) array_push($this->front, $t);
+ return empty($this->back) ? NULL : array_pop($this->back);
+ }
+
+ /**
+ * Iterated hole advancement.
+ * @param $t Element to fill hole with
+ * @param $i How many forward to advance hole
+ * @return Original contents of new hole, i away
+ */
+ public function advance($t, $n) {
+ for ($i = 0; $i < $n; $i++) {
+ $t = $this->next($t);
+ }
+ return $t;
+ }
+
+ /**
+ * Move hole to the previous element
+ * @param $t Element to fill hole with
+ * @return Original contents of new hole.
+ */
+ public function prev($t) {
+ if ($t !== NULL) array_push($this->back, $t);
+ return empty($this->front) ? NULL : array_pop($this->front);
+ }
+
+ /**
+ * Delete contents of current hole, shifting hole to
+ * next element.
+ * @return Original contents of new hole.
+ */
+ public function delete() {
+ return empty($this->back) ? NULL : array_pop($this->back);
+ }
+
+ /**
+ * Returns true if we are at the end of the list.
+ * @return bool
+ */
+ public function done() {
+ return empty($this->back);
+ }
+
+ /**
+ * Insert element before hole.
+ * @param Element to insert
+ */
+ public function insertBefore($t) {
+ if ($t !== NULL) array_push($this->front, $t);
+ }
+
+ /**
+ * Insert element after hole.
+ * @param Element to insert
+ */
+ public function insertAfter($t) {
+ if ($t !== NULL) array_push($this->back, $t);
+ }
+
+ /**
+ * Splice in multiple elements at hole. Functional specification
+ * in terms of array_splice:
+ *
+ * $arr1 = $arr;
+ * $old1 = array_splice($arr1, $i, $delete, $replacement);
+ *
+ * list($z, $t) = HTMLPurifier_Zipper::fromArray($arr);
+ * $t = $z->advance($t, $i);
+ * list($old2, $t) = $z->splice($t, $delete, $replacement);
+ * $arr2 = $z->toArray($t);
+ *
+ * assert($old1 === $old2);
+ * assert($arr1 === $arr2);
+ *
+ * NB: the absolute index location after this operation is
+ * *unchanged!*
+ *
+ * @param Current contents of hole.
+ */
+ public function splice($t, $delete, $replacement) {
+ // delete
+ $old = array();
+ $r = $t;
+ for ($i = $delete; $i > 0; $i--) {
+ $old[] = $r;
+ $r = $this->delete();
+ }
+ // insert
+ for ($i = count($replacement)-1; $i >= 0; $i--) {
+ $this->insertAfter($r);
+ $r = $replacement[$i];
+ }
+ return array($old, $r);
+ }
+}
diff --git a/library/jquery.AreYouSure/.gitignore b/library/jquery.AreYouSure/.gitignore
new file mode 100644
index 000000000..345f0dbeb
--- /dev/null
+++ b/library/jquery.AreYouSure/.gitignore
@@ -0,0 +1,166 @@
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Rr]elease/
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.vspscc
+.builds
+*.dotCover
+
+## TODO: If you have NuGet Package Restore enabled, uncomment this
+#packages/
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Others
+[Bb]in
+[Oo]bj
+sql
+TestResults
+*.Cache
+ClientBin
+stylecop.*
+~$*
+*.dbmdl
+Generated_Code #added for RIA/Silverlight projects
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+
+
+
+############
+## Windows
+############
+
+# Windows image file caches
+Thumbs.db
+
+# Folder config file
+Desktop.ini
+
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
+
+# Mac crap
+.DS_Store
+
+bower_components/
+node_modules/
diff --git a/library/jquery.AreYouSure/Gruntfile.js b/library/jquery.AreYouSure/Gruntfile.js
new file mode 100644
index 000000000..efca34c0a
--- /dev/null
+++ b/library/jquery.AreYouSure/Gruntfile.js
@@ -0,0 +1,26 @@
+module.exports = function(grunt) {
+ grunt.config.init({
+ karma: {
+ options: {
+ browsers: [ 'Chrome', 'Firefox', 'Safari', 'IE' ],
+ frameworks: [ 'jasmine' ],
+ reportSlowerThan: 500,
+ singleRun: true
+ },
+ unit: {
+ files: [
+ { pattern: 'bower_components/jquery/dist/jquery.min.js' },
+ { pattern: 'bower_components/jasmine-jquery/lib/jasmine-jquery.js' },
+ { pattern: 'jquery.are-you-sure.js' },
+ { pattern: 'spec/javascripts/*.js' },
+ { pattern: 'spec/javascripts/fixtures/**/*.html', included: false }
+ ]
+ }
+ }
+ });
+
+ grunt.registerTask('test', 'Run tests.', [ 'karma' ]);
+ grunt.registerTask('default', [ 'test' ]);
+
+ grunt.loadNpmTasks('grunt-karma');
+};
diff --git a/library/jquery.AreYouSure/README.md b/library/jquery.AreYouSure/README.md
new file mode 100644
index 000000000..6a538648a
--- /dev/null
+++ b/library/jquery.AreYouSure/README.md
@@ -0,0 +1,297 @@
+Are You Sure? - A light "dirty forms" JQuery Plugin
+======
+**Version:** 1.9
+
+*Are-you-sure* (```jquery.are-you-sure.js```) is simple light-weight "dirty
+form" JQuery Plugin for modern browsers. It helps prevent users from losing
+unsaved HTML Form changes by promoting the user to save/submit.
+
+It's simple to use. Just add the following line to your page's ready
+function:
+
+```javascript
+$('form').areYouSure();
+```
+
+*Are-you-sure* is a minimal plugin for modern browsers. There are plenty of
+"dirty forms" implementations out there, however they all seemed very
+heavyweight and over-engineered...! Most were written some time back and
+contain many 'hacks' to support legacy browsers, and/or rely on other fat
+dependencies such as FaceBox or jQueryUI. *Are-you-sure* solves this by
+doing this simple task in the simplest possible way.
+
+*Are-you-sure* is as simple as it gets:
+
+ * 100% JS with zero dependencies and no external CSS.
+ * Leverages `onBeforeUnload` to detect all page/browser exit events.
+ * Works on forms of any size.
+ * Correct state management - if a user edits then restores a value, the form
+ is not considered dirty.
+ * Easy to understand - less than a "terminal screen" of code!
+ * Graceful degradation on legacy browsers (i.e. if you're running an old
+ browser... remember to save :-)
+
+###Basic Usage
+
+```javascript
+
+$(function() {
+
+ // Enable on all forms
+ $('form').areYouSure();
+
+ // Enable on selected forms
+ $('form.dirty-check').areYouSure();
+
+ // With a custom message
+ $('form').areYouSure( {'message':'Your profile details are not saved!'} );
+
+}
+```
+To ignore selected fields from the dirtyness check:
+
+```html
+ <form id="myForm" name="myform" action="/post" method="post">
+
+ Field 1: (checked) <input type="text" name="field1"> <br />
+ Field 2: (ignored): <input type="text" name="field2" data-ays-ignore="true"> <br />
+ Field 3: (ignored): <input type="text" name="field3" class="ays-ignore"> <br />
+
+ <input type="submit" value="Submit">
+
+ </form>
+```
+
+###Advanced Usage
+
+```javascript
+
+$(function() {
+
+ /*
+ * Make Are-You-Sure "silent" by disabling the warning message
+ * (tracking/monitoring only mode). This option is useful when you wish to
+ * use the dirty/save events and/or use the dirtyness tracking in your own
+ * beforeunload handler.
+ */
+ $('form').areYouSure( {'silent':true} );
+
+ /*
+ * Dirtyness Change Events
+ * Are-You-Sure fires off "dirty" and "clean" events when the form's state
+ * changes. You can bind() or on(), these events to implement your own form
+ * state logic. A good example is enabling/disabling a Save button.
+ *
+ * "this" refers to the form that fired the event.
+ */
+ $('form').on('dirty.areYouSure', function() {
+ // Enable save button only as the form is dirty.
+ $(this).find('input[type="submit"]').removeAttr('disabled');
+ });
+ $('form').on('clean.areYouSure', function() {
+ // Form is clean so nothing to save - disable the save button.
+ $(this).find('input[type="submit"]').attr('disabled', 'disabled');
+ });
+
+ /*
+ * It's easy to test if a form is dirty in your own code - just check
+ * to see if it has a "dirty" CSS class.
+ */
+ if ($('#my-form').hasClass('dirty')) {
+ // Do something
+ }
+
+ /*
+ * If you're dynamically adding new fields/inputs, and would like to track
+ * their state, trigger Are-You-Sure to rescan the form like this:
+ */
+ $('#my-form').trigger('rescan.areYouSure');
+
+ /*
+ * If you'd like to reset/reinitialize the form's state as clean and
+ * start tracking again from this new point onwards, trigger the
+ * reinitalize as follows. This is handy if say you've managing your
+ * own form save/submit via asyc AJAX.
+ */
+ $('#my-form').trigger('reinitialize.areYouSure');
+
+ /*
+ * In some situations it may be desirable to look for other form
+ * changes such as adding/removing fields. This is useful for forms that
+ * can change their field count, such as address/phone contact forms.
+ * Form example, you might remove a phone number from a contact form
+ * but update nothing else. This should mark the form as dirty.
+ */
+ $('form').areYouSure( {'addRemoveFieldsMarksDirty':true} );
+
+ /*
+ * Sometimes you may have advanced forms that change their state via
+ * custom JavaScript or 3rd-party component JavaScript. Are-You-Sure may
+ * not automatically detect these state changes. Examples include:
+ * - Updating a hidden input field via background JS.
+ * - Using a [rich WYSIWYG edit control](https://github.com/codedance/jquery.AreYouSure/issues/17).
+ * One solution is to manually trigger a form check as follows:
+ */
+ $('#my-form').trigger('checkform.areYouSure');
+
+ /*
+ * As an alternative to using events, you can pass in a custom change
+ * function.
+ */
+ $('#my-adv-form').areYouSure({
+ change: function() {
+ // Enable save button only if the form is dirty. i.e. something to save.
+ if ($(this).hasClass('dirty')) {
+ $(this).find('input[type="submit"]').removeAttr('disabled');
+ } else {
+ $(this).find('input[type="submit"]').attr('disabled', 'disabled');
+ }
+ }
+ });
+
+ /*
+ * Mixing in your own logic into the warning.
+ */
+ $('#my-form').areYouSure( {'silent':true} );
+ $(window).on('beforeunload', function() {
+ isSunday = (0 == (new Date()).getDay());
+ if ($('#my-form').hasClass('dirty') && isSunday) {
+ return "Because it's Sunday, I'll be nice and let you know you forgot to save!";
+ }
+ }
+
+}
+```
+The [demo page](http://www.papercut.com/products/free_software/are-you-sure/demo/are-you-sure-demo.html)
+shows the advanced usage options in more detail.
+
+
+###Install
+Are-You-Sure is a light-weight jQuery plugin - it's a single standalone
+JavaScript file. You can download the
+[jquery.are-you-sure.js](https://raw.github.com/codedance/jquery.AreYouSure/master/jquery.are-you-sure.js)
+file and include it in your page. Because it's so simple it seems a shame
+to add an extra browser round trip. It's recommended that you consider
+concatenating it with other common JS lib files, and/or even cut-n-pasting
+the code (and license header) into one of your existing JS files.
+
+For experimental Mobile Safari support, also include ```ays-beforeunload-shim.js```
+(see Known Issues below).
+
+*Are-you-sure* may also be installed with [Bower](http://twitter.github.com/bower/):
+
+```bash
+$ bower install jquery.are-you-sure
+```
+
+If you're using, or like, *Are-you-sure* make sure you **star/watch** this project
+so you can stay up-to-date with updates.
+
+###Demo
+This [demo page](http://www.papercut.com/products/free_software/are-you-sure/demo/are-you-sure-demo.html)
+hosts a number of example forms.
+
+###Supported Browsers
+*Are-you-sure* has been tested on and fully supports the following browsers:
+
+* IE 9 through 11
+* Google Chrome (versions since 2012)
+* Firefox (versions since 2012)
+* Safari (versions since 2012)
+
+Experimental support is available on iOS and Opera via the *beforeunload* shim (see below).
+
+###Known Issues & Limitations
+
+####Mobile Safari and Opera
+The ```windows.beforeunload``` event is not supported on iOS (iPhone, iPad, and iPod). An
+experimental shim offering partial *beforeunload* emulation is provided to help plug this gap.
+It works by scanning the page for anchor links and augments the default behaviour to first
+check with *Are-you-sure* before navigating away. To use, simply include
+```ays-beforeunload-shim.js``` in your page.
+
+####Firefox
+The custom message option may not work on Firefox ([Firefox bug 588292](https://bugzilla.mozilla.org/show_bug.cgi?id=588292)).
+
+###Development
+The aim is to keep *Are-you-sure* simple and light. If you think you have
+a good idea which is aligned with this objective, please voice your thoughts
+in the issues list.
+
+####Pull Requests
+If possible, please submit your pull request against the most recent ```dev-*``` branch rather than master. This will make it easier to merge your code into the next planned release.
+
+####Running tests
+```bash
+$ npm install
+$ npm test
+```
+
+###Release History
+
+**2014-08-13** (1.9) - This is a minor bugfix release:
+
+* Addressed issue [#45](https://github.com/codedance/jquery.AreYouSure/issues/55) seen with empty select fields.
+* Thanks [valgen](https://github.com/valgen) and [tus124](https://github.com/tus124) for the contribution.
+
+**2014-06-22** (1.8) - This is a minor bugfix release:
+
+* Fixed NPE that may occur when using a 'multiple' option field.
+* Minor timing tweak to help mitigate bypass issue raised in [#45](https://github.com/codedance/jquery.AreYouSure/issues/45)
+* Thanks [apassant](https://github.com/apassant) and [amatenkov](https://github.com/amatenkov) for the contribution.
+
+**2014-05-28** (1.7)
+
+* Fixed multiple warning dialogs that may appear on IE and recent versions of Chrome
+* Experimental support for iOS Mobile Safari (via a *beforeunload* shim)
+* Various minor fixes (e.g. support input fields with no type=)
+* Minor performance improvements on pages with multiple forms
+* Improved documentation and examples
+* Thanks to [lfjeff](https://github.com/lfjeff) and [aqlong](https://github.com/aqlong) for the contribution and ideas!
+
+**2014-02-07** (1.6)
+
+* Add field count tracking (```addRemoveFieldsMarksDirty```) (contrib *jonegerton*)
+* Added event to manually trigger a form check/recheck (contrib *jonegerton*)
+* Thanks to [jonegerton](https://github.com/jonegerton) for the contribution!
+
+**2013-11-15** (1.5)
+
+* Added support for HTML5 input field types. (contrib *albinsunnanbo*)
+* New option to reinitialize/reset the dirty state. This is handy if you're managing your own async submit/save using AJAX. (contrib *albinsunnanbo*)
+* Thanks to [albinsunnanbo](https://github.com/albinsunnanbo) for the contribution!
+
+**2013-10-2** (1.4)
+
+* Added dirty and clean "events"
+* Added an option to disable the message (dirty tracking only)
+* Added an option to rescan a form to look/detect any new fields
+
+**2013-07-24** - Minor fix - don't fail if form elements have no "name" attribute.
+
+**2013-05-14** - Added support for form reset buttons (contributed by codev).
+
+**2013-05-01** - Added support for hidden and disabled form fields.
+
+**2013-02-03** - Add demo page.
+
+**2013-01-28** - Add ```change``` event support and a demo page.
+
+**2012-10-26** - Use dashes in class names rather than camel case.
+
+**2012-10-24** - Initial public release.
+
+
+###Prerequisites
+jQuery version 1.4.2 or higher. 2.0+ or 1.10+ recommended.
+
+
+###License
+The same as JQuery...
+
+ jQuery Plugin: Are-You-Sure (Dirty Form Detection)
+ https://github.com/codedance/jquery.AreYouSure/
+
+ Copyright (c) 2012-2014, Chris Dance - PaperCut Software http://www.papercut.com/
+ Dual licensed under the MIT or GPL Version 2 licenses.
+ http://jquery.org/license
diff --git a/library/jquery.AreYouSure/are-you-sure.jquery.json b/library/jquery.AreYouSure/are-you-sure.jquery.json
new file mode 100644
index 000000000..9c699b72b
--- /dev/null
+++ b/library/jquery.AreYouSure/are-you-sure.jquery.json
@@ -0,0 +1,39 @@
+{
+ "name": "are-you-sure",
+ "title": "Are You Sure? - a dirty forms check plugin",
+ "description": "Are-you-sure is simple light-weight dirty forms JQuery Plugin for modern browsers. It helps prevent users from loosing unsaved form changes by prompting the user to save/submit. It's dependency free and designed for modern browsers... just the features you need and nothing more! See the project page and demo for usage and examples.",
+ "keywords": [
+ "form",
+ "dirty",
+ "field",
+ "change",
+ "save",
+ "save-check",
+ "save-warning"
+ ],
+ "version": "1.9.0",
+ "author": {
+ "name": "Chris Dance (codedance) at PaperCut Software",
+ "url": "https://github.com/codedance"
+ },
+ "maintainers": [
+ {
+ "name": "Chris Dance",
+ "email": "chris.dance@papercut.com",
+ "url": "http://www.papercut.com/"
+ }
+ ],
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/codedance/jquery.AreYouSure/blob/master/README.md"
+ }
+ ],
+ "bugs": "https://github.com/codedance/jquery.AreYouSure/issues",
+ "homepage": "https://github.com/codedance/jquery.AreYouSure",
+ "docs": "https://github.com/codedance/jquery.AreYouSure",
+ "demo": "http://www.papercut.com/products/free_software/are-you-sure/demo/are-you-sure-demo.html",
+ "dependencies": {
+ "jquery": ">=1.4.2"
+ }
+}
diff --git a/library/jquery.AreYouSure/ays-beforeunload-shim.js b/library/jquery.AreYouSure/ays-beforeunload-shim.js
new file mode 100644
index 000000000..cb864cdeb
--- /dev/null
+++ b/library/jquery.AreYouSure/ays-beforeunload-shim.js
@@ -0,0 +1,31 @@
+/*!
+ * An experimental shim to partially emulate onBeforeUnload on iOS.
+ * Part of https://github.com/codedance/jquery.AreYouSure/
+ *
+ * Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Author: chris.dance@papercut.com
+ * Date: 19th May 2014
+ */
+$(function() {
+ if (!navigator.userAgent.toLowerCase().match(/iphone|ipad|ipod|opera/)) {
+ return;
+ }
+ $('a').bind('click', function(evt) {
+ var href = $(evt.target).closest('a').attr('href');
+ if (href !== undefined && !(href.match(/^#/) || href.trim() == '')) {
+ var response = $(window).triggerHandler('beforeunload', response);
+ if (response && response != "") {
+ var msg = response + "\n\n"
+ + "Press OK to leave this page or Cancel to stay.";
+ if (!confirm(msg)) {
+ return false;
+ }
+ }
+ window.location.href = href;
+ return false;
+ }
+ });
+});
diff --git a/library/jquery.AreYouSure/bower.json b/library/jquery.AreYouSure/bower.json
new file mode 100644
index 000000000..8591dc0d0
--- /dev/null
+++ b/library/jquery.AreYouSure/bower.json
@@ -0,0 +1,30 @@
+{
+ "name": "jquery.are-you-sure",
+ "version": "1.9.0",
+ "homepage": "https://github.com/codedance/jquery.AreYouSure",
+ "authors": [
+ "CodeDance <chris.dance@papercut.com>"
+ ],
+ "description": "A light-weight jQuery 'dirty forms' Plugin - it monitors html forms and alerts users to unsaved changes if they attempt to close the browser or navigate away from the page. (Are you sure?)",
+ "main": "jquery.are-you-sure.js",
+ "keywords": [
+ "form",
+ "dirty",
+ "field",
+ "change",
+ "save-check",
+ "are-you-sure",
+ "save-warning"
+ ],
+ "license": "MIT/GPLv2",
+ "ignore": [
+ "**/.*",
+ "demo"
+ ],
+ "dependencies": {
+ "jquery": ">=1.4.2"
+ },
+ "devDependencies": {
+ "jasmine-jquery": "~2.0.3"
+ }
+}
diff --git a/library/jquery.AreYouSure/demo/are-you-sure-demo.html b/library/jquery.AreYouSure/demo/are-you-sure-demo.html
new file mode 100644
index 000000000..3f0327b2e
--- /dev/null
+++ b/library/jquery.AreYouSure/demo/are-you-sure-demo.html
@@ -0,0 +1,576 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Demo: Are You Sure? - a dirty forms jQuery Plugin</title>
+
+ <!--
+
+ We'll use an old version of jQuery to show we're backwards compatible. In
+ production we recommend using a later version. e.g.
+
+ <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
+ <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
+
+ -->
+
+ <script src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
+ <script src="../jquery.are-you-sure.js"></script>
+ <script src="../ays-beforeunload-shim.js"></script>
+ <script>
+
+ $(function() {
+
+ // Example 1 - ... in one line of code
+ $('#example-1-form').areYouSure();
+
+
+ // Example 2 - ignore a dynamic field
+ $('#example-2-form').areYouSure();
+
+ var defaultPickup15min = new Date((new Date()).getTime() + 15 * 60000);
+ $('#pickup').val(defaultPickup15min.getHours()
+ + ':' + defaultPickup15min.getMinutes());
+
+
+ // Example 3 - custom message and hooking the dirty change events
+ $('#example-3-form').areYouSure(
+ {
+ message: "Did you forget to save your standard coffee order?"
+ }
+ );
+ // Enable save button only if the form is dirty - using events.
+ $('#example-3-form').bind('dirty.areYouSure', function() {
+ $(this).find('input[type="submit"]').removeAttr('disabled');
+ });
+ $('#example-3-form').bind('clean.areYouSure', function() {
+ $(this).find('input[type="submit"]').attr('disabled', 'disabled');
+ });
+
+
+ // Example 4 - dynamically change and add form fields.
+ $('#example-4-form').areYouSure(
+ {
+ message: "Did you forget to submit your coffee order?"
+ }
+ );
+
+ $('#example-4-lastorder').click(function() {
+ // ... set our saved coffee type.
+ $('#example-4-coffee').val('espresso');
+ // Because we've made a change from our own JavaScript, we need to fire
+ // off manual 'form check'.
+ $('#example-4-form').trigger('checkform.areYouSure');
+ });
+
+ // If it's warm enough, offer an iced coffee special.
+ $.getJSON("http://api.openweathermap.org/data/2.5/weather?q=Melbourne,AU&mode=json&units=metric&callback=?",
+ function(data) {
+ var temp = data.main.temp;
+ if (temp > 5) {
+ $('#example-4-special').append('<p>It\'s currently '
+ + temp + 'C in Melbourne. Ice it up!</p>');
+ $('#example-4-special').append('<input type="checkbox" name="make-it-iced" value="true" />'
+ + ' Make it an iced coffee<br />');
+
+ // Trigger rescan event on the form so we start tracking the new field.
+ $('#example-4-form').trigger('rescan.areYouSure');
+ }
+ }
+ );
+
+
+ /*
+ * Example 5
+ * - extra shots button to enable/disable shots options
+ * - like/unlike button (changing hidden form field value)
+ * - hook dirty change event to enable/disable submit (using method),
+ * to more easily demonstrate when the form is dirty
+ */
+ $('#example-5-extra-shots').click(function() {
+ // we trigger a change event on the fields so that the AreYouSure event handler is called
+ $('#example-5-form input[name=shots]').removeAttr('disabled').change();
+ $('#example-5-extra-shots').hide();
+ $('#example-5-shots-options').show();
+ return false;
+ });
+ $('#example-5-like-button').click(function() {
+ var currentLike = $('#example-5-like').val() == 'true';
+ var newLike = !currentLike;
+ // we trigger a change event on the fields so that the areYouSure event handler is called
+ $('#example-5-like').val(newLike).change();
+ $('#example-5-like-button').text(newLike ? 'Unlike' : 'Like');
+ return false;
+ });
+ $('#example-5-form').areYouSure({
+ change: function() {
+ // Enable save button only if the form is dirty.
+ if ($(this).hasClass('dirty')) {
+ $(this).find('input[type="submit"]').removeAttr('disabled');
+ } else {
+ $(this).find('input[type="submit"]').attr('disabled', 'disabled');
+ }
+ }
+ });
+
+ // Example 6 - HTML5 input types
+ $('#example-6-form').areYouSure();
+
+ // Example 7 - ... in one line of code for the form and some more optional to toggle disabled state of the save button
+ $('#example-7-form').areYouSure();
+ $('#example-7-save-button').click(function () {
+ $('#example-7-form').trigger('reinitialize.areYouSure');
+ });
+ // code below is optional to handle disabled state of the save button
+ $('#example-7-form').bind('dirty.areYouSure', function () {
+ // Enable save button only as the form is dirty.
+ $('#example-7-save-button').attr({ 'disabled': false });
+ });
+ $('#example-7-form').bind('clean.areYouSure', function () {
+ // Form is clean so nothing to save - disable the save button.
+ $('#example-7-save-button').attr({ 'disabled': true });
+ });
+ });
+
+ </script>
+
+ <style type="text/css">
+ body {
+ font-family: myriad-pro-1, myriad-pro-2, 'Lucida Grande', 'Arial', sans-serif;
+ margin: 25px;
+ }
+
+ form {
+ width: 350px;
+ border: 1px solid #AA5303;
+ padding: 10px 20px;
+ background-image: -webkit-linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5));
+ background-image: -moz-linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5));
+ background-image: -ms-linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5));
+ background-image: -o-linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5));
+ background-image: linear-gradient(top, rgba(170,83,3, 0.1), rgba(170,83,3, 0.5));
+ border-radius: 5px;
+ }
+
+ /* A bit of custom styling on example 3 */
+ #example-3-form.dirty, #example-4-form.dirty {
+ box-shadow: 0 0 8px rgba(255, 0, 0, 1);
+ -webkit-box-shadow: 0 0 8px rgba(255, 0, 0, 1);
+ -moz-box-shadow: 0 0 8px rgba(255, 0, 0, 1);
+ border:1px solid rgba(255,0,0, 0.8);
+ }
+
+ form h2 {
+ font-size: 22px;
+ }
+
+ form > div {
+ padding: 8px;
+ font-size: 12px;
+ }
+ form > div input[type="text"],
+ form > div input[type="color"],
+ form > div input[type="date"],
+ form > div input[type="datetime"],
+ form > div input[type="datetime-local"],
+ form > div input[type="email"],
+ form > div input[type="month"],
+ form > div input[type="number"],
+ form > div input[type="range"],
+ form > div input[type="search"],
+ form > div input[type="tel"],
+ form > div input[type="time"],
+ form > div input[type="url"],
+ form > div input[type="week"],
+ form > div input:not([type]),
+ form > div textarea,
+ form > div select,
+ form > div button {
+ float: right;
+ width: 200px;
+ }
+
+ form > div input[type="radio"],
+ form > div input[type="checkbox"] {
+ display: inline-block;
+ margin-left: 130px;
+ }
+
+ form > div input[type="submit"] {
+ float: right;
+ }
+ form > div.buttons {
+ clear: both;
+ padding-bottom: 20px;
+ }
+ </style>
+ </head>
+
+ <body>
+ <h1>jQuery Plugin Demo: Are You Sure?</h1>
+ <p>
+ This page hosts a demo of the <a href="https://github.com/codedance/jquery.AreYouSure">jQuery Are-You-Sure</a> plugin (<code>jquery.are-you-sure.js</code>).
+ </p>
+ <p>
+ <i>Are-you-sure</i> is simple light-weight "dirty forms" JQuery Plugin for modern browsers. It helps prevent users from loosing unsaved form changes.
+ </p>
+ <p>
+ <strong>Features:</strong>
+ <ul>
+ <li>Light weight - only the features you need!</li>
+ <li>Dependency free.</li>
+ <li>Correct state management - if a user edits then restores a value, the form is not considered dirty.</li>
+ <li>Easy to understand - less than a "terminal screen" of code!</li>
+ <li>... and <a href="https://github.com/codedance/jquery.AreYouSure">more</a>.</li>
+ </ul>
+ </p>
+
+ <h2>Example 1: It's simple!</h2>
+ <p>
+ This example shows how easy it is to add a dirty check to your form(s) with one line
+ of code. (View the page's source)
+ </p>
+
+ <form id="example-1-form" name="coffeeOrder1" method="post">
+ <h2>Enter Your Coffee Order</h2>
+ <div>
+ <label for="example-1-coffee">Coffee</label>
+ <select name="coffee" id="example-1-coffee">
+ <option value="espresso">Espresso</option>
+ <option value="dbl-espresso">Caffe Doppio</option>
+ <option value="latte">Caffe Latte</option>
+ <option value="macciato">Machhiato</option>
+ <option value="cappuccino">Cappuccino</option>
+ </select>
+ </div>
+ <div>
+ <label>Shots</label><br />
+ <input type="radio" name="shots" value="1" checked /> 1 Shot - Standard<br />
+ <input type="radio" name="shots" value="2" /> 2 Shots - Morning wakeup!<br />
+ <input type="radio" name="shots" value="3" /> 3 Shots - Overdrive!<br />
+ </div>
+ <div>
+ <label for="example-1-sugar">Sugar</label> <input type="text" name="sugar" value="0" id="example-1-sugar" />
+ </div>
+ <div>
+ <label for="example-1-instructions">Special Instructions</label>
+ <textarea name="instructions" rows="5" id="example-1-instructions"></textarea>
+ </div>
+
+ <div class="buttons">
+ <input type="checkbox" name="remember" value="true" /> Remember my order<br />
+ <input type="submit" value="Submit">
+ <input type="reset" value="Reset">
+ </div>
+ <div>
+ <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p>
+ </div>
+ </form>
+
+ <h2>Example 2: Ignore the unimportant!</h2>
+ <p>
+ This example highlights how to disregard a field from the dirty check. In this form
+ the first field is dynamically populated and hence a change on this field should <em>not</em>
+ mark the form as dirty.
+ </p>
+ <form id="example-2-form" name="coffeeOrder2" method="post">
+ <h2>Enter Your Coffee Order</h2>
+ <div>
+ <!-- The ays-ignore class means a change on this field is not considered "dirty" -->
+ <label for="pickup">Pickup Time</label>
+ <input class="ays-ignore" type="text" name="pickup" id="pickup" />
+ <!-- or you can use a data attribute like this:
+ <label for="pickup">Pickup Time</label> <input data-ays-ignore="true" type="text" name="pickup" id="pickup" />
+ -->
+ </div>
+ <div>
+ <label for="example-2-coffee">Coffee</label>
+ <select name="coffee" id="example-2-coffee">
+ <option value="espresso">Espresso</option>
+ <option value="dbl-espresso">Caffe Doppio</option>
+ <option value="latte">Caffe Latte</option>
+ <option value="macciato">Machhiato</option>
+ <option value="cappuccino">Cappuccino</option>
+ </select>
+ </div>
+ <div>
+ <label>Shots</label><br />
+ <input type="radio" name="shots" value="1" checked /> 1 Shot - Standard<br />
+ <input type="radio" name="shots" value="2" /> 2 Shots - Morning wakeup!<br />
+ <input type="radio" name="shots" value="3" /> 3 Shots - Overdrive!<br />
+ </div>
+ <div>
+ <label for="example-2-sugar">Sugar</label> <input type="text" name="sugar" value="0" id="example-2-sugar" />
+ </div>
+ <div>
+ <label for="example-2-instructions">Special Instructions</label>
+ <textarea name="instructions" rows="5" id="example-2-instructions"></textarea>
+ </div>
+
+ <div class="buttons">
+ <input type="checkbox" name="remember" value="true" /> Remember my order<br />
+ <input type="submit" value="Submit">
+ </div>
+ <div>
+ <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p>
+ </div>
+ </form>
+
+
+ <h2>Example 3: Lets be intelligent!</h2>
+ <p>
+ This is a more advanced example. The <code>dirty</code> and <code>clean</code> change events are
+ intercepted so the save button is only enabled if the form is dirty (i.e. something to save).
+ It also demonstrates how to customize the warning message and change the style of a dirty
+ form (CSS styling using the <code>.dirty</code> class).
+ </p>
+ <form id="example-3-form" name="coffeeOrder3" method="post">
+ <h2>Update My Standard Order</h2>
+ <div>
+ <label for="example-3-coffee">Coffee</label>
+ <select name="coffee" id="example-3-coffee">
+ <option value=""></option>
+ <option value="cappuccino">Cappuccino</option>
+ <option value="espresso">Espresso</option>
+ <option value="dbl-espresso">Caffe Doppio</option>
+ <option value="latte">Caffe Latte</option>
+ <option value="macciato">Machhiato</option>
+ </select>
+ </div>
+ <div>
+ <label>Shots</label><br />
+ <input type="radio" name="shots" value="1" /> 1 Shot - Standard<br />
+ <input type="radio" name="shots" value="2" checked /> 2 Shots - Morning wakeup!<br />
+ <input type="radio" name="shots" value="3" /> 3 Shots - Overdrive!<br />
+ </div>
+ <div>
+ <label for="example-3-sugar">Sugar</label>
+ <input type="text" name="sugar" value="1" id="example-3-sugar" />
+ </div>
+ <div>
+ <label for="example-3-instructions">Special Instructions</label>
+ <textarea name="instructions" rows="5" id="example-3-instructions">No chocolate please</textarea>
+ </div>
+
+ <div class="buttons">
+ <input type="submit" value="Save" disabled="disabled">
+ </div>
+ <div>
+ <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p>
+ </div>
+ </form>
+
+ <h2>Example 4: Lets be dynamic!</h2>
+ <p>
+ In this example we'll dymaically add a field and fire off the <code>rescan</code> event. After
+ the rescan, Are-You-Sure will start looking for changes on the new fields as well.
+ </p>
+ <form id="example-4-form" name="coffeeOrder4" method="post">
+ <h2>Order Coffee For Pickup Now</h2>
+ <div>
+ <a id="example-4-lastorder" href="javascript:void(0);">Set my preferences from my last order</a><br />
+ </div>
+ <div>
+ <label for="example-4-coffee">Coffee</label>
+ <select name="coffee" id="example-4-coffee">
+ <option value="cappuccino">Cappuccino</option>
+ <option value="espresso">Espresso</option>
+ <option value="dbl-espresso">Caffe Doppio</option>
+ <option value="latte">Caffe Latte</option>
+ </select>
+ </div>
+ <div id="example-4-special"></div>
+ <div class="buttons">
+ <input type="submit" value="Place Order">
+ </div>
+ <div>
+ <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p>
+ </div>
+ </form>
+
+ <h2>Example 5: Edge cases</h2>
+ <p>
+ This example demonstrates tracking of hidden and disabled form elements that are changed by non-input elements.
+ E.g.:
+ </p>
+ <ul>
+ <li>clicking a link or non-input button that changes the value of a hidden form field, or</li>
+ <li>
+ clicking a link or non-input button that enables or disables some form fields (which has an effect on whether
+ or not those fields will be submitted with the form, despite the values not changing).
+ </li>
+ </ul>
+ <form id="example-5-form" name="coffeeOrder5" method="post">
+ <h2>Update My Standard Order</h2>
+ <div>
+ <label for="example-5-coffee">Coffee</label>
+ <select name="coffee" id="example-3-coffee">
+ <option value="cappuccino">Cappuccino</option>
+ <option value="espresso">Espresso</option>
+ <option value="dbl-espresso">Caffe Doppio</option>
+ <option value="latte">Caffe Latte</option>
+ <option value="macciato">Machhiato</option>
+ </select>
+ </div>
+ <div>
+ <label>Shots</label>
+ <!--
+ The visually hidden "shots" radio buttons are disabled and would not normally be submitted with the form.
+ Clicking the following button will visually show and enable these buttons, resulting in a form state change
+ (and hence the form is considered dirty) without the values having changed.
+ -->
+ <button id="example-5-extra-shots">I want extra shots</button>
+ <div id="example-5-shots-options" style="display: none;">
+ <input type="radio" name="shots" value="1" disabled /> 1 Shot - Standard<br />
+ <input type="radio" name="shots" value="2" disabled /> 2 Shots - Morning wakeup!<br />
+ <input type="radio" name="shots" value="3" disabled /> 3 Shots - Overdrive!<br />
+ </div>
+ </div>
+ <div>
+ <label>Do you like us?</label>
+ <input type="hidden" name="like" value="false" id="example-5-like" />
+ <button id="example-5-like-button">Like</button>
+ </div>
+ <div class="buttons">
+ <input type="submit" value="Save" disabled="disabled">
+ </div>
+ <div>
+ <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p>
+ </div>
+ </form>
+
+ <h2>Example 6: HTML5 inputs!</h2>
+ <p>
+ This example shows support for HTML5 input types. It's not a coffee order form,
+ but you need coffee if you're working with HTML5 :-)
+ </p>
+
+ <form id="example-6-form" name="coffeeOrder6" method="post">
+ <h2>Doing HTML5? You'll need coffee!</h2>
+ <div>
+ <label for="example-6-color">color</label>
+ <input type="color" name="example-6-color" />
+ </div>
+ <div>
+ <label for="example-6-date">date</label>
+ <input type="date" name="example-6-date" />
+ </div>
+ <div>
+ <label for="example-6-datetime">datetime</label>
+ <input type="datetime" name="example-6-datetime" />
+ </div>
+ <div>
+ <label for="example-6-datetime-local">datetime-local</label>
+ <input type="datetime-local" name="example-6-datetime-local" />
+ </div>
+ <div>
+ <label for="example-6-email">email</label>
+ <input type="email" name="example-6-email" />
+ </div>
+ <div>
+ <label for="example-6-month">month</label>
+ <input type="month" name="example-6-month" />
+ </div>
+ <div>
+ <label for="example-6-number">number</label>
+ <input type="number" name="example-6-number" />
+ </div>
+ <div>
+ <label for="example-6-range">range</label>
+ <input type="range" name="example-6-range" />
+ </div>
+ <div>
+ <label for="example-6-search">search</label>
+ <input type="search" name="example-6-search" />
+ </div>
+ <div>
+ <label for="example-6-tel">tel</label>
+ <input type="tel" name="example-6-tel" />
+ </div>
+ <div>
+ <label for="example-6-time">time</label>
+ <input type="time" name="example-6-time" />
+ </div>
+ <div>
+ <label for="example-6-url">url</label>
+ <input type="url" name="example-6-url" />
+ </div>
+ <div>
+ <label for="example-6-week">week</label>
+ <input type="week" name="example-6-week" />
+ </div>
+ <div>
+ <label for="example-6-select">select/optgroup</label>
+ <select>
+ <optgroup label="Beans">
+ <option value="india">India</option>
+ <option value="indonesia" selected="selected">Indonesia</option>
+ <option value="brazil">Brazil</option>
+ </optgroup>
+ <optgroup label="Roast">
+ <option value="l">Light</option>
+ <option value="m">Medium</option>
+ <option value="h">Heavy</option>
+ </optgroup>
+ </select>
+ </div>
+ <div>
+ <label for="example-6-mselect">multi select</label>
+ <select multiple>
+ <option value="arabica">Arabica</option>
+ <option value="arabica">Peaberry</option>
+ <option value="malabar " selected="selected">Malabar</option>
+ <option value="robusta ">Robusta</option>
+ </select>
+ </div>
+ <div style="clear:both;"></div>
+ <div>
+ <label for="example-6-plain">plain old field</label>
+ <input name="example-6-plain" />
+ </div>
+
+ <div class="buttons">
+ <input type="submit" value="Submit">
+ <input type="reset" value="Reset">
+ </div>
+ <div>
+ <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p>
+ </div>
+ </form>
+ <h2>Example 7: Mark current state as not dirty!</h2>
+ <p>
+ This example shows how you can mark the current state as not dirty. Handy for AJAX forms
+ we're you're managing your own submits.
+ </p>
+
+ <form id="example-7-form" name="coffeeOrder7" method="post">
+ <h2>Tell us your default coffee</h2>
+ <div>
+ <label for="example-7-coffee">Default coffee</label>
+ <select name="coffee" id="example-7-coffee">
+ <option value="espresso">Espresso</option>
+ <option value="dbl-espresso">Caffe Doppio</option>
+ <option value="latte">Caffe Latte</option>
+ <option value="macciato">Machhiato</option>
+ <option value="cappuccino">Cappuccino</option>
+ </select>
+ </div>
+ <div>
+ <button id="example-7-save-button" disabled="disabled">Save without submit</button>
+ </div>
+ <div class="buttons">
+ <input type="submit" value="Submit">
+ </div>
+ <div>
+ <p>... or visit <a href="http://www.google.com/">Google</a> or close the window without saving!</p>
+ </div>
+ </form>
+
+ <p>
+ This jQuery plugin is developed by <a href="https://github.com/codedance">Chris Dance</a>
+ at <a href="http://www.papercut.com/">PaperCut Software</a> - Are-You-Sure is used in
+ PaperCut's printing management software and it has been open sourced with help of
+ Tom, Jack and Matt from PaperCut's dev team.
+ </p>
+
+ </body>
+</html>
diff --git a/library/jquery.AreYouSure/jquery.are-you-sure.js b/library/jquery.AreYouSure/jquery.are-you-sure.js
new file mode 100644
index 000000000..3c41e2fcc
--- /dev/null
+++ b/library/jquery.AreYouSure/jquery.are-you-sure.js
@@ -0,0 +1,192 @@
+/*!
+ * jQuery Plugin: Are-You-Sure (Dirty Form Detection)
+ * https://github.com/codedance/jquery.AreYouSure/
+ *
+ * Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Author: chris.dance@papercut.com
+ * Version: 1.9.0
+ * Date: 13th August 2014
+ */
+(function($) {
+
+ $.fn.areYouSure = function(options) {
+
+ var settings = $.extend(
+ {
+ 'message' : 'You have unsaved changes!',
+ 'dirtyClass' : 'dirty',
+ 'change' : null,
+ 'silent' : false,
+ 'addRemoveFieldsMarksDirty' : false,
+ 'fieldEvents' : 'change keyup propertychange input',
+ 'fieldSelector': ":input:not(input[type=submit]):not(input[type=button])"
+ }, options);
+
+ var getValue = function($field) {
+ if ($field.hasClass('ays-ignore')
+ || $field.hasClass('aysIgnore')
+ || $field.attr('data-ays-ignore')
+ || $field.attr('name') === undefined) {
+ return null;
+ }
+
+ if ($field.is(':disabled')) {
+ return 'ays-disabled';
+ }
+
+ var val;
+ var type = $field.attr('type');
+ if ($field.is('select')) {
+ type = 'select';
+ }
+
+ switch (type) {
+ case 'checkbox':
+ case 'radio':
+ val = $field.is(':checked');
+ break;
+ case 'select':
+ val = '';
+ $field.find('option').each(function(o) {
+ var $option = $(this);
+ if ($option.is(':selected')) {
+ val += $option.val();
+ }
+ });
+ break;
+ default:
+ val = $field.val();
+ }
+
+ return val;
+ };
+
+ var storeOrigValue = function($field) {
+ $field.data('ays-orig', getValue($field));
+ };
+
+ var checkForm = function(evt) {
+
+ var isFieldDirty = function($field) {
+ var origValue = $field.data('ays-orig');
+ if (undefined === origValue) {
+ return false;
+ }
+ return (getValue($field) != origValue);
+ };
+
+ var $form = ($(this).is('form'))
+ ? $(this)
+ : $(this).parents('form');
+
+ // Test on the target first as it's the most likely to be dirty
+ if (isFieldDirty($(evt.target))) {
+ setDirtyStatus($form, true);
+ return;
+ }
+
+ $fields = $form.find(settings.fieldSelector);
+
+ if (settings.addRemoveFieldsMarksDirty) {
+ // Check if field count has changed
+ var origCount = $form.data("ays-orig-field-count");
+ if (origCount != $fields.length) {
+ setDirtyStatus($form, true);
+ return;
+ }
+ }
+
+ // Brute force - check each field
+ var isDirty = false;
+ $fields.each(function() {
+ $field = $(this);
+ if (isFieldDirty($field)) {
+ isDirty = true;
+ return false; // break
+ }
+ });
+
+ setDirtyStatus($form, isDirty);
+ };
+
+ var initForm = function($form) {
+ var fields = $form.find(settings.fieldSelector);
+ $(fields).each(function() { storeOrigValue($(this)); });
+ $(fields).unbind(settings.fieldEvents, checkForm);
+ $(fields).bind(settings.fieldEvents, checkForm);
+ $form.data("ays-orig-field-count", $(fields).length);
+ setDirtyStatus($form, false);
+ };
+
+ var setDirtyStatus = function($form, isDirty) {
+ var changed = isDirty != $form.hasClass(settings.dirtyClass);
+ $form.toggleClass(settings.dirtyClass, isDirty);
+
+ // Fire change event if required
+ if (changed) {
+ if (settings.change) settings.change.call($form, $form);
+
+ if (isDirty) $form.trigger('dirty.areYouSure', [$form]);
+ if (!isDirty) $form.trigger('clean.areYouSure', [$form]);
+ $form.trigger('change.areYouSure', [$form]);
+ }
+ };
+
+ var rescan = function() {
+ var $form = $(this);
+ var fields = $form.find(settings.fieldSelector);
+ $(fields).each(function() {
+ var $field = $(this);
+ if (!$field.data('ays-orig')) {
+ storeOrigValue($field);
+ $field.bind(settings.fieldEvents, checkForm);
+ }
+ });
+ // Check for changes while we're here
+ $form.trigger('checkform.areYouSure');
+ };
+
+ var reinitialize = function() {
+ initForm($(this));
+ }
+
+ if (!settings.silent && !window.aysUnloadSet) {
+ window.aysUnloadSet = true;
+ $(window).bind('beforeunload', function() {
+ $dirtyForms = $("form").filter('.' + settings.dirtyClass);
+ if ($dirtyForms.length == 0) {
+ return;
+ }
+ // Prevent multiple prompts - seen on Chrome and IE
+ if (navigator.userAgent.toLowerCase().match(/msie|chrome/)) {
+ if (window.aysHasPrompted) {
+ return;
+ }
+ window.aysHasPrompted = true;
+ window.setTimeout(function() {window.aysHasPrompted = false;}, 900);
+ }
+ return settings.message;
+ });
+ }
+
+ return this.each(function(elem) {
+ if (!$(this).is('form')) {
+ return;
+ }
+ var $form = $(this);
+
+ $form.submit(function() {
+ $form.removeClass(settings.dirtyClass);
+ });
+ $form.bind('reset', function() { setDirtyStatus($form, false); });
+ // Add a custom events
+ $form.bind('rescan.areYouSure', rescan);
+ $form.bind('reinitialize.areYouSure', reinitialize);
+ $form.bind('checkform.areYouSure', checkForm);
+ initForm($form);
+ });
+ };
+})(jQuery);
diff --git a/library/jquery.AreYouSure/package.json b/library/jquery.AreYouSure/package.json
new file mode 100644
index 000000000..0b4c38dde
--- /dev/null
+++ b/library/jquery.AreYouSure/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "jquery.AreYouSure",
+ "description": "A light-weight jQuery \"dirty forms\" Plugin - it monitors HTML forms and alerts users to unsaved changes if they attempt to close the browser or navigate away from the page. (Are you sure?)",
+ "homepage": "https://github.com/codedance/jquery.AreYouSure",
+ "author": "Chris Dance <chris.dance@papercut.com> (https://github.com/codedance)",
+ "contributors": [
+ "Tom Clift <tom.clift@papercut.com> (https://github.com/tclift)",
+ "Jon Egerton <jon@ja2.co.uk> (http://www.jonegerton.com/)",
+ "Scadoodles (https://github.com/Scadoodles)",
+ "Albin Sunnanbo (https://github.com/albinsunnanbo)",
+ "Marc Sutton <ashre@iname.com> (http://www.codev.co.uk)"
+ ],
+ "version": "1.9.0",
+ "license": "MIT/GPLv2",
+ "keywords": [ "dirty", "form", "onbeforeunload", "save", "check" ],
+ "main": "jquery.are-you-sure.js",
+ "engines": {
+ "node": ">=0.8.0"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/codedance/jquery.AreYouSure"
+ },
+ "bugs": {
+ "url": "https://github.com/codedance/jquery.AreYouSure/issues"
+ },
+ "dependencies": {
+ "jquery": ">=1.4.2"
+ },
+ "devDependencies": {
+ "bower": "^1.3.1",
+ "grunt": "^0.4.5",
+ "grunt-cli": "^0.1.13",
+ "grunt-karma": "^0.8.3",
+ "karma-chrome-launcher": "^0.1.4",
+ "karma-jasmine": "^0.2.2",
+ "karma-ie-launcher": "^0.1.5",
+ "karma-firefox-launcher": "^0.1.3",
+ "karma-safari-launcher": "^0.1.1"
+ },
+ "scripts": {
+ "postinstall": "node_modules/.bin/bower install",
+ "test": "node_modules/.bin/grunt test"
+ }
+}
diff --git a/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html b/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html
new file mode 100644
index 000000000..1b2850759
--- /dev/null
+++ b/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html
@@ -0,0 +1,4 @@
+<form>
+ <input type="text" name="a">
+ <input type="submit">
+</form>
diff --git a/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js b/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js
new file mode 100644
index 000000000..5e02f7cb0
--- /dev/null
+++ b/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js
@@ -0,0 +1,28 @@
+'use strict';
+
+// Karma adds 'base/' to the default path
+jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures';
+
+describe("A form's", function() {
+ var $form = undefined;
+
+ describe('text input', function() {
+ var $textInput = undefined;
+
+ beforeEach(function() {
+ loadFixtures('input-text.html');
+ $form = $('form');
+ $textInput = $('input[type=text]');
+ $form.areYouSure();
+ });
+
+ it('should cause dirtyness after its value changes', function(done) {
+ expect($form.hasClass('dirty')).toBe(false);
+ $textInput.val('new').change();
+ setTimeout(function() {
+ expect($form.hasClass('dirty')).toBe(true);
+ done();
+ }, 0);
+ });
+ });
+});
diff --git a/mod/item.php b/mod/item.php
index f5a9a4b22..894e23a0f 100644
--- a/mod/item.php
+++ b/mod/item.php
@@ -470,11 +470,13 @@ function item_post(&$a) {
require_once('include/text.php');
if($uid && $uid == $profile_uid && feature_enabled($uid,'markdown')) {
- require_once('include/bb2diaspora.php');
- $body = diaspora2bb(escape_tags($body),true);
+ require_once('include/bb2diaspora.php');
+ $body = escape_tags($body);
+ $body = preg_replace_callback('/\[share(.*?)\]/ism','share_shield',$body);
+ $body = diaspora2bb($body,true);
+ $body = preg_replace_callback('/\[share(.*?)\]/ism','share_unshield',$body);
}
-
// BBCODE alert: the following functions assume bbcode input
// and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.)
// we may need virtual or template classes to implement the possible alternatives
diff --git a/mod/new_channel.php b/mod/new_channel.php
index 185fc7c28..047048f0a 100644
--- a/mod/new_channel.php
+++ b/mod/new_channel.php
@@ -115,11 +115,8 @@ function new_channel_content(&$a) {
'$nick_desc' => t('Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others.'),
'$label_import' => t('Or <a href="import">import an existing channel</a> from another location'),
'$name' => $name,
- '$label_role' => t('Channel Type'),
- '$questionmark' => t('?'),
- '$what_is_role' => t('What is this?'),
- '$help_role' => t('Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you'),
- '$role_select' => role_selector(($privacy_role) ? $privacy_role : 'social'),
+ '$help_role' => t('Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you'),
+ '$role' => array('permissions_role' , t('Channel Type'), ($privacy_role) ? $privacy_role : 'social', '<a href="help/roles" target="_blank">'.t('Read more about roles').'</a>',get_roles()),
'$nickname' => $nickname,
'$submit' => t('Create')
));
diff --git a/mod/profiles.php b/mod/profiles.php
index f2695f332..6bdc7f11a 100644
--- a/mod/profiles.php
+++ b/mod/profiles.php
@@ -596,13 +596,12 @@ function profiles_content(&$a) {
$opt_tpl = get_markup_template("profile_hide_friends.tpl");
- $hide_friends = replace_macros($opt_tpl,array(
- '$desc' => t('Hide your contact/friend list from viewers of this profile?'),
- '$yes_str' => t('Yes'),
- '$no_str' => t('No'),
- '$yes_selected' => (($r[0]['hide_friends']) ? " checked=\"checked\" " : ""),
- '$no_selected' => (($r[0]['hide_friends'] == 0) ? " checked=\"checked\" " : "")
- ));
+ $hide_friends = replace_macros($opt_tpl,array('$field' => array(
+ 'hide-friends',
+ t('Hide your contact/friend list from viewers of this profile?'),
+ $r[0]['hide_friends'],
+ '',
+ )));
$q = q("select * from profdef where true");
if($q) {
diff --git a/mod/settings.php b/mod/settings.php
index be6f2cfb9..59ce98a2a 100644
--- a/mod/settings.php
+++ b/mod/settings.php
@@ -122,10 +122,19 @@ function settings_post(&$a) {
if((argc() > 1) && (argv(1) === 'features')) {
check_form_security_token_redirectOnErr('/settings/features', 'settings_features');
- foreach($_POST as $k => $v) {
- if(strpos($k,'feature_') === 0) {
- set_pconfig(local_user(),'feature',substr($k,8),((intval($v)) ? 1 : 0));
- }
+
+ // Build list of features and check which are set
+ $features = get_features();
+ $all_features = array();
+ foreach($features as $k => $v) {
+ foreach($v as $f)
+ $all_features[] = $f[0];
+ }
+ foreach($all_features as $k) {
+ if(x($_POST,"feature_$k"))
+ set_pconfig(local_user(),'feature',$k, 1);
+ else
+ set_pconfig(local_user(),'feature',$k, 0);
}
build_sync_packet();
return;
@@ -707,7 +716,6 @@ function settings_content(&$a) {
'$title' => t('Additional Features'),
'$features' => $arr,
'$submit' => t('Submit'),
- '$field_yesno' => 'field_yesno.tpl',
));
return $o;
@@ -938,7 +946,7 @@ function settings_content(&$a) {
$timezone = date_default_timezone_get();
- $opt_tpl = get_markup_template("field_yesno.tpl");
+ $opt_tpl = get_markup_template("field_checkbox.tpl");
if(get_config('system','publish_all')) {
$profile_in_dir = '<input type="hidden" name="profile_in_directory" value="1" />';
}
@@ -1010,12 +1018,10 @@ function settings_content(&$a) {
'$uid' => local_user(),
'$form_security_token' => get_form_security_token("settings"),
'$nickname_block' => $prof_addr,
-
-
'$h_basic' => t('Basic Settings'),
'$username' => array('username', t('Full Name:'), $username,''),
'$email' => array('email', t('Email Address:'), $email, ''),
- '$timezone' => array('timezone_select' , t('Your Timezone:'), select_timezone($timezone), ''),
+ '$timezone' => array('timezone_select' , t('Your Timezone:'), $timezone, '', get_timezones()),
'$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')),
'$allowloc' => array('allow_location', t('Use Browser Location:'), ((get_pconfig(local_user(),'system','use_browser_location')) ? 1 : ''), ''),
@@ -1044,9 +1050,7 @@ function settings_content(&$a) {
'$aclselect' => populate_acl($perm_defaults,false),
'$suggestme' => $suggestme,
'$group_select' => $group_select,
- '$role_lbl' => t('Channel permissions category:'),
-
- '$role_select' => role_selector($permissions_role),
+ '$role' => array('permissions_role' , t('Channel permissions category:'), $permissions_role, '', get_roles()),
'$profile_in_dir' => $profile_in_dir,
'$hide_friends' => $hide_friends,
diff --git a/mod/setup.php b/mod/setup.php
index 044def15a..6f2c7c074 100755
--- a/mod/setup.php
+++ b/mod/setup.php
@@ -349,7 +349,7 @@ function setup_content(&$a) {
'$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Please use SSL (https) URL if available.')),
- '$timezone' => field_timezone('timezone', t('Please select a default timezone for your website'), $timezone, ''),
+ '$timezone' => array('timezone', t('Please select a default timezone for your website'), $timezone, '', get_timezones()),
'$baseurl' => $a->get_baseurl(),
diff --git a/view/css/bootstrap-red.css b/view/css/bootstrap-red.css
index 12287ba4f..5d9bb6e90 100644
--- a/view/css/bootstrap-red.css
+++ b/view/css/bootstrap-red.css
@@ -79,3 +79,7 @@ nav .navbar-toggle {
code {
white-space: normal;
}
+
+/* Bootstrap assumes that checkboxes are on the left of labels, while it's usually the opposite in Red */
+.field.checkbox input[type="checkbox"] { margin-left: 0px; }
+.field.checkbox label { padding-left: 0px; font-weight: 700}
diff --git a/view/css/mod_connect.css b/view/css/mod_connect.css
index d1a46ec48..218b1d2cb 100644
--- a/view/css/mod_connect.css
+++ b/view/css/mod_connect.css
@@ -6,6 +6,8 @@
margin-top: 25px;
}
-#sellpage-edit label{
+/* first-of-type needed to style switches */
+#sellpage-edit label.mainlabel,
+#sellpage-edit label:first-of-type {
width: 300px;
-} \ No newline at end of file
+}
diff --git a/view/css/mod_group.css b/view/css/mod_group.css
index cc5f15843..30a954d2a 100644
--- a/view/css/mod_group.css
+++ b/view/css/mod_group.css
@@ -3,7 +3,9 @@
margin-top: 30px;
}
-#group-edit-form label {
+/* first-of-type needed to style switches */
+#group-edit-form label.mainlabel,
+#group-edit-form label:first-of-type {
float: left;
width: 300px;
}
diff --git a/view/css/mod_settings.css b/view/css/mod_settings.css
index b03023e21..b066e6059 100644
--- a/view/css/mod_settings.css
+++ b/view/css/mod_settings.css
@@ -28,7 +28,9 @@ ul#settings-privacy-macros {
margin-bottom: 10px;
}
-#settings-permissions-wrapper .field label{
+/* first-of-type needed to be able to style switches */
+#settings-permissions-wrapper .field label.mainlabel,
+#settings-permissions-wrapper .field label:first-of-type {
width: 350px;
}
@@ -41,7 +43,9 @@ ul#settings-privacy-macros {
margin-bottom: 45px;
}
-#settings-notifications label {
+/* first-of-type needed to be able to style switches */
+#settings-notifications .field label.mainlabel,
+#settings-notifications .field label:first-of-type {
margin-left: 20px;
width: 330px;
}
@@ -63,4 +67,4 @@ ul#settings-privacy-macros {
#settings-channel-menu-end {
clear: both;
margin-bottom: 15px;
-} \ No newline at end of file
+}
diff --git a/view/css/mod_thing.css b/view/css/mod_thing.css
index 125230b38..ddb2faa87 100644
--- a/view/css/mod_thing.css
+++ b/view/css/mod_thing.css
@@ -4,8 +4,9 @@
margin-left: 0;
}
-
-.thing-label, .field label, .thing-verb-label, .thing-profile-label{
+/* first-of-type needed to style switches */
+.field label.mainlabel,
+.thing-label, .field label:first-of-type, .thing-verb-label, .thing-profile-label{
float: left;
width: 350px;
}
@@ -18,4 +19,4 @@
.thing-field-end {
clear: both;
-} \ No newline at end of file
+}
diff --git a/view/js/mod_admin.js b/view/js/mod_admin.js
new file mode 100644
index 000000000..aad2ca902
--- /dev/null
+++ b/view/js/mod_admin.js
@@ -0,0 +1,3 @@
+$(document).ready(function() {
+ $('form').areYouSure(); // Warn user about unsaved settings
+});
diff --git a/view/js/mod_new_channel.js b/view/js/mod_new_channel.js
index 492267ff9..c4d5408f2 100644
--- a/view/js/mod_new_channel.js
+++ b/view/js/mod_new_channel.js
@@ -1,5 +1,5 @@
$(document).ready(function() {
-// $("#privacy-role-select").sSelect();
+// $("#id_permissions_role").sSelect();
$("#newchannel-name").blur(function() {
$("#name-spinner").spin('small');
var zreg_name = $("#newchannel-name").val();
diff --git a/view/js/mod_profiles.js b/view/js/mod_profiles.js
new file mode 100644
index 000000000..aad2ca902
--- /dev/null
+++ b/view/js/mod_profiles.js
@@ -0,0 +1,3 @@
+$(document).ready(function() {
+ $('form').areYouSure(); // Warn user about unsaved settings
+});
diff --git a/view/js/mod_settings.js b/view/js/mod_settings.js
index 87c8c3a2b..0db0dd165 100644
--- a/view/js/mod_settings.js
+++ b/view/js/mod_settings.js
@@ -2,14 +2,15 @@
var ispublic = aStr['everybody'] ;
$(document).ready(function() {
+ $('form').areYouSure(); // Warn user about unsaved settings
$("a#settings-default-perms-menu").colorbox({
'inline' : true,
'transition' : 'elastic'
});
- $("#privacy-role-select").change(function() {
- var role = $("#privacy-role-select").val();
+ $("#id_permissions_role").change(function() {
+ var role = $("#id_permissions_role").val();
if(role == 'custom')
$('#advanced-perm').show();
else
diff --git a/view/php/theme_init.php b/view/php/theme_init.php
index f28f9aa8d..33b7e87dc 100644
--- a/view/php/theme_init.php
+++ b/view/php/theme_init.php
@@ -44,6 +44,7 @@ head_add_js('docready.js');
head_add_js('library/colorbox/jquery.colorbox-min.js');
head_add_js('library/bootstrap-tagsinput/bootstrap-tagsinput.js');
+head_add_js('library/jquery.AreYouSure/jquery.are-you-sure.js');
/**
* Those who require this feature will know what to do with it.
* Those who don't, won't.
diff --git a/view/sv/messages.po b/view/sv/messages.po
index 945ac691e..3cafa9809 100644
--- a/view/sv/messages.po
+++ b/view/sv/messages.po
@@ -9,8 +9,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Red Matrix\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-11-28 00:04-0800\n"
-"PO-Revision-Date: 2014-11-29 10:37+0000\n"
+"POT-Creation-Date: 2014-12-26 00:04-0800\n"
+"PO-Revision-Date: 2014-12-29 22:54+0000\n"
"Last-Translator: Erik Lundin <sby8zrm8v1@asdf.asdfasdf.eu>\n"
"Language-Team: Swedish (http://www.transifex.com/projects/p/red-matrix/language/sv/)\n"
"MIME-Version: 1.0\n"
@@ -25,597 +25,371 @@ msgid "Cannot locate DNS info for database server '%s'"
msgstr "Kan inte hitta DNS-information för databasserver '%s'"
#: ../../include/photo/photo_driver.php:680 ../../include/photos.php:52
+#: ../../mod/photos.php:91 ../../mod/photos.php:654
#: ../../mod/profile_photo.php:142 ../../mod/profile_photo.php:301
-#: ../../mod/profile_photo.php:423 ../../mod/photos.php:91
-#: ../../mod/photos.php:654
+#: ../../mod/profile_photo.php:423
msgid "Profile Photos"
msgstr "Profilfoton"
-#: ../../include/conversation.php:120 ../../include/text.php:1747
-#: ../../include/diaspora.php:1928 ../../mod/subthread.php:72
-#: ../../mod/subthread.php:174 ../../mod/like.php:290 ../../mod/tagger.php:45
-msgid "photo"
-msgstr "foto"
-
-#: ../../include/conversation.php:123 ../../include/text.php:1750
-#: ../../mod/tagger.php:49
-msgid "event"
-msgstr "händelse"
-
-#: ../../include/conversation.php:126 ../../mod/like.php:89
-msgid "channel"
-msgstr "kanal"
-
-#: ../../include/conversation.php:148 ../../include/text.php:1753
-#: ../../include/diaspora.php:1928 ../../mod/subthread.php:72
-#: ../../mod/subthread.php:174 ../../mod/like.php:290 ../../mod/tagger.php:53
-msgid "status"
-msgstr "status"
-
-#: ../../include/conversation.php:150 ../../include/text.php:1755
-#: ../../mod/tagger.php:55
-msgid "comment"
-msgstr "kommentar"
-
-#: ../../include/conversation.php:164 ../../include/diaspora.php:1957
-#: ../../mod/like.php:336
-#, php-format
-msgid "%1$s likes %2$s's %3$s"
-msgstr "%1$s gillar %2$ss %3$s"
-
-#: ../../include/conversation.php:167 ../../mod/like.php:338
-#, php-format
-msgid "%1$s doesn't like %2$s's %3$s"
-msgstr "%1$s gillar inte %2$ss %3$s"
-
-#: ../../include/conversation.php:204
-#, php-format
-msgid "%1$s is now connected with %2$s"
-msgstr "%1$s har nu kontakt med %2$s"
-
-#: ../../include/conversation.php:239
-#, php-format
-msgid "%1$s poked %2$s"
-msgstr "%1$s puffade %2$s"
-
-#: ../../include/conversation.php:243 ../../include/text.php:905
-msgid "poked"
-msgstr "puffade"
-
-#: ../../include/conversation.php:261 ../../mod/mood.php:63
-#, php-format
-msgctxt "mood"
-msgid "%1$s is %2$s"
-msgstr "%1$s är %2$s"
-
-#: ../../include/conversation.php:633 ../../include/ItemObject.php:126
-msgid "Select"
-msgstr "Välj"
-
-#: ../../include/conversation.php:634 ../../include/RedDAV/RedBrowser.php:251
-#: ../../include/apps.php:250 ../../include/ItemObject.php:120
-#: ../../mod/settings.php:626 ../../mod/connedit.php:476
-#: ../../mod/thing.php:234 ../../mod/group.php:176 ../../mod/admin.php:730
-#: ../../mod/admin.php:861 ../../mod/photos.php:1070
-msgid "Delete"
-msgstr "Ta bort"
-
-#: ../../include/conversation.php:641 ../../include/ItemObject.php:89
-msgid "Private Message"
-msgstr "Privat meddelande"
-
-#: ../../include/conversation.php:648 ../../include/ItemObject.php:194
-msgid "Message signature validated"
-msgstr "Meddelandesignatur bekräftad"
-
-#: ../../include/conversation.php:649 ../../include/ItemObject.php:195
-msgid "Message signature incorrect"
-msgstr "Meddelandesignatur felaktig"
+#: ../../include/items.php:382 ../../mod/group.php:68
+#: ../../mod/subthread.php:49 ../../mod/profperm.php:23 ../../mod/like.php:246
+#: ../../index.php:389
+msgid "Permission denied"
+msgstr "Behörighet saknas"
-#: ../../include/conversation.php:670
-#, php-format
-msgid "View %s's profile @ %s"
-msgstr "Visa %ss profil på %s"
+#: ../../include/items.php:969 ../../include/items.php:1014
+msgid "(Unknown)"
+msgstr "(Okänt)"
-#: ../../include/conversation.php:685
-msgid "Categories:"
-msgstr "Kategorier:"
+#: ../../include/items.php:1171
+msgid "Visible to anybody on the internet."
+msgstr "Kan ses av vem som helst på Internet."
-#: ../../include/conversation.php:686
-msgid "Filed under:"
-msgstr "Postat under:"
+#: ../../include/items.php:1173
+msgid "Visible to you only."
+msgstr "Kan bara ses av dig."
-#: ../../include/conversation.php:694 ../../include/ItemObject.php:266
-#, php-format
-msgid " from %s"
-msgstr "från %s"
+#: ../../include/items.php:1175
+msgid "Visible to anybody in this network."
+msgstr "Kan ses av alla på det här nätverket."
-#: ../../include/conversation.php:697 ../../include/ItemObject.php:269
-#, php-format
-msgid "last edited: %s"
-msgstr "senast redigerat: %s"
+#: ../../include/items.php:1177
+msgid "Visible to anybody authenticated."
+msgstr "Kan ses av alla inloggade."
-#: ../../include/conversation.php:698 ../../include/ItemObject.php:270
+#: ../../include/items.php:1179
#, php-format
-msgid "Expires: %s"
-msgstr "Upphör: %s"
-
-#: ../../include/conversation.php:713
-msgid "View in context"
-msgstr "Visa sammanhang"
-
-#: ../../include/conversation.php:715 ../../include/conversation.php:1137
-#: ../../include/ItemObject.php:317 ../../mod/editblock.php:152
-#: ../../mod/editlayout.php:148 ../../mod/editpost.php:121
-#: ../../mod/editwebpage.php:183 ../../mod/mail.php:238 ../../mod/mail.php:353
-#: ../../mod/photos.php:978
-msgid "Please wait"
-msgstr "Vänta"
-
-#: ../../include/conversation.php:831
-msgid "remove"
-msgstr "ta bort"
-
-#: ../../include/conversation.php:835 ../../include/nav.php:257
-msgid "Loading..."
-msgstr "Laddar..."
-
-#: ../../include/conversation.php:836
-msgid "Delete Selected Items"
-msgstr "Ta bort valda poster"
-
-#: ../../include/conversation.php:926
-msgid "View Source"
-msgstr "Visa källa"
-
-#: ../../include/conversation.php:927
-msgid "Follow Thread"
-msgstr "Följ tråd"
-
-#: ../../include/conversation.php:928
-msgid "View Status"
-msgstr "Visa status"
-
-#: ../../include/conversation.php:929 ../../include/nav.php:99
-#: ../../mod/connedit.php:429 ../../mod/connedit.php:544
-msgid "View Profile"
-msgstr "Visa profil"
-
-#: ../../include/conversation.php:930
-msgid "View Photos"
-msgstr "Visa foton"
-
-#: ../../include/conversation.php:931
-msgid "Matrix Activity"
-msgstr "Matrisaktivitet"
-
-#: ../../include/conversation.php:932 ../../include/identity.php:840
-#: ../../include/widgets.php:135 ../../include/widgets.php:175
-#: ../../include/Contact.php:107 ../../mod/suggest.php:51
-#: ../../mod/match.php:62 ../../mod/directory.php:235
-msgid "Connect"
-msgstr "Ta kontakt"
-
-#: ../../include/conversation.php:933
-msgid "Edit Contact"
-msgstr "Redigera kontakt"
-
-#: ../../include/conversation.php:934
-msgid "Send PM"
-msgstr "Skicka meddelande"
-
-#: ../../include/conversation.php:935 ../../include/apps.php:143
-msgid "Poke"
-msgstr "Puffa"
+msgid "Visible to anybody on %s."
+msgstr "Kan ses av alla på %s."
-#: ../../include/conversation.php:987 ../../include/RedDAV/RedBrowser.php:163
-#: ../../include/apps.php:331 ../../include/apps.php:382
-#: ../../mod/connedit.php:512 ../../mod/photos.php:713
-#: ../../mod/photos.php:1132
-msgid "Unknown"
-msgstr "Okända"
+#: ../../include/items.php:1181
+msgid "Visible to all connections."
+msgstr "Kan ses av alla kontakter."
-#: ../../include/conversation.php:1008
-#, php-format
-msgid "%s likes this."
-msgstr "%s gillar det här."
+#: ../../include/items.php:1183
+msgid "Visible to approved connections."
+msgstr "Kan ses av godkända kontakter."
-#: ../../include/conversation.php:1008
-#, php-format
-msgid "%s doesn't like this."
-msgstr "%s gillar inte det här."
+#: ../../include/items.php:1185
+msgid "Visible to specific connections."
+msgstr "Kan ses av valda kontakter."
-#: ../../include/conversation.php:1012
-#, php-format
-msgid "<span %1$s>%2$d people</span> like this."
-msgid_plural "<span %1$s>%2$d people</span> like this."
-msgstr[0] "<span %1$s>%2$d person</span> gillar det här."
-msgstr[1] "<span %1$s>%2$d personer</span> gillar det här."
+#: ../../include/items.php:3952 ../../mod/display.php:32
+#: ../../mod/thing.php:76 ../../mod/filestorage.php:26 ../../mod/admin.php:168
+#: ../../mod/admin.php:896 ../../mod/admin.php:1099 ../../mod/viewsrc.php:20
+msgid "Item not found."
+msgstr "Posten hittades inte."
-#: ../../include/conversation.php:1014
-#, php-format
-msgid "<span %1$s>%2$d people</span> don't like this."
-msgid_plural "<span %1$s>%2$d people</span> don't like this."
-msgstr[0] "<span %1$s>%2$d person</span> gillar inte det här."
-msgstr[1] "<span %1$s>%2$d personer</span> gillar inte det här."
+#: ../../include/items.php:4019 ../../include/photos.php:15
+#: ../../include/attach.php:116 ../../include/attach.php:163
+#: ../../include/attach.php:226 ../../include/attach.php:240
+#: ../../include/attach.php:280 ../../include/attach.php:294
+#: ../../include/attach.php:318 ../../include/attach.php:511
+#: ../../include/attach.php:585 ../../include/chat.php:116
+#: ../../mod/mood.php:112 ../../mod/register.php:72 ../../mod/mitem.php:106
+#: ../../mod/achievements.php:30 ../../mod/settings.php:542
+#: ../../mod/group.php:9 ../../mod/poke.php:128 ../../mod/api.php:26
+#: ../../mod/api.php:31 ../../mod/setup.php:207 ../../mod/authtest.php:13
+#: ../../mod/profile.php:64 ../../mod/profile.php:72 ../../mod/block.php:22
+#: ../../mod/block.php:72 ../../mod/delegate.php:6 ../../mod/sources.php:66
+#: ../../mod/events.php:195 ../../mod/channel.php:90 ../../mod/channel.php:201
+#: ../../mod/channel.php:244 ../../mod/chat.php:90 ../../mod/chat.php:95
+#: ../../mod/regmod.php:17 ../../mod/editpost.php:13 ../../mod/common.php:35
+#: ../../mod/connections.php:169 ../../mod/connedit.php:266
+#: ../../mod/mail.php:111 ../../mod/photos.php:68 ../../mod/webpages.php:67
+#: ../../mod/bookmarks.php:46 ../../mod/blocks.php:67 ../../mod/blocks.php:75
+#: ../../mod/editblock.php:65 ../../mod/pdledit.php:21
+#: ../../mod/editlayout.php:64 ../../mod/editlayout.php:89
+#: ../../mod/editwebpage.php:64 ../../mod/editwebpage.php:86
+#: ../../mod/editwebpage.php:118 ../../mod/profile_photo.php:263
+#: ../../mod/profile_photo.php:276 ../../mod/like.php:154
+#: ../../mod/thing.php:247 ../../mod/thing.php:264 ../../mod/thing.php:299
+#: ../../mod/fsuggest.php:78 ../../mod/filestorage.php:18
+#: ../../mod/filestorage.php:67 ../../mod/filestorage.php:82
+#: ../../mod/filestorage.php:109 ../../mod/locs.php:71 ../../mod/item.php:191
+#: ../../mod/item.php:199 ../../mod/item.php:972 ../../mod/suggest.php:26
+#: ../../mod/layouts.php:67 ../../mod/layouts.php:74 ../../mod/layouts.php:85
+#: ../../mod/profiles.php:179 ../../mod/profiles.php:550
+#: ../../mod/manage.php:6 ../../mod/menu.php:61 ../../mod/invite.php:13
+#: ../../mod/invite.php:104 ../../mod/network.php:12
+#: ../../mod/notifications.php:66 ../../mod/viewconnections.php:22
+#: ../../mod/viewconnections.php:27 ../../mod/viewsrc.php:14
+#: ../../mod/message.php:16 ../../mod/new_channel.php:68
+#: ../../mod/new_channel.php:99 ../../mod/page.php:28 ../../mod/page.php:78
+#: ../../mod/appman.php:66 ../../mod/service_limits.php:7 ../../index.php:190
+#: ../../index.php:390
+msgid "Permission denied."
+msgstr "Behörighet saknas."
-#: ../../include/conversation.php:1020
-msgid "and"
-msgstr "och"
+#: ../../include/items.php:4410 ../../mod/group.php:38 ../../mod/group.php:140
+msgid "Collection not found."
+msgstr "Kretsen hittades inte."
-#: ../../include/conversation.php:1023
-#, php-format
-msgid ", and %d other people"
-msgid_plural ", and %d other people"
-msgstr[0] ", och %d annan person"
-msgstr[1] ", och %d andra personer"
+#: ../../include/items.php:4425
+msgid "Collection is empty."
+msgstr "Kretsen är tom."
-#: ../../include/conversation.php:1024
+#: ../../include/items.php:4432
#, php-format
-msgid "%s like this."
-msgstr "%s gillar det här."
+msgid "Collection: %s"
+msgstr "Krets: %s"
-#: ../../include/conversation.php:1024
+#: ../../include/items.php:4443
#, php-format
-msgid "%s don't like this."
-msgstr "%s gillar inte det här."
-
-#: ../../include/conversation.php:1081
-msgid "Visible to <strong>everybody</strong>"
-msgstr "Kan ses av <strong>alla</strong>"
-
-#: ../../include/conversation.php:1082 ../../mod/mail.php:171
-#: ../../mod/mail.php:286
-msgid "Please enter a link URL:"
-msgstr "Ange en länkadress:"
-
-#: ../../include/conversation.php:1083
-msgid "Please enter a video link/URL:"
-msgstr "Ange en videolänkadress:"
-
-#: ../../include/conversation.php:1084
-msgid "Please enter an audio link/URL:"
-msgstr "Ange en ljudlänkadress"
-
-#: ../../include/conversation.php:1085
-msgid "Tag term:"
-msgstr "Tagguttryck"
-
-#: ../../include/conversation.php:1086 ../../mod/filer.php:49
-msgid "Save to Folder:"
-msgstr "Spara i mapp:"
-
-#: ../../include/conversation.php:1087
-msgid "Where are you right now?"
-msgstr "Var är du just nu?"
-
-#: ../../include/conversation.php:1088 ../../mod/editpost.php:52
-#: ../../mod/mail.php:172 ../../mod/mail.php:287
-msgid "Expires YYYY-MM-DD HH:MM"
-msgstr "Upphör YYYY-MM-DD HH:MM"
-
-#: ../../include/conversation.php:1098 ../../include/page_widgets.php:40
-#: ../../include/ItemObject.php:630 ../../mod/webpages.php:166
-#: ../../mod/editblock.php:173 ../../mod/editlayout.php:168
-#: ../../mod/editpost.php:140 ../../mod/editwebpage.php:205
-#: ../../mod/photos.php:998
-msgid "Preview"
-msgstr "Förhandsgranska"
-
-#: ../../include/conversation.php:1112 ../../mod/editblock.php:198
-#: ../../mod/editlayout.php:193 ../../mod/editwebpage.php:230
-#: ../../mod/layouts.php:168 ../../mod/photos.php:977
-msgid "Share"
-msgstr "Dela"
-
-#: ../../include/conversation.php:1114 ../../mod/editwebpage.php:170
-msgid "Page link title"
-msgstr "Titel på sidlänk"
-
-#: ../../include/conversation.php:1117
-msgid "Post as"
-msgstr "Posta som"
-
-#: ../../include/conversation.php:1118 ../../mod/editblock.php:144
-#: ../../mod/editlayout.php:140 ../../mod/editpost.php:113
-#: ../../mod/editwebpage.php:175 ../../mod/mail.php:235 ../../mod/mail.php:349
-msgid "Upload photo"
-msgstr "Ladda upp foto"
-
-#: ../../include/conversation.php:1119
-msgid "upload photo"
-msgstr "ladda upp foto"
-
-#: ../../include/conversation.php:1120 ../../mod/editblock.php:145
-#: ../../mod/editlayout.php:141 ../../mod/editpost.php:114
-#: ../../mod/editwebpage.php:176 ../../mod/mail.php:236 ../../mod/mail.php:350
-msgid "Attach file"
-msgstr "Bifoga fil"
-
-#: ../../include/conversation.php:1121
-msgid "attach file"
-msgstr "bifoga fil"
-
-#: ../../include/conversation.php:1122 ../../mod/editblock.php:146
-#: ../../mod/editlayout.php:142 ../../mod/editpost.php:115
-#: ../../mod/editwebpage.php:177 ../../mod/mail.php:237 ../../mod/mail.php:351
-msgid "Insert web link"
-msgstr "Infoga webblänk"
-
-#: ../../include/conversation.php:1123
-msgid "web link"
-msgstr "webblänk"
-
-#: ../../include/conversation.php:1124
-msgid "Insert video link"
-msgstr "Infoga videolänk"
+msgid "Connection: %s"
+msgstr "Kontakt: %s"
-#: ../../include/conversation.php:1125
-msgid "video link"
-msgstr "videolänk"
+#: ../../include/items.php:4446
+msgid "Connection not found."
+msgstr "Kontakten hittades inte."
-#: ../../include/conversation.php:1126
-msgid "Insert audio link"
-msgstr "Infoga ljudlänk"
+#: ../../include/menu.php:42 ../../include/page_widgets.php:8
+#: ../../include/page_widgets.php:36 ../../include/RedDAV/RedBrowser.php:261
+#: ../../include/ItemObject.php:100 ../../include/apps.php:254
+#: ../../mod/settings.php:627 ../../mod/editpost.php:112
+#: ../../mod/connections.php:381 ../../mod/connections.php:394
+#: ../../mod/connections.php:413 ../../mod/webpages.php:162
+#: ../../mod/blocks.php:132 ../../mod/editblock.php:143
+#: ../../mod/editlayout.php:139 ../../mod/editwebpage.php:174
+#: ../../mod/thing.php:233 ../../mod/layouts.php:167 ../../mod/menu.php:78
+msgid "Edit"
+msgstr "Redigera"
-#: ../../include/conversation.php:1127
-msgid "audio link"
-msgstr "ljudlänk"
+#: ../../include/message.php:18
+msgid "No recipient provided."
+msgstr "Ingen mottagare angiven."
-#: ../../include/conversation.php:1128 ../../mod/editblock.php:150
-#: ../../mod/editlayout.php:146 ../../mod/editpost.php:119
-#: ../../mod/editwebpage.php:181
-msgid "Set your location"
-msgstr "Ange din plats"
+#: ../../include/message.php:23
+msgid "[no subject]"
+msgstr "[inget ämne]"
-#: ../../include/conversation.php:1129
-msgid "set location"
-msgstr "ange plats"
+#: ../../include/message.php:45
+msgid "Unable to determine sender."
+msgstr "Kunde inte avgöra vem som är avsändare."
-#: ../../include/conversation.php:1130 ../../mod/editblock.php:151
-#: ../../mod/editlayout.php:147 ../../mod/editpost.php:120
-#: ../../mod/editwebpage.php:182
-msgid "Clear browser location"
-msgstr "Rensa webbläsarplats"
+#: ../../include/message.php:200
+msgid "Stored post could not be verified."
+msgstr "Den sparade posten kunde inte verifieras."
-#: ../../include/conversation.php:1131
-msgid "clear location"
-msgstr "rensa plats"
+#: ../../include/network.php:590
+msgid "view full size"
+msgstr "visa full storlek"
-#: ../../include/conversation.php:1133 ../../mod/editblock.php:164
-#: ../../mod/editlayout.php:159 ../../mod/editpost.php:132
-#: ../../mod/editwebpage.php:198
-msgid "Set title"
-msgstr "Ange titel"
+#: ../../include/permissions.php:26
+msgid "Can view my normal stream and posts"
+msgstr "Kan se mina normala strömmar och inlägg"
-#: ../../include/conversation.php:1136 ../../mod/events.php:574
-#: ../../mod/editblock.php:167 ../../mod/editlayout.php:162
-#: ../../mod/editpost.php:134 ../../mod/editwebpage.php:200
-msgid "Categories (comma-separated list)"
-msgstr "Kategorier (kommaseparerad lista)"
+#: ../../include/permissions.php:27
+msgid "Can view my default channel profile"
+msgstr "Kan se min standardkanalprofil"
-#: ../../include/conversation.php:1138 ../../mod/editblock.php:153
-#: ../../mod/editlayout.php:149 ../../mod/editpost.php:122
-#: ../../mod/editwebpage.php:184
-msgid "Permission settings"
-msgstr "Behörighetsinställningar"
+#: ../../include/permissions.php:28
+msgid "Can view my photo albums"
+msgstr "Kan se mina fotoalbum"
-#: ../../include/conversation.php:1139
-msgid "permissions"
-msgstr "behörighet"
+#: ../../include/permissions.php:29
+msgid "Can view my connections"
+msgstr "Kan se mina kontakter"
-#: ../../include/conversation.php:1146 ../../mod/editblock.php:161
-#: ../../mod/editlayout.php:156 ../../mod/editpost.php:129
-#: ../../mod/editwebpage.php:193
-msgid "Public post"
-msgstr "Offentligt inlägg"
+#: ../../include/permissions.php:30
+msgid "Can view my file storage"
+msgstr "Kan se mitt filutrymme"
-#: ../../include/conversation.php:1148 ../../mod/editblock.php:168
-#: ../../mod/editlayout.php:163 ../../mod/editpost.php:135
-#: ../../mod/editwebpage.php:201
-msgid "Example: bob@example.com, mary@example.com"
-msgstr "Exempel: bob@example.com, mary@example.com"
+#: ../../include/permissions.php:31
+msgid "Can view my webpages"
+msgstr "Kan se mina webbsidor"
-#: ../../include/conversation.php:1161 ../../mod/editblock.php:178
-#: ../../mod/editlayout.php:173 ../../mod/editpost.php:146
-#: ../../mod/editwebpage.php:210 ../../mod/mail.php:242 ../../mod/mail.php:356
-msgid "Set expiration date"
-msgstr "Ange utgångsdatum"
+#: ../../include/permissions.php:34
+msgid "Can send me their channel stream and posts"
+msgstr "Kan skicka sina kanalströmmar och inlägg till mig"
-#: ../../include/conversation.php:1163 ../../include/ItemObject.php:633
-#: ../../mod/editpost.php:148 ../../mod/mail.php:244 ../../mod/mail.php:358
-msgid "Encrypt text"
-msgstr "Kryptera text"
+#: ../../include/permissions.php:35
+msgid "Can post on my channel page (\"wall\")"
+msgstr "Kan posta inlägg på min kanalsida (\"vägg\")"
-#: ../../include/conversation.php:1165 ../../mod/events.php:580
-#: ../../mod/editpost.php:150
-msgid "OK"
-msgstr "OK"
+#: ../../include/permissions.php:36
+msgid "Can comment on or like my posts"
+msgstr "Kan kommentera eller gilla mina inlägg"
-#: ../../include/conversation.php:1166 ../../mod/settings.php:564
-#: ../../mod/settings.php:590 ../../mod/events.php:579
-#: ../../mod/editpost.php:151 ../../mod/fbrowser.php:82
-#: ../../mod/fbrowser.php:117 ../../mod/tagrm.php:11 ../../mod/tagrm.php:134
-msgid "Cancel"
-msgstr "Avbryt"
+#: ../../include/permissions.php:37
+msgid "Can send me private mail messages"
+msgstr "Kan skicka privata meddelanden till mig"
-#: ../../include/conversation.php:1410
-msgid "Discover"
-msgstr "Upptäck"
+#: ../../include/permissions.php:38
+msgid "Can post photos to my photo albums"
+msgstr "Kan lägga till foton i mitt fotoalbum"
-#: ../../include/conversation.php:1413
-msgid "Imported public streams"
-msgstr "Importerade offentliga strömmar"
+#: ../../include/permissions.php:39
+msgid "Can like/dislike stuff"
+msgstr "Kan gilla/ogilla saker"
-#: ../../include/conversation.php:1418
-msgid "Commented Order"
-msgstr "Kommentarsordning"
+#: ../../include/permissions.php:39
+msgid "Profiles and things other than posts/comments"
+msgstr "Profiler och annat än inlägg/kommentarer"
-#: ../../include/conversation.php:1421
-msgid "Sort by Comment Date"
-msgstr "Ordna efter kommentarsdatum"
+#: ../../include/permissions.php:41
+msgid "Can forward to all my channel contacts via post @mentions"
+msgstr "Kan vidarebefordra till alla mina kanalkontakter genom @omnämnanden"
-#: ../../include/conversation.php:1425
-msgid "Posted Order"
-msgstr "Inläggsordning"
+#: ../../include/permissions.php:41
+msgid "Advanced - useful for creating group forum channels"
+msgstr "Avancerat - användbart för att skapa kanaler för gruppforum"
-#: ../../include/conversation.php:1428
-msgid "Sort by Post Date"
-msgstr "Ordna efter när inlägget skrevs"
+#: ../../include/permissions.php:42
+msgid "Can chat with me (when available)"
+msgstr "Kan chatta med mig (när tillgänglig)"
-#: ../../include/conversation.php:1433 ../../include/widgets.php:89
-msgid "Personal"
-msgstr "Personligt"
+#: ../../include/permissions.php:43
+msgid "Can write to my file storage"
+msgstr "Har skrivrättigheter i mitt filutrymme"
-#: ../../include/conversation.php:1436
-msgid "Posts that mention or involve you"
-msgstr "Inlägg som nämner eller berör dig"
+#: ../../include/permissions.php:44
+msgid "Can edit my webpages"
+msgstr "Kan redigera mina webbsidor"
-#: ../../include/conversation.php:1442 ../../mod/connections.php:211
-#: ../../mod/connections.php:224 ../../mod/menu.php:80
-msgid "New"
-msgstr "Nytt"
+#: ../../include/permissions.php:46
+msgid "Can source my public posts in derived channels"
+msgstr "Kan använda mina offentliga inlägg i kanaler nedströms"
-#: ../../include/conversation.php:1445
-msgid "Activity Stream - by date"
-msgstr "Aktivitetsström - efter datum"
+#: ../../include/permissions.php:46
+msgid "Somewhat advanced - very useful in open communities"
+msgstr "Ganska avancerat - väldigt användbart i öppna gemenskaper"
-#: ../../include/conversation.php:1451
-msgid "Starred"
-msgstr "Märkt"
+#: ../../include/permissions.php:48
+msgid "Can administer my channel resources"
+msgstr "Kan administrera mina kanalresurser"
-#: ../../include/conversation.php:1454
-msgid "Favourite Posts"
-msgstr "Favoritinlägg"
+#: ../../include/permissions.php:48
+msgid ""
+"Extremely advanced. Leave this alone unless you know what you are doing"
+msgstr "Extremt avancerat. Låt detta vara om du inte vet vad du gör"
-#: ../../include/conversation.php:1461
-msgid "Spam"
-msgstr "Skräp"
+#: ../../include/permissions.php:814
+msgid "Social Networking"
+msgstr "Socialt nätverkande"
-#: ../../include/conversation.php:1464
-msgid "Posts flagged as SPAM"
-msgstr "Inlägg markerade som SKRÄP"
+#: ../../include/permissions.php:815 ../../include/permissions.php:817
+#: ../../include/permissions.php:819
+msgid "Mostly Public"
+msgstr "Mestadels offentligt"
-#: ../../include/conversation.php:1504 ../../mod/admin.php:865
-msgid "Channel"
-msgstr "Kanal"
+#: ../../include/permissions.php:815 ../../include/permissions.php:817
+#: ../../include/permissions.php:819
+msgid "Restricted"
+msgstr "Begränsat"
-#: ../../include/conversation.php:1507
-msgid "Status Messages and Posts"
-msgstr "Statusmeddelanden och inlägg"
+#: ../../include/permissions.php:815 ../../include/permissions.php:817
+msgid "Private"
+msgstr "Privat"
-#: ../../include/conversation.php:1516
-msgid "About"
-msgstr "Om"
+#: ../../include/permissions.php:816
+msgid "Community Forum"
+msgstr "Gemenskapsforum"
-#: ../../include/conversation.php:1519
-msgid "Profile Details"
-msgstr "Profildetaljer"
+#: ../../include/permissions.php:818
+msgid "Feed Republish"
+msgstr "Vidarepublicering av flöde"
-#: ../../include/conversation.php:1525 ../../include/nav.php:105
-#: ../../include/apps.php:137 ../../mod/fbrowser.php:25
-msgid "Photos"
-msgstr "Foton"
+#: ../../include/permissions.php:820
+msgid "Special Purpose"
+msgstr "Särskilt syfte"
-#: ../../include/conversation.php:1528 ../../include/photos.php:341
-msgid "Photo Albums"
-msgstr "Fotoalbum"
+#: ../../include/permissions.php:821
+msgid "Celebrity/Soapbox"
+msgstr "Kändis/talarstol"
-#: ../../include/conversation.php:1534 ../../include/RedDAV/RedBrowser.php:241
-#: ../../include/nav.php:106 ../../include/apps.php:133
-#: ../../mod/fbrowser.php:114
-msgid "Files"
-msgstr "Filer"
+#: ../../include/permissions.php:821
+msgid "Group Repository"
+msgstr "Gruppförråd"
-#: ../../include/conversation.php:1537
-msgid "Files and Storage"
-msgstr "Filer och lagring"
+#: ../../include/permissions.php:822 ../../include/profile_selectors.php:6
+#: ../../include/profile_selectors.php:23
+#: ../../include/profile_selectors.php:61
+#: ../../include/profile_selectors.php:97
+msgid "Other"
+msgstr "Annat"
-#: ../../include/conversation.php:1547 ../../include/conversation.php:1550
-msgid "Chatrooms"
-msgstr "Chattrum"
+#: ../../include/permissions.php:823
+msgid "Custom/Expert Mode"
+msgstr "Anpassat/expertläge"
-#: ../../include/conversation.php:1560 ../../include/nav.php:117
-#: ../../include/apps.php:127
-msgid "Bookmarks"
-msgstr "Bokmärken"
+#: ../../include/notify.php:23
+msgid "created a new post"
+msgstr "skapade ett nytt inlägg"
-#: ../../include/conversation.php:1563
-msgid "Saved Bookmarks"
-msgstr "Sparade bokmärken"
+#: ../../include/notify.php:24
+#, php-format
+msgid "commented on %s's post"
+msgstr "kommenterade %ss inlägg"
-#: ../../include/conversation.php:1571 ../../include/nav.php:121
-#: ../../include/apps.php:134 ../../mod/webpages.php:160
-msgid "Webpages"
-msgstr "Webbsidor"
+#: ../../include/taxonomy.php:210 ../../include/taxonomy.php:229
+msgid "Tags"
+msgstr "Taggar"
-#: ../../include/conversation.php:1574
-msgid "Manage Webpages"
-msgstr "Hantera webbsidor"
+#: ../../include/taxonomy.php:250 ../../include/contact_widgets.php:92
+#: ../../include/widgets.php:35
+msgid "Categories"
+msgstr "Kategorier"
-#: ../../include/follow.php:28
-msgid "Channel is blocked on this site."
-msgstr "Kanalen är blockerad på den här servern."
+#: ../../include/taxonomy.php:269
+msgid "Keywords"
+msgstr "Nyckelord"
-#: ../../include/follow.php:33
-msgid "Channel location missing."
-msgstr "Kanalplats saknas."
+#: ../../include/taxonomy.php:294
+msgid "have"
+msgstr "har"
-#: ../../include/follow.php:82
-msgid "Response from remote channel was incomplete."
-msgstr "Svar från den andra kanalen var ofullständigt."
+#: ../../include/taxonomy.php:294
+msgid "has"
+msgstr "har"
-#: ../../include/follow.php:99
-msgid "Channel was deleted and no longer exists."
-msgstr "Kanalen har tagits bort och finns inte längre."
+#: ../../include/taxonomy.php:295
+msgid "want"
+msgstr "vill ha"
-#: ../../include/follow.php:135 ../../include/follow.php:202
-msgid "Protocol disabled."
-msgstr "Protokoll inaktiverat."
+#: ../../include/taxonomy.php:295
+msgid "wants"
+msgstr "vill ha"
-#: ../../include/follow.php:176
-msgid "Channel discovery failed."
-msgstr "Kanalsökning misslyckades."
+#: ../../include/taxonomy.php:296 ../../include/ItemObject.php:221
+msgid "like"
+msgstr "gilla"
-#: ../../include/follow.php:192
-msgid "local account not found."
-msgstr "hittade inte lokalt konto."
+#: ../../include/taxonomy.php:296
+msgid "likes"
+msgstr "gillar"
-#: ../../include/follow.php:220
-msgid "Cannot connect to yourself."
-msgstr "Du kan inte kontakta dig själv."
+#: ../../include/taxonomy.php:297 ../../include/ItemObject.php:222
+msgid "dislike"
+msgstr "ogilla"
-#: ../../include/notify.php:23
-msgid "created a new post"
-msgstr "skapade ett nytt inlägg"
+#: ../../include/taxonomy.php:297
+msgid "dislikes"
+msgstr "ogillar"
-#: ../../include/notify.php:24
-#, php-format
-msgid "commented on %s's post"
-msgstr "kommenterade %ss inlägg"
+#: ../../include/taxonomy.php:380 ../../include/identity.php:1148
+#: ../../include/ItemObject.php:146 ../../mod/photos.php:1027
+msgctxt "noun"
+msgid "Like"
+msgid_plural "Likes"
+msgstr[0] "gillar detta"
+msgstr[1] "gillar detta"
#: ../../include/page_widgets.php:6
msgid "New Page"
msgstr "Ny sida"
-#: ../../include/page_widgets.php:8 ../../include/page_widgets.php:36
-#: ../../include/menu.php:42 ../../include/RedDAV/RedBrowser.php:250
-#: ../../include/apps.php:249 ../../include/ItemObject.php:100
-#: ../../mod/blocks.php:132 ../../mod/settings.php:625
-#: ../../mod/connections.php:381 ../../mod/connections.php:394
-#: ../../mod/connections.php:413 ../../mod/thing.php:233
-#: ../../mod/webpages.php:162 ../../mod/editblock.php:143
-#: ../../mod/editlayout.php:139 ../../mod/editpost.php:112
-#: ../../mod/editwebpage.php:174 ../../mod/layouts.php:167
-#: ../../mod/menu.php:78
-msgid "Edit"
-msgstr "Redigera"
-
-#: ../../include/page_widgets.php:39 ../../mod/blocks.php:135
-#: ../../mod/webpages.php:165 ../../mod/layouts.php:171
+#: ../../include/page_widgets.php:39 ../../mod/webpages.php:165
+#: ../../mod/blocks.php:135 ../../mod/layouts.php:171
msgid "View"
msgstr "Visa"
+#: ../../include/page_widgets.php:40 ../../include/conversation.php:1102
+#: ../../include/ItemObject.php:638 ../../mod/photos.php:998
+#: ../../mod/webpages.php:166
+msgid "Preview"
+msgstr "Förhandsgranska"
+
#: ../../include/page_widgets.php:41 ../../mod/webpages.php:167
msgid "Actions"
msgstr "Åtgärder"
@@ -636,80 +410,6 @@ msgstr "Skapad"
msgid "Edited"
msgstr "Ändrad"
-#: ../../include/contact_widgets.php:14
-#, php-format
-msgid "%d invitation available"
-msgid_plural "%d invitations available"
-msgstr[0] "%d inbjudan tillgänglig"
-msgstr[1] "%d inbjudningar tillgängliga"
-
-#: ../../include/contact_widgets.php:19 ../../mod/admin.php:416
-msgid "Advanced"
-msgstr "Avancerat"
-
-#: ../../include/contact_widgets.php:22
-msgid "Find Channels"
-msgstr "Hitta kanaler"
-
-#: ../../include/contact_widgets.php:23
-msgid "Enter name or interest"
-msgstr "Ange namn eller intresse"
-
-#: ../../include/contact_widgets.php:24
-msgid "Connect/Follow"
-msgstr "Ta kontakt/följ"
-
-#: ../../include/contact_widgets.php:25
-msgid "Examples: Robert Morgenstein, Fishing"
-msgstr "Exempel: Robert Morgenstein, Fiske"
-
-#: ../../include/contact_widgets.php:26 ../../mod/connections.php:412
-#: ../../mod/directory.php:278 ../../mod/directory.php:283
-msgid "Find"
-msgstr "Sök"
-
-#: ../../include/contact_widgets.php:27 ../../mod/suggest.php:59
-msgid "Channel Suggestions"
-msgstr "Kanalförslag"
-
-#: ../../include/contact_widgets.php:29
-msgid "Random Profile"
-msgstr "Slumpvald profil"
-
-#: ../../include/contact_widgets.php:30
-msgid "Invite Friends"
-msgstr "Bjud in vänner"
-
-#: ../../include/contact_widgets.php:32
-msgid "Advanced example: name=fred and country=iceland"
-msgstr "Avancerat exempel: name=fred and country=iceland"
-
-#: ../../include/contact_widgets.php:57 ../../include/features.php:73
-#: ../../include/widgets.php:303
-msgid "Saved Folders"
-msgstr "Sparade mappar"
-
-#: ../../include/contact_widgets.php:60 ../../include/contact_widgets.php:95
-#: ../../include/widgets.php:306
-msgid "Everything"
-msgstr "Allt"
-
-#: ../../include/contact_widgets.php:92 ../../include/taxonomy.php:230
-#: ../../include/widgets.php:29
-msgid "Categories"
-msgstr "Kategorier"
-
-#: ../../include/contact_widgets.php:125
-#, php-format
-msgid "%d connection in common"
-msgid_plural "%d connections in common"
-msgstr[0] "%d gemensam kontakt"
-msgstr[1] "%d gemensamma kontakter"
-
-#: ../../include/contact_widgets.php:130
-msgid "show more"
-msgstr "visa fler"
-
#: ../../include/oembed.php:171
msgid "Embedded content"
msgstr "Inbäddat innehåll"
@@ -718,21 +418,42 @@ msgstr "Inbäddat innehåll"
msgid "Embedding disabled"
msgstr "Inbäddning inaktiverat"
-#: ../../include/message.php:18
-msgid "No recipient provided."
-msgstr "Ingen mottagare angiven."
+#: ../../include/auth.php:130
+msgid "Logged out."
+msgstr "Utloggad."
-#: ../../include/message.php:23
-msgid "[no subject]"
-msgstr "[inget ämne]"
+#: ../../include/auth.php:271
+msgid "Failed authentication"
+msgstr "Inloggning misslyckades"
-#: ../../include/message.php:45
-msgid "Unable to determine sender."
-msgstr "Kunde inte avgöra vem som är avsändare."
+#: ../../include/auth.php:285 ../../mod/openid.php:190
+msgid "Login failed."
+msgstr "Inloggning misslyckades."
-#: ../../include/message.php:200
-msgid "Stored post could not be verified."
-msgstr "Den sparade posten kunde inte verifieras."
+#: ../../include/photos.php:105
+#, php-format
+msgid "Image exceeds website size limit of %lu bytes"
+msgstr "Bild överskrider webbplatsens storleksbegränsning på %lu byte"
+
+#: ../../include/photos.php:112
+msgid "Image file is empty."
+msgstr "Bildfil är tom."
+
+#: ../../include/photos.php:141 ../../mod/profile_photo.php:216
+msgid "Unable to process image"
+msgstr "Kunde inte bearbeta bild"
+
+#: ../../include/photos.php:213
+msgid "Photo storage failed."
+msgstr "Fotolagring misslyckades."
+
+#: ../../include/photos.php:341 ../../include/conversation.php:1533
+msgid "Photo Albums"
+msgstr "Fotoalbum"
+
+#: ../../include/photos.php:345
+msgid "Upload New Photos"
+msgstr "Ladda upp nya foton"
#: ../../include/activities.php:39
msgid " and "
@@ -742,172 +463,288 @@ msgstr " och "
msgid "public profile"
msgstr "offentlig profil"
-#: ../../include/activities.php:52
+#: ../../include/activities.php:56
#, php-format
msgid "%1$s changed %2$s to &ldquo;%3$s&rdquo;"
msgstr "%1$s ändrade %2$s till &quot;%3$s&quot;"
-#: ../../include/activities.php:53
+#: ../../include/activities.php:57
#, php-format
msgid "Visit %1$s's %2$s"
msgstr "Besök %1$ss %2$s"
-#: ../../include/activities.php:56
+#: ../../include/activities.php:60
#, php-format
msgid "%1$s has an updated %2$s, changing %3$s."
msgstr "%1$s har en uppdaterad %2$s (har ändrat %3$s)."
-#: ../../include/acl_selectors.php:240
-msgid "Visible to your default audience"
-msgstr "Kan ses av förinställda mottagare"
-
-#: ../../include/acl_selectors.php:241
-msgid "Show"
-msgstr "Visa"
-
-#: ../../include/acl_selectors.php:242
-msgid "Don't show"
-msgstr "Visa inte"
-
-#: ../../include/acl_selectors.php:248 ../../mod/events.php:596
-#: ../../mod/chat.php:209 ../../mod/filestorage.php:137
-#: ../../mod/photos.php:588 ../../mod/photos.php:950
-msgid "Permissions"
-msgstr "Behörighet"
-
-#: ../../include/acl_selectors.php:249 ../../include/ItemObject.php:312
-#: ../../mod/photos.php:1149
-msgid "Close"
-msgstr "Stäng"
-
-#: ../../include/bb2diaspora.php:384
+#: ../../include/bb2diaspora.php:366
msgid "Attachments:"
msgstr "Bilagor:"
-#: ../../include/bb2diaspora.php:463 ../../include/event.php:11
+#: ../../include/bb2diaspora.php:445 ../../include/event.php:11
msgid "l F d, Y \\@ g:i A"
msgstr "l j F Y \\k\\l. H.i"
-#: ../../include/bb2diaspora.php:465
+#: ../../include/bb2diaspora.php:447
msgid "Redmatrix event notification:"
msgstr "Händelsenotifiering från Redmatrix:"
-#: ../../include/bb2diaspora.php:469 ../../include/event.php:20
+#: ../../include/bb2diaspora.php:451 ../../include/event.php:20
msgid "Starts:"
msgstr "Börjar:"
-#: ../../include/bb2diaspora.php:477 ../../include/event.php:30
+#: ../../include/bb2diaspora.php:459 ../../include/event.php:30
msgid "Finishes:"
msgstr "Slutar:"
-#: ../../include/bb2diaspora.php:485 ../../include/identity.php:891
-#: ../../include/event.php:40 ../../mod/events.php:590
-#: ../../mod/directory.php:170
+#: ../../include/bb2diaspora.php:467 ../../include/event.php:40
+#: ../../include/identity.php:891 ../../mod/events.php:590
+#: ../../mod/directory.php:199
msgid "Location:"
msgstr "Plats:"
-#: ../../include/attach.php:116 ../../include/attach.php:163
-#: ../../include/attach.php:226 ../../include/attach.php:240
-#: ../../include/attach.php:280 ../../include/attach.php:294
-#: ../../include/attach.php:318 ../../include/attach.php:511
-#: ../../include/attach.php:585 ../../include/photos.php:15
-#: ../../include/items.php:4019 ../../include/chat.php:116
-#: ../../mod/mood.php:112 ../../mod/mitem.php:106
-#: ../../mod/achievements.php:30 ../../mod/register.php:72
-#: ../../mod/sources.php:66 ../../mod/poke.php:128 ../../mod/api.php:26
-#: ../../mod/api.php:31 ../../mod/authtest.php:13 ../../mod/profile.php:64
-#: ../../mod/profile.php:72 ../../mod/block.php:22 ../../mod/block.php:72
-#: ../../mod/blocks.php:67 ../../mod/blocks.php:75 ../../mod/setup.php:207
-#: ../../mod/settings.php:540 ../../mod/events.php:195
-#: ../../mod/channel.php:89 ../../mod/channel.php:198
-#: ../../mod/channel.php:241 ../../mod/chat.php:90 ../../mod/chat.php:95
-#: ../../mod/regmod.php:17 ../../mod/common.php:35 ../../mod/like.php:154
-#: ../../mod/connections.php:169 ../../mod/connedit.php:266
-#: ../../mod/thing.php:247 ../../mod/thing.php:264 ../../mod/thing.php:299
-#: ../../mod/webpages.php:67 ../../mod/bookmarks.php:46
-#: ../../mod/profiles.php:179 ../../mod/profiles.php:550
-#: ../../mod/editblock.php:65 ../../mod/pdledit.php:21
-#: ../../mod/editlayout.php:64 ../../mod/editlayout.php:89
-#: ../../mod/editpost.php:13 ../../mod/editwebpage.php:64
-#: ../../mod/editwebpage.php:86 ../../mod/editwebpage.php:118
-#: ../../mod/profile_photo.php:263 ../../mod/profile_photo.php:276
-#: ../../mod/item.php:191 ../../mod/item.php:199 ../../mod/item.php:971
-#: ../../mod/fsuggest.php:78 ../../mod/filestorage.php:18
-#: ../../mod/filestorage.php:67 ../../mod/filestorage.php:82
-#: ../../mod/filestorage.php:109 ../../mod/delegate.php:6
-#: ../../mod/group.php:9 ../../mod/suggest.php:26 ../../mod/locs.php:71
-#: ../../mod/mail.php:111 ../../mod/invite.php:13 ../../mod/invite.php:104
-#: ../../mod/manage.php:6 ../../mod/layouts.php:67 ../../mod/layouts.php:74
-#: ../../mod/layouts.php:85 ../../mod/viewconnections.php:22
-#: ../../mod/viewconnections.php:27 ../../mod/viewsrc.php:14
-#: ../../mod/network.php:12 ../../mod/menu.php:61 ../../mod/message.php:16
-#: ../../mod/new_channel.php:68 ../../mod/new_channel.php:99
-#: ../../mod/notifications.php:66 ../../mod/page.php:28 ../../mod/page.php:78
-#: ../../mod/photos.php:68 ../../mod/appman.php:66
-#: ../../mod/service_limits.php:7 ../../index.php:190 ../../index.php:390
-msgid "Permission denied."
-msgstr "Behörighet saknas."
+#: ../../include/features.php:23
+msgid "General Features"
+msgstr "Allmänna funktioner"
-#: ../../include/attach.php:221 ../../include/attach.php:275
-msgid "Item was not found."
-msgstr "Posten hittades inte."
+#: ../../include/features.php:25
+msgid "Content Expiration"
+msgstr "Tidsbegränsat innehåll"
-#: ../../include/attach.php:331
-msgid "No source file."
-msgstr "Ingen källfil."
+#: ../../include/features.php:25
+msgid "Remove posts/comments and/or private messages at a future time"
+msgstr "Ta bort inlägg/kommentarer och/eller privata meddelanden efter en tid"
-#: ../../include/attach.php:348
-msgid "Cannot locate file to replace"
-msgstr "Kan inte hitta fil att ersätta"
+#: ../../include/features.php:26
+msgid "Multiple Profiles"
+msgstr "Flera profiler"
-#: ../../include/attach.php:366
-msgid "Cannot locate file to revise/update"
-msgstr "Kan inte hitta fil att revidera/uppdatera"
+#: ../../include/features.php:26
+msgid "Ability to create multiple profiles"
+msgstr "Möjlighet att skapa flera profiler"
-#: ../../include/attach.php:377
-#, php-format
-msgid "File exceeds size limit of %d"
-msgstr "Filen överskrider storleksbegränsningen %d"
+#: ../../include/features.php:27
+msgid "Advanced Profiles"
+msgstr "Avancerade profiler"
-#: ../../include/attach.php:389
-#, php-format
-msgid "You have reached your limit of %1$.0f Mbytes attachment storage."
-msgstr "Du har nått begränsningen %1$.0f megabyte utrymme för bilagor."
+#: ../../include/features.php:27
+msgid "Additional profile sections and selections"
+msgstr "Fler profilinställningar"
-#: ../../include/attach.php:472
-msgid "File upload failed. Possible system limit or action terminated."
-msgstr "Filuppladdning misslyckades. Möjlig systembegränsning eller avbruten åtgärd."
+#: ../../include/features.php:28
+msgid "Profile Import/Export"
+msgstr "Profilimport/-export"
-#: ../../include/attach.php:484
-msgid "Stored file could not be verified. Upload failed."
-msgstr "Den lagrade filen kunde inte verifieras. Uppladdning misslyckad."
+#: ../../include/features.php:28
+msgid "Save and load profile details across sites/channels"
+msgstr "Spara och ladda profiluppgifter mellan webbplatser/kanaler"
-#: ../../include/attach.php:526 ../../include/attach.php:543
-msgid "Path not available."
-msgstr "Sökväg inte tillgänglig."
+#: ../../include/features.php:29
+msgid "Web Pages"
+msgstr "Webbsidor"
-#: ../../include/attach.php:590
-msgid "Empty pathname"
-msgstr "Tom sökväg"
+#: ../../include/features.php:29
+msgid "Provide managed web pages on your channel"
+msgstr "Tillhandahåll ordnade webbsidor i din kanal"
-#: ../../include/attach.php:606
-msgid "duplicate filename or path"
-msgstr "filnamn eller sökväg finns redan"
+#: ../../include/features.php:30
+msgid "Private Notes"
+msgstr "Privata anteckningar"
-#: ../../include/attach.php:630
-msgid "Path not found."
-msgstr "Sökväg hittas inte."
+#: ../../include/features.php:30
+msgid "Enables a tool to store notes and reminders"
+msgstr "Aktivera ett verktyg för att spara anteckningar och påminnelser"
-#: ../../include/attach.php:681
-msgid "mkdir failed."
-msgstr "mkdir misslyckades."
+#: ../../include/features.php:34
+msgid "Navigation Channel Select"
+msgstr "Kanalväljare i navigation"
-#: ../../include/attach.php:685
-msgid "database storage failed."
-msgstr "databaslagring misslyckades."
+#: ../../include/features.php:34
+msgid "Change channels directly from within the navigation dropdown menu"
+msgstr "Välj kanal direkt från navigationslistens rullgardinsmeny"
+
+#: ../../include/features.php:38
+msgid "Extended Identity Sharing"
+msgstr "Utökad identitetsdelning"
+
+#: ../../include/features.php:38
+msgid ""
+"Share your identity with all websites on the internet. When disabled, "
+"identity is only shared with sites in the matrix."
+msgstr "Dela din identitet med alla webbplatser på Internet. Om inaktiverat är identiteten bara delad med platser i matrisen."
+
+#: ../../include/features.php:39
+msgid "Expert Mode"
+msgstr "Expertläge"
+
+#: ../../include/features.php:39
+msgid "Enable Expert Mode to provide advanced configuration options"
+msgstr "Aktivera expertläge för att tillåta avancerade inställningar"
+
+#: ../../include/features.php:40
+msgid "Premium Channel"
+msgstr "Premiumkanal"
+
+#: ../../include/features.php:40
+msgid ""
+"Allows you to set restrictions and terms on those that connect with your "
+"channel"
+msgstr "Låter dig ange begränsningar och villkor för dem som vill ansluta till din kanal"
+
+#: ../../include/features.php:45
+msgid "Post Composition Features"
+msgstr "Skrivfunktioner"
+
+#: ../../include/features.php:47
+msgid "Use Markdown"
+msgstr "Använd Markdown"
+
+#: ../../include/features.php:47
+msgid "Allow use of \"Markdown\" to format posts"
+msgstr "Tillåt att \"Markdown\" används för att formatera inlägg"
+
+#: ../../include/features.php:49 ../../include/widgets.php:527
+#: ../../mod/sources.php:88
+msgid "Channel Sources"
+msgstr "Kanalkällor"
+
+#: ../../include/features.php:49
+msgid "Automatically import channel content from other channels or feeds"
+msgstr "Importera kanalinnehåll från andra kanaler eller flöden automatiskt"
+
+#: ../../include/features.php:50
+msgid "Even More Encryption"
+msgstr "Ytterligare kryptering"
+
+#: ../../include/features.php:50
+msgid ""
+"Allow optional encryption of content end-to-end with a shared secret key"
+msgstr "Tillåt änd-till-änd-kryptering av innehåll med en delad hemlig nyckel"
+
+#: ../../include/features.php:51
+msgid "Flag Adult Photos"
+msgstr "Flagga vuxenfoton"
+
+#: ../../include/features.php:51
+msgid "Provide photo edit option to hide adult photos from default album view"
+msgstr "Gör det möjligt att inte visa foton som är olämpliga för barn i albums standardvy"
+
+#: ../../include/features.php:56
+msgid "Network and Stream Filtering"
+msgstr "Nätverk och strömfiltrering"
+
+#: ../../include/features.php:57
+msgid "Search by Date"
+msgstr "Sök på datum"
+
+#: ../../include/features.php:57
+msgid "Ability to select posts by date ranges"
+msgstr "Tillåter urval av inlägg baserat på datum"
+
+#: ../../include/features.php:58
+msgid "Collections Filter"
+msgstr "Kretsfilter"
+
+#: ../../include/features.php:58
+msgid "Enable widget to display Network posts only from selected collections"
+msgstr "Aktivera en väljare för att visa nätverksinlägg från enbart valda kretsar"
+
+#: ../../include/features.php:59 ../../include/widgets.php:272
+msgid "Saved Searches"
+msgstr "Sparade sökningar"
+
+#: ../../include/features.php:59
+msgid "Save search terms for re-use"
+msgstr "Spara sökuttryck för återanvändning"
+
+#: ../../include/features.php:60
+msgid "Network Personal Tab"
+msgstr "Personlig nätverksflik"
+
+#: ../../include/features.php:60
+msgid "Enable tab to display only Network posts that you've interacted on"
+msgstr "Aktivera en flik som visar endast de nätverksinlägg som du har deltagit i"
+
+#: ../../include/features.php:61
+msgid "Network New Tab"
+msgstr "Flik för nytt på nätverket"
+
+#: ../../include/features.php:61
+msgid "Enable tab to display all new Network activity"
+msgstr "Aktivera en flik som visar all ny nätverksaktivitet"
+
+#: ../../include/features.php:62
+msgid "Affinity Tool"
+msgstr "Samhörighetsverktyg"
+
+#: ../../include/features.php:62
+msgid "Filter stream activity by depth of relationships"
+msgstr "Filtrera strömaktivitet efter hur nära relationen är"
+
+#: ../../include/features.php:63
+msgid "Suggest Channels"
+msgstr "Föreslå kanaler"
+
+#: ../../include/features.php:63
+msgid "Show channel suggestions"
+msgstr "Visa förslag på kanaler"
+
+#: ../../include/features.php:68
+msgid "Post/Comment Tools"
+msgstr "Inläggs-/kommentarsverktyg"
+
+#: ../../include/features.php:71
+msgid "Tagging"
+msgstr "Taggning"
+
+#: ../../include/features.php:71
+msgid "Ability to tag existing posts"
+msgstr "Möjlighet att tagga befintliga inlägg"
+
+#: ../../include/features.php:72
+msgid "Post Categories"
+msgstr "Inläggskategorier"
+
+#: ../../include/features.php:72
+msgid "Add categories to your posts"
+msgstr "Lägg till kategorier till dina inlägg"
+
+#: ../../include/features.php:73 ../../include/contact_widgets.php:57
+#: ../../include/widgets.php:302
+msgid "Saved Folders"
+msgstr "Sparade mappar"
+
+#: ../../include/features.php:73
+msgid "Ability to file posts under folders"
+msgstr "Möjlighet att lägga inlägg i mappar"
+
+#: ../../include/features.php:74
+msgid "Dislike Posts"
+msgstr "Ogilla inlägg"
+
+#: ../../include/features.php:74
+msgid "Ability to dislike posts/comments"
+msgstr "Möjlighet att ogilla inlägg/kommentarer"
+
+#: ../../include/features.php:75
+msgid "Star Posts"
+msgstr "Märk inlägg"
+
+#: ../../include/features.php:75
+msgid "Ability to mark special posts with a star indicator"
+msgstr "Möjlighet att märka speciella inlägg med en stjärna"
+
+#: ../../include/features.php:76
+msgid "Tag Cloud"
+msgstr "Taggmoln"
+
+#: ../../include/features.php:76
+msgid "Provide a personal tag cloud on your channel page"
+msgstr "Tillhandahåll ett personligt taggmoln på din kanalsida"
#: ../../include/RedDAV/RedBrowser.php:106
-#: ../../include/RedDAV/RedBrowser.php:249
+#: ../../include/RedDAV/RedBrowser.php:260
msgid "parent"
msgstr "en nivå upp"
@@ -935,6 +772,13 @@ msgstr "Schemainkorg"
msgid "Schedule Outbox"
msgstr "Schemautkorg"
+#: ../../include/RedDAV/RedBrowser.php:163 ../../include/conversation.php:992
+#: ../../include/apps.php:336 ../../include/apps.php:387
+#: ../../mod/connedit.php:513 ../../mod/photos.php:713
+#: ../../mod/photos.php:1132
+msgid "Unknown"
+msgstr "Okända"
+
#: ../../include/RedDAV/RedBrowser.php:223
#, php-format
msgid "%1$s used"
@@ -945,42 +789,56 @@ msgstr "%1$s använt"
msgid "%1$s used of %2$s (%3$s&#37;)"
msgstr "%1$s använt av %2$s (%3$s&#37;)"
-#: ../../include/RedDAV/RedBrowser.php:245 ../../mod/settings.php:565
-#: ../../mod/settings.php:591 ../../mod/admin.php:866
+#: ../../include/RedDAV/RedBrowser.php:247 ../../include/conversation.php:1539
+#: ../../include/apps.php:135 ../../include/nav.php:106
+#: ../../mod/fbrowser.php:114
+msgid "Files"
+msgstr "Filer"
+
+#: ../../include/RedDAV/RedBrowser.php:249
+msgid "Total"
+msgstr "Totalt"
+
+#: ../../include/RedDAV/RedBrowser.php:256 ../../mod/settings.php:567
+#: ../../mod/settings.php:593 ../../mod/admin.php:866
msgid "Name"
msgstr "Namn"
-#: ../../include/RedDAV/RedBrowser.php:246
+#: ../../include/RedDAV/RedBrowser.php:257
msgid "Type"
msgstr "Typ"
-#: ../../include/RedDAV/RedBrowser.php:247
+#: ../../include/RedDAV/RedBrowser.php:258
msgid "Size"
msgstr "Storlek"
-#: ../../include/RedDAV/RedBrowser.php:248
+#: ../../include/RedDAV/RedBrowser.php:259
msgid "Last Modified"
msgstr "Senast ändrad"
-#: ../../include/RedDAV/RedBrowser.php:252
-msgid "Total"
-msgstr "Totalt"
+#: ../../include/RedDAV/RedBrowser.php:262 ../../include/conversation.php:639
+#: ../../include/ItemObject.php:120 ../../include/apps.php:255
+#: ../../mod/settings.php:628 ../../mod/group.php:176
+#: ../../mod/connedit.php:476 ../../mod/photos.php:1070
+#: ../../mod/thing.php:234 ../../mod/admin.php:730 ../../mod/admin.php:861
+msgid "Delete"
+msgstr "Ta bort"
-#: ../../include/RedDAV/RedBrowser.php:305
+#: ../../include/RedDAV/RedBrowser.php:310
msgid "Create new folder"
msgstr "Skapa ny mapp"
-#: ../../include/RedDAV/RedBrowser.php:306 ../../mod/mitem.php:169
-#: ../../mod/menu.php:100 ../../mod/new_channel.php:122
+#: ../../include/RedDAV/RedBrowser.php:311 ../../mod/mitem.php:169
+#: ../../mod/menu.php:100 ../../mod/new_channel.php:124
msgid "Create"
msgstr "Skapa"
-#: ../../include/RedDAV/RedBrowser.php:307
+#: ../../include/RedDAV/RedBrowser.php:312
msgid "Upload file"
msgstr "Ladda upp fil"
-#: ../../include/RedDAV/RedBrowser.php:308 ../../mod/profile_photo.php:361
-#: ../../mod/photos.php:738 ../../mod/photos.php:1246
+#: ../../include/RedDAV/RedBrowser.php:313 ../../mod/photos.php:738
+#: ../../mod/photos.php:1246 ../../mod/profile_photo.php:361
msgid "Upload"
msgstr "Ladda upp"
@@ -989,258 +847,45 @@ msgstr "Ladda upp"
msgid "%1$s's bookmarks"
msgstr "%1$ss bokmärken"
-#: ../../include/nav.php:95 ../../include/nav.php:128 ../../boot.php:1485
-msgid "Logout"
-msgstr "Logga ut"
-
-#: ../../include/nav.php:95 ../../include/nav.php:128
-msgid "End this session"
-msgstr "Avsluta sessionen"
-
-#: ../../include/nav.php:98 ../../include/nav.php:159
-msgid "Home"
-msgstr "Hem"
-
-#: ../../include/nav.php:98
-msgid "Your posts and conversations"
-msgstr "Dina inlägg och konversationer"
-
-#: ../../include/nav.php:99
-msgid "Your profile page"
-msgstr "Din profilsida"
-
-#: ../../include/nav.php:101
-msgid "Edit Profiles"
-msgstr "Redigera profiler"
-
-#: ../../include/nav.php:101
-msgid "Manage/Edit profiles"
-msgstr "Hantera/redigera profiler"
-
-#: ../../include/nav.php:103 ../../include/identity.php:864
-msgid "Edit Profile"
-msgstr "Redigera profil"
-
-#: ../../include/nav.php:103
-msgid "Edit your profile"
-msgstr "Redigera din profil"
-
-#: ../../include/nav.php:105
-msgid "Your photos"
-msgstr "Dina foton"
-
-#: ../../include/nav.php:106
-msgid "Your files"
-msgstr "Dina filer"
-
-#: ../../include/nav.php:111 ../../include/apps.php:144
-msgid "Chat"
-msgstr "Chatt"
-
-#: ../../include/nav.php:111
-msgid "Your chatrooms"
-msgstr "Dina chattrum"
-
-#: ../../include/nav.php:117
-msgid "Your bookmarks"
-msgstr "Dina bokmärken"
-
-#: ../../include/nav.php:121
-msgid "Your webpages"
-msgstr "Dina webbsidor"
-
-#: ../../include/nav.php:125 ../../include/apps.php:129 ../../boot.php:1486
-msgid "Login"
-msgstr "Logga in"
-
-#: ../../include/nav.php:125
-msgid "Sign in"
-msgstr "Logga in"
-
-#: ../../include/nav.php:142
-#, php-format
-msgid "%s - click to logout"
-msgstr "%s - klicka för att logga ut"
-
-#: ../../include/nav.php:145
-msgid "Remote authentication"
-msgstr "Fjärrinloggning"
-
-#: ../../include/nav.php:145
-msgid "Click to authenticate to your home hub"
-msgstr "Klicka för att autentisera mot din hemmahubb"
-
-#: ../../include/nav.php:159
-msgid "Home Page"
-msgstr "Hemsida"
-
-#: ../../include/nav.php:163 ../../mod/register.php:224 ../../boot.php:1464
-msgid "Register"
-msgstr "Skapa konto"
-
-#: ../../include/nav.php:163
-msgid "Create an account"
-msgstr "Skapa ett konto"
-
-#: ../../include/nav.php:168 ../../include/apps.php:140 ../../mod/help.php:58
-#: ../../mod/help.php:63
-msgid "Help"
-msgstr "Hjälp"
-
-#: ../../include/nav.php:168
-msgid "Help and documentation"
-msgstr "Hjälp och dokumentation"
-
-#: ../../include/nav.php:171 ../../include/widgets.php:86
-#: ../../mod/apps.php:33
-msgid "Apps"
-msgstr "Appar"
-
-#: ../../include/nav.php:171
-msgid "Applications, utilities, links, games"
-msgstr "Applikationer, verktyg, länkar, spel"
-
-#: ../../include/nav.php:173 ../../include/text.php:826
-#: ../../include/text.php:838 ../../include/apps.php:145
-#: ../../mod/search.php:30
-msgid "Search"
-msgstr "Sök"
-
-#: ../../include/nav.php:173
-msgid "Search site content"
-msgstr "Sök innehåll"
-
-#: ../../include/nav.php:176 ../../include/apps.php:139
-#: ../../mod/directory.php:282
-msgid "Directory"
-msgstr "Katalog"
-
-#: ../../include/nav.php:176
-msgid "Channel Directory"
-msgstr "Kanalkatalog"
-
-#: ../../include/nav.php:190 ../../include/apps.php:131
-msgid "Matrix"
-msgstr "Matris"
-
-#: ../../include/nav.php:190
-msgid "Your matrix"
-msgstr "Din matris"
-
-#: ../../include/nav.php:191
-msgid "Mark all matrix notifications seen"
-msgstr "Märk alla matrisnotifieringar som lästa"
-
-#: ../../include/nav.php:193 ../../include/apps.php:135
-msgid "Channel Home"
-msgstr "Kanalhem"
-
-#: ../../include/nav.php:193
-msgid "Channel home"
-msgstr "Kanalhem"
-
-#: ../../include/nav.php:194
-msgid "Mark all channel notifications seen"
-msgstr "Märk alla kanalnotifieringar som lästa"
-
-#: ../../include/nav.php:197 ../../mod/connections.php:406
-msgid "Connections"
-msgstr "Kontakter"
-
-#: ../../include/nav.php:200
-msgid "Notices"
-msgstr "Meddelanden"
-
-#: ../../include/nav.php:200
-msgid "Notifications"
-msgstr "Notifieringar"
-
-#: ../../include/nav.php:201
-msgid "See all notifications"
-msgstr "Se alla notifieringar"
-
-#: ../../include/nav.php:202 ../../mod/notifications.php:99
-msgid "Mark all system notifications seen"
-msgstr "Märk alla systemnotifieringar som lästa"
-
-#: ../../include/nav.php:204 ../../include/apps.php:141
-msgid "Mail"
-msgstr "Privat meddelande"
-
-#: ../../include/nav.php:204
-msgid "Private mail"
-msgstr "Privat meddelande"
-
-#: ../../include/nav.php:205
-msgid "See all private messages"
-msgstr "Se alla privata meddelanden"
-
-#: ../../include/nav.php:206
-msgid "Mark all private messages seen"
-msgstr "Märk alla privata meddelanden som lästa"
-
-#: ../../include/nav.php:207
-msgid "Inbox"
-msgstr "Inkorg"
-
-#: ../../include/nav.php:208
-msgid "Outbox"
-msgstr "Utkorg"
-
-#: ../../include/nav.php:209 ../../include/widgets.php:572
-msgid "New Message"
-msgstr "Nytt meddelande"
-
-#: ../../include/nav.php:212 ../../include/apps.php:138
-#: ../../mod/events.php:442
-msgid "Events"
-msgstr "Händelser"
-
-#: ../../include/nav.php:212
-msgid "Event Calendar"
-msgstr "Kalender"
-
-#: ../../include/nav.php:213
-msgid "See all events"
-msgstr "Se alla händelser"
+#: ../../include/dir_fns.php:68
+msgid "Directory Options"
+msgstr "Katalogalternativ"
-#: ../../include/nav.php:214
-msgid "Mark all events seen"
-msgstr "Märk alla händelser som lästa"
+#: ../../include/dir_fns.php:69
+msgid "Alphabetic"
+msgstr "Alfabetisk"
-#: ../../include/nav.php:216 ../../include/apps.php:130
-#: ../../mod/manage.php:148
-msgid "Channel Manager"
-msgstr "Kanalhanterare"
+#: ../../include/dir_fns.php:70
+msgid "Reverse Alphabetic"
+msgstr "Omvänd alfabetisk"
-#: ../../include/nav.php:216
-msgid "Manage Your Channels"
-msgstr "Hantera dina kanaler"
+#: ../../include/dir_fns.php:71
+msgid "Newest to Oldest"
+msgstr "Nyast till äldst"
-#: ../../include/nav.php:218 ../../include/widgets.php:548
-#: ../../include/apps.php:132 ../../mod/admin.php:951 ../../mod/admin.php:1156
-msgid "Settings"
-msgstr "Inställningar"
+#: ../../include/dir_fns.php:72
+msgid "Oldest to Newest"
+msgstr "Äldst till nyast"
-#: ../../include/nav.php:218
-msgid "Account/Channel Settings"
-msgstr "Konto-/kanalinställningar"
+#: ../../include/dir_fns.php:73
+msgid "Public Forums Only"
+msgstr "Endast offentliga forum"
-#: ../../include/nav.php:226 ../../mod/admin.php:123
-msgid "Admin"
-msgstr "Administration"
+#: ../../include/dir_fns.php:75
+msgid "Sort"
+msgstr "Ordning"
-#: ../../include/nav.php:226
-msgid "Site Setup and Configuration"
-msgstr "Serverinställning och -konfiguration"
+#: ../../include/dir_fns.php:91
+msgid "Enable Safe Search"
+msgstr "Aktivera säker sökning"
-#: ../../include/nav.php:262
-msgid "Please wait..."
-msgstr "Vänta..."
+#: ../../include/dir_fns.php:93
+msgid "Disable Safe Search"
+msgstr "Avaktivera säker sökning"
-#: ../../include/network.php:590
-msgid "view full size"
-msgstr "visa full storlek"
+#: ../../include/dir_fns.php:95
+msgid "Safe Mode"
+msgstr "Säkert läge"
#: ../../include/comanche.php:35 ../../mod/admin.php:353
#: ../../view/theme/apw/php/config.php:185
@@ -1284,7 +929,7 @@ msgid "RSS/Atom"
msgstr "RSS/Atom"
#: ../../include/contact_selectors.php:79 ../../mod/admin.php:726
-#: ../../mod/admin.php:735 ../../boot.php:1488
+#: ../../mod/admin.php:735 ../../boot.php:1542
msgid "Email"
msgstr "E-post"
@@ -1312,475 +957,439 @@ msgstr "XMPP/IM"
msgid "MySpace"
msgstr "MySpace"
-#: ../../include/identity.php:31 ../../mod/item.php:1368
-msgid "Unable to obtain identity information from database"
-msgstr "Kunde inte hämta från databasen"
-
-#: ../../include/identity.php:66
-msgid "Empty name"
-msgstr "Tomt namn"
-
-#: ../../include/identity.php:68
-msgid "Name too long"
-msgstr "För långt namn"
+#: ../../include/acl_selectors.php:240
+msgid "Visible to your default audience"
+msgstr "Kan ses av förinställda mottagare"
-#: ../../include/identity.php:169
-msgid "No account identifier"
-msgstr "Ingen kontoidentifierare"
+#: ../../include/acl_selectors.php:241
+msgid "Show"
+msgstr "Visa"
-#: ../../include/identity.php:182
-msgid "Nickname is required."
-msgstr "Smeknamn måste anges."
+#: ../../include/acl_selectors.php:242
+msgid "Don't show"
+msgstr "Visa inte"
-#: ../../include/identity.php:196
-msgid "Reserved nickname. Please choose another."
-msgstr "Reserverat smeknamn. Välj ett annat."
+#: ../../include/acl_selectors.php:248 ../../mod/events.php:596
+#: ../../mod/chat.php:209 ../../mod/photos.php:588 ../../mod/photos.php:950
+#: ../../mod/filestorage.php:137
+msgid "Permissions"
+msgstr "Behörighet"
-#: ../../include/identity.php:201 ../../include/dimport.php:34
-msgid ""
-"Nickname has unsupported characters or is already being used on this site."
-msgstr "Smeknamnet innehåller otillåtna tecken eller är redan upptaget på den här servern."
+#: ../../include/acl_selectors.php:249 ../../include/ItemObject.php:320
+#: ../../mod/photos.php:1149
+msgid "Close"
+msgstr "Stäng"
-#: ../../include/identity.php:283
-msgid "Unable to retrieve created identity"
-msgstr "Kunde inte hämta den skapade identiteten"
+#: ../../include/text.php:320
+msgid "prev"
+msgstr "föregående"
-#: ../../include/identity.php:343
-msgid "Default Profile"
-msgstr "Standardprofil"
+#: ../../include/text.php:322
+msgid "first"
+msgstr "första"
-#: ../../include/identity.php:387 ../../include/identity.php:388
-#: ../../include/identity.php:395 ../../include/widgets.php:431
-#: ../../include/profile_selectors.php:80 ../../mod/settings.php:318
-#: ../../mod/settings.php:322 ../../mod/settings.php:323
-#: ../../mod/settings.php:326 ../../mod/settings.php:337
-#: ../../mod/connedit.php:509
-msgid "Friends"
-msgstr "Vänner"
+#: ../../include/text.php:351
+msgid "last"
+msgstr "sista"
-#: ../../include/identity.php:643
-msgid "Requested channel is not available."
-msgstr "Den begärda kanalen är inte tillgänglig"
+#: ../../include/text.php:354
+msgid "next"
+msgstr "nästa"
-#: ../../include/identity.php:691 ../../mod/achievements.php:11
-#: ../../mod/profile.php:16 ../../mod/blocks.php:29 ../../mod/connect.php:13
-#: ../../mod/webpages.php:29 ../../mod/editblock.php:29
-#: ../../mod/editlayout.php:28 ../../mod/editwebpage.php:28
-#: ../../mod/filestorage.php:48 ../../mod/layouts.php:29 ../../mod/hcard.php:8
-msgid "Requested profile is not available."
-msgstr "Begärd profil är inte tillgänglig."
+#: ../../include/text.php:366
+msgid "older"
+msgstr "äldre"
-#: ../../include/identity.php:854 ../../mod/profiles.php:740
-msgid "Change profile photo"
-msgstr "Bytprofilfoto"
+#: ../../include/text.php:368
+msgid "newer"
+msgstr "nyare"
-#: ../../include/identity.php:860
-msgid "Profiles"
-msgstr "Profiler"
+#: ../../include/text.php:756
+msgid "No connections"
+msgstr "Inga kontakter"
-#: ../../include/identity.php:860
-msgid "Manage/edit profiles"
-msgstr "Hantera/redigera profiler"
+#: ../../include/text.php:772
+#, php-format
+msgid "%d Connection"
+msgid_plural "%d Connections"
+msgstr[0] "%d kontakt"
+msgstr[1] "%d kontakter"
-#: ../../include/identity.php:861 ../../mod/profiles.php:741
-msgid "Create New Profile"
-msgstr "Skapa ny profil"
+#: ../../include/text.php:785
+msgid "View Connections"
+msgstr "Visa kontakter"
-#: ../../include/identity.php:875 ../../mod/profiles.php:752
-msgid "Profile Image"
-msgstr "Profilbild"
+#: ../../include/text.php:842 ../../include/text.php:854
+#: ../../include/apps.php:147 ../../include/nav.php:173
+#: ../../mod/search.php:30
+msgid "Search"
+msgstr "Sök"
-#: ../../include/identity.php:878
-msgid "visible to everybody"
-msgstr "synlig för alla"
+#: ../../include/text.php:843 ../../include/text.php:855
+#: ../../include/widgets.php:192 ../../mod/rbmark.php:28
+#: ../../mod/rbmark.php:98 ../../mod/filer.php:50 ../../mod/admin.php:1339
+#: ../../mod/admin.php:1360
+msgid "Save"
+msgstr "Spara"
-#: ../../include/identity.php:879 ../../mod/profiles.php:635
-#: ../../mod/profiles.php:756
-msgid "Edit visibility"
-msgstr "Redigera synlighet"
+#: ../../include/text.php:920
+msgid "poke"
+msgstr "puffa"
-#: ../../include/identity.php:895 ../../include/identity.php:1132
-msgid "Gender:"
-msgstr "Kön:"
+#: ../../include/text.php:920 ../../include/conversation.php:243
+msgid "poked"
+msgstr "puffade"
-#: ../../include/identity.php:896 ../../include/identity.php:1176
-msgid "Status:"
-msgstr "Status:"
+#: ../../include/text.php:921
+msgid "ping"
+msgstr "pinga"
-#: ../../include/identity.php:897 ../../include/identity.php:1187
-msgid "Homepage:"
-msgstr "Hemsida:"
+#: ../../include/text.php:921
+msgid "pinged"
+msgstr "pingade"
-#: ../../include/identity.php:898
-msgid "Online Now"
-msgstr "Online nu"
+#: ../../include/text.php:922
+msgid "prod"
+msgstr "stöt till"
-#: ../../include/identity.php:976 ../../include/identity.php:1056
-#: ../../mod/ping.php:326
-msgid "g A l F d"
-msgstr "l j F \\k\\l G"
+#: ../../include/text.php:922
+msgid "prodded"
+msgstr "stötte till"
-#: ../../include/identity.php:977 ../../include/identity.php:1057
-msgid "F d"
-msgstr "j F"
+#: ../../include/text.php:923
+msgid "slap"
+msgstr "daska till"
-#: ../../include/identity.php:1022 ../../include/identity.php:1097
-#: ../../mod/ping.php:348
-msgid "[today]"
-msgstr "[i dag]"
+#: ../../include/text.php:923
+msgid "slapped"
+msgstr "daskade till"
-#: ../../include/identity.php:1034
-msgid "Birthday Reminders"
-msgstr "Födelsedagspåminnelser"
+#: ../../include/text.php:924
+msgid "finger"
+msgstr "fingra på"
-#: ../../include/identity.php:1035
-msgid "Birthdays this week:"
-msgstr "Födelsedagar den här veckan:"
+#: ../../include/text.php:924
+msgid "fingered"
+msgstr "fingrade på"
-#: ../../include/identity.php:1090
-msgid "[No description]"
-msgstr "[Ingen beskrivning]"
+#: ../../include/text.php:925
+msgid "rebuff"
+msgstr "stöt tillbaka"
-#: ../../include/identity.php:1108
-msgid "Event Reminders"
-msgstr "Händelsepåminnelser"
+#: ../../include/text.php:925
+msgid "rebuffed"
+msgstr "stötte tillbaks"
-#: ../../include/identity.php:1109
-msgid "Events this week:"
-msgstr "Händelser den här veckan:"
+#: ../../include/text.php:935
+msgid "happy"
+msgstr "glad"
-#: ../../include/identity.php:1122 ../../include/identity.php:1240
-#: ../../include/apps.php:136 ../../mod/profperm.php:112
-msgid "Profile"
-msgstr "Profil"
+#: ../../include/text.php:936
+msgid "sad"
+msgstr "ledsen"
-#: ../../include/identity.php:1130 ../../mod/settings.php:1005
-msgid "Full Name:"
-msgstr "Fullständigt namn:"
+#: ../../include/text.php:937
+msgid "mellow"
+msgstr "lugn"
-#: ../../include/identity.php:1137
-msgid "Like this channel"
-msgstr "Gilla den här kanalen"
+#: ../../include/text.php:938
+msgid "tired"
+msgstr "trött"
-#: ../../include/identity.php:1148 ../../include/taxonomy.php:360
-#: ../../include/ItemObject.php:146 ../../mod/photos.php:1027
-msgctxt "noun"
-msgid "Like"
-msgid_plural "Likes"
-msgstr[0] "gillar detta"
-msgstr[1] "gillar detta"
+#: ../../include/text.php:939
+msgid "perky"
+msgstr "uppåt"
-#: ../../include/identity.php:1161
-msgid "j F, Y"
-msgstr "j F Y"
+#: ../../include/text.php:940
+msgid "angry"
+msgstr "arg"
-#: ../../include/identity.php:1162
-msgid "j F"
-msgstr "j F"
+#: ../../include/text.php:941
+msgid "stupified"
+msgstr "virrig"
-#: ../../include/identity.php:1169
-msgid "Birthday:"
-msgstr "Födelsedag:"
+#: ../../include/text.php:942
+msgid "puzzled"
+msgstr "förbryllad"
-#: ../../include/identity.php:1173
-msgid "Age:"
-msgstr "Ålder:"
+#: ../../include/text.php:943
+msgid "interested"
+msgstr "intresserad"
-#: ../../include/identity.php:1182
-#, php-format
-msgid "for %1$d %2$s"
-msgstr "i %1$d %2$s"
+#: ../../include/text.php:944
+msgid "bitter"
+msgstr "bitter"
-#: ../../include/identity.php:1185 ../../mod/profiles.php:657
-msgid "Sexual Preference:"
-msgstr "Sexuell preferens:"
+#: ../../include/text.php:945
+msgid "cheerful"
+msgstr "munter"
-#: ../../include/identity.php:1189 ../../mod/profiles.php:659
-msgid "Hometown:"
-msgstr "Hemort:"
+#: ../../include/text.php:946
+msgid "alive"
+msgstr "pigg"
-#: ../../include/identity.php:1191
-msgid "Tags:"
-msgstr "Taggar:"
+#: ../../include/text.php:947
+msgid "annoyed"
+msgstr "irriterad"
-#: ../../include/identity.php:1193 ../../mod/profiles.php:660
-msgid "Political Views:"
-msgstr "Politisk åskådning:"
+#: ../../include/text.php:948
+msgid "anxious"
+msgstr "bekymrad"
-#: ../../include/identity.php:1195
-msgid "Religion:"
-msgstr "Religion:"
+#: ../../include/text.php:949
+msgid "cranky"
+msgstr "grinig"
-#: ../../include/identity.php:1197
-msgid "About:"
-msgstr "Om:"
+#: ../../include/text.php:950
+msgid "disturbed"
+msgstr "besvärad"
-#: ../../include/identity.php:1199
-msgid "Hobbies/Interests:"
-msgstr "Fritidssysselsättning/intressen:"
+#: ../../include/text.php:951
+msgid "frustrated"
+msgstr "frustrerad"
-#: ../../include/identity.php:1201 ../../mod/profiles.php:663
-msgid "Likes:"
-msgstr "Gillar:"
+#: ../../include/text.php:952
+msgid "depressed"
+msgstr "deprimerad"
-#: ../../include/identity.php:1203 ../../mod/profiles.php:664
-msgid "Dislikes:"
-msgstr "Ogillar:"
+#: ../../include/text.php:953
+msgid "motivated"
+msgstr "motiverad"
-#: ../../include/identity.php:1206
-msgid "Contact information and Social Networks:"
-msgstr "Kontaktinformation och sociala nätverk:"
+#: ../../include/text.php:954
+msgid "relaxed"
+msgstr "avslappnad"
-#: ../../include/identity.php:1208
-msgid "My other channels:"
-msgstr "Mina andra kanaler:"
+#: ../../include/text.php:955
+msgid "surprised"
+msgstr "förvånad"
-#: ../../include/identity.php:1210
-msgid "Musical interests:"
-msgstr "Musikintressen:"
+#: ../../include/text.php:1121
+msgid "Monday"
+msgstr "måndag"
-#: ../../include/identity.php:1212
-msgid "Books, literature:"
-msgstr "Böcker, litteratur:"
+#: ../../include/text.php:1121
+msgid "Tuesday"
+msgstr "tisdag"
-#: ../../include/identity.php:1214
-msgid "Television:"
-msgstr "Tv:"
+#: ../../include/text.php:1121
+msgid "Wednesday"
+msgstr "onsdag"
-#: ../../include/identity.php:1216
-msgid "Film/dance/culture/entertainment:"
-msgstr "Film/dans/kultur/underhållning:"
+#: ../../include/text.php:1121
+msgid "Thursday"
+msgstr "torsdag"
-#: ../../include/identity.php:1218
-msgid "Love/Romance:"
-msgstr "Kärlek/romantik:"
+#: ../../include/text.php:1121
+msgid "Friday"
+msgstr "fredag"
-#: ../../include/identity.php:1220
-msgid "Work/employment:"
-msgstr "Arbete/sysselsättning:"
+#: ../../include/text.php:1121
+msgid "Saturday"
+msgstr "lördag"
-#: ../../include/identity.php:1222
-msgid "School/education:"
-msgstr "Skola/utbildning:"
+#: ../../include/text.php:1121
+msgid "Sunday"
+msgstr "söndag"
-#: ../../include/identity.php:1242
-msgid "Like this thing"
-msgstr "Gilla den här saken"
+#: ../../include/text.php:1125
+msgid "January"
+msgstr "januari"
-#: ../../include/bbcode.php:112 ../../include/bbcode.php:655
-#: ../../include/bbcode.php:658 ../../include/bbcode.php:663
-#: ../../include/bbcode.php:666 ../../include/bbcode.php:669
-#: ../../include/bbcode.php:672 ../../include/bbcode.php:677
-#: ../../include/bbcode.php:680 ../../include/bbcode.php:685
-#: ../../include/bbcode.php:688 ../../include/bbcode.php:691
-#: ../../include/bbcode.php:694
-msgid "Image/photo"
-msgstr "Bild/foto"
+#: ../../include/text.php:1125
+msgid "February"
+msgstr "februari"
-#: ../../include/bbcode.php:147 ../../include/bbcode.php:705
-msgid "Encrypted content"
-msgstr "Krypterat innehåll"
+#: ../../include/text.php:1125
+msgid "March"
+msgstr "mars"
-#: ../../include/bbcode.php:165
-msgid "Install design element: "
-msgstr "Installera designelement: "
+#: ../../include/text.php:1125
+msgid "April"
+msgstr "april"
-#: ../../include/bbcode.php:171
-msgid "QR code"
-msgstr "QR-kod"
+#: ../../include/text.php:1125
+msgid "May"
+msgstr "maj"
-#: ../../include/bbcode.php:220
-#, php-format
-msgid "%1$s wrote the following %2$s %3$s"
-msgstr "%1$s skrev följande %2$s %3$s"
+#: ../../include/text.php:1125
+msgid "June"
+msgstr "juni"
-#: ../../include/bbcode.php:222
-msgid "post"
-msgstr "post"
+#: ../../include/text.php:1125
+msgid "July"
+msgstr "juli"
-#: ../../include/bbcode.php:623
-msgid "$1 spoiler"
-msgstr "$1 spoiler"
+#: ../../include/text.php:1125
+msgid "August"
+msgstr "augusti"
-#: ../../include/bbcode.php:643
-msgid "$1 wrote:"
-msgstr "$1 skrev:"
+#: ../../include/text.php:1125
+msgid "September"
+msgstr "september"
-#: ../../include/datetime.php:43 ../../include/datetime.php:45
-msgid "Miscellaneous"
-msgstr "Övrigt"
+#: ../../include/text.php:1125
+msgid "October"
+msgstr "oktober"
-#: ../../include/datetime.php:142
-msgid "YYYY-MM-DD or MM-DD"
-msgstr "ÅÅÅÅ-MM-DD eller MM-DD"
+#: ../../include/text.php:1125
+msgid "November"
+msgstr "november"
-#: ../../include/datetime.php:259
-msgid "never"
-msgstr "aldrig"
+#: ../../include/text.php:1125
+msgid "December"
+msgstr "december"
-#: ../../include/datetime.php:265
-msgid "less than a second ago"
-msgstr "mindre än en sekund sedan"
+#: ../../include/text.php:1203
+msgid "unknown.???"
+msgstr "okänt.???"
-#: ../../include/datetime.php:268
-msgid "year"
-msgstr "år"
+#: ../../include/text.php:1204
+msgid "bytes"
+msgstr "byte"
-#: ../../include/datetime.php:268
-msgid "years"
-msgstr "år"
+#: ../../include/text.php:1240
+msgid "remove category"
+msgstr "ta bort kategori"
-#: ../../include/datetime.php:269
-msgid "month"
-msgstr "månad"
+#: ../../include/text.php:1309
+msgid "remove from file"
+msgstr "ta bort från fil"
-#: ../../include/datetime.php:269
-msgid "months"
-msgstr "månader"
+#: ../../include/text.php:1385 ../../include/text.php:1396
+msgid "Click to open/close"
+msgstr "Klicka för att öppna/stänga"
-#: ../../include/datetime.php:270
-msgid "week"
-msgstr "vecka"
+#: ../../include/text.php:1544 ../../mod/events.php:414
+msgid "Link to Source"
+msgstr "Länk till källa"
-#: ../../include/datetime.php:270
-msgid "weeks"
-msgstr "veckor"
+#: ../../include/text.php:1563
+msgid "Select a page layout: "
+msgstr "Välj en sidlayout: "
-#: ../../include/datetime.php:271
-msgid "day"
-msgstr "dag"
+#: ../../include/text.php:1566 ../../include/text.php:1626
+msgid "default"
+msgstr "standard"
-#: ../../include/datetime.php:271
-msgid "days"
-msgstr "dagar"
+#: ../../include/text.php:1599
+msgid "Page content type: "
+msgstr "Typ av sidinnehåll: "
-#: ../../include/datetime.php:272
-msgid "hour"
-msgstr "timme"
+#: ../../include/text.php:1638
+msgid "Select an alternate language"
+msgstr "Välj ett alternativt språk"
-#: ../../include/datetime.php:272
-msgid "hours"
-msgstr "timmar"
+#: ../../include/text.php:1757 ../../include/conversation.php:120
+#: ../../include/diaspora.php:1928 ../../mod/subthread.php:72
+#: ../../mod/subthread.php:174 ../../mod/like.php:290 ../../mod/tagger.php:45
+msgid "photo"
+msgstr "foto"
-#: ../../include/datetime.php:273
-msgid "minute"
-msgstr "minut"
+#: ../../include/text.php:1760 ../../include/conversation.php:123
+#: ../../mod/tagger.php:49
+msgid "event"
+msgstr "händelse"
-#: ../../include/datetime.php:273
-msgid "minutes"
-msgstr "minuter"
+#: ../../include/text.php:1763 ../../include/conversation.php:148
+#: ../../include/diaspora.php:1928 ../../mod/subthread.php:72
+#: ../../mod/subthread.php:174 ../../mod/like.php:290 ../../mod/tagger.php:53
+msgid "status"
+msgstr "status"
-#: ../../include/datetime.php:274
-msgid "second"
-msgstr "sekund"
+#: ../../include/text.php:1765 ../../include/conversation.php:150
+#: ../../mod/tagger.php:55
+msgid "comment"
+msgstr "kommentar"
-#: ../../include/datetime.php:274
-msgid "seconds"
-msgstr "sekunder"
+#: ../../include/text.php:1770
+msgid "activity"
+msgstr "aktivitet"
-#: ../../include/datetime.php:283
-#, php-format
-msgid "%1$d %2$s ago"
-msgstr "%1$d %2$s sedan"
+#: ../../include/text.php:2057
+msgid "Design"
+msgstr "Design"
-#: ../../include/datetime.php:491
-#, php-format
-msgid "%1$s's birthday"
-msgstr "%1$ss födelsedag"
+#: ../../include/text.php:2060
+msgid "Blocks"
+msgstr "Block"
-#: ../../include/datetime.php:492
-#, php-format
-msgid "Happy Birthday %1$s"
-msgstr "Grattis på födelsedagen %1$s"
+#: ../../include/text.php:2061
+msgid "Menus"
+msgstr "Menyer"
-#: ../../include/zot.php:664
-msgid "Invalid data packet"
-msgstr "Ogiltigt datapaket"
+#: ../../include/text.php:2062
+msgid "Layouts"
+msgstr "Layouter"
-#: ../../include/zot.php:680
-msgid "Unable to verify channel signature"
-msgstr "Kunde inte bekräfta kanalsignatur"
+#: ../../include/text.php:2063
+msgid "Pages"
+msgstr "Sidor"
-#: ../../include/zot.php:1818
+#: ../../include/contact_widgets.php:14
#, php-format
-msgid "Unable to verify site signature for %s"
-msgstr "Kunde inte bekräfta signatur för servern %s"
-
-#: ../../include/taxonomy.php:210
-msgid "Tags"
-msgstr "Taggar"
-
-#: ../../include/taxonomy.php:249
-msgid "Keywords"
-msgstr "Nyckelord"
-
-#: ../../include/taxonomy.php:274
-msgid "have"
-msgstr "har"
-
-#: ../../include/taxonomy.php:274
-msgid "has"
-msgstr "har"
-
-#: ../../include/taxonomy.php:275
-msgid "want"
-msgstr "vill ha"
-
-#: ../../include/taxonomy.php:275
-msgid "wants"
-msgstr "vill ha"
+msgid "%d invitation available"
+msgid_plural "%d invitations available"
+msgstr[0] "%d inbjudan tillgänglig"
+msgstr[1] "%d inbjudningar tillgängliga"
-#: ../../include/taxonomy.php:276 ../../include/ItemObject.php:221
-msgid "like"
-msgstr "gilla"
+#: ../../include/contact_widgets.php:19 ../../mod/admin.php:416
+msgid "Advanced"
+msgstr "Avancerat"
-#: ../../include/taxonomy.php:276
-msgid "likes"
-msgstr "gillar"
+#: ../../include/contact_widgets.php:22
+msgid "Find Channels"
+msgstr "Hitta kanaler"
-#: ../../include/taxonomy.php:277 ../../include/ItemObject.php:222
-msgid "dislike"
-msgstr "ogilla"
+#: ../../include/contact_widgets.php:23
+msgid "Enter name or interest"
+msgstr "Ange namn eller intresse"
-#: ../../include/taxonomy.php:277
-msgid "dislikes"
-msgstr "ogillar"
+#: ../../include/contact_widgets.php:24
+msgid "Connect/Follow"
+msgstr "Ta kontakt/följ"
-#: ../../include/api.php:1084
-msgid "Public Timeline"
-msgstr "Offentlig tidslinje"
+#: ../../include/contact_widgets.php:25
+msgid "Examples: Robert Morgenstein, Fishing"
+msgstr "Exempel: Robert Morgenstein, Fiske"
-#: ../../include/dir_fns.php:56
-msgid "Directory Options"
-msgstr "Katalogalternativ"
+#: ../../include/contact_widgets.php:26 ../../mod/connections.php:412
+#: ../../mod/directory.php:317 ../../mod/directory.php:322
+msgid "Find"
+msgstr "Sök"
-#: ../../include/dir_fns.php:57
-msgid "Alphabetic"
-msgstr "Alfabetisk"
+#: ../../include/contact_widgets.php:27 ../../mod/suggest.php:59
+#: ../../mod/directory.php:321
+msgid "Channel Suggestions"
+msgstr "Kanalförslag"
-#: ../../include/dir_fns.php:58
-msgid "Reverse Alphabetic"
-msgstr "Omvänd alfabetisk"
+#: ../../include/contact_widgets.php:29
+msgid "Random Profile"
+msgstr "Slumpvald profil"
-#: ../../include/dir_fns.php:59
-msgid "Newest to Oldest"
-msgstr "Nyast till äldst"
+#: ../../include/contact_widgets.php:30
+msgid "Invite Friends"
+msgstr "Bjud in vänner"
-#: ../../include/dir_fns.php:60
-msgid "Public Forums Only"
-msgstr "Endast offentliga forum"
+#: ../../include/contact_widgets.php:32
+msgid "Advanced example: name=fred and country=iceland"
+msgstr "Avancerat exempel: name=fred and country=iceland"
-#: ../../include/dir_fns.php:72
-msgid "Enable Safe Search"
-msgstr "Aktivera säker sökning"
+#: ../../include/contact_widgets.php:60 ../../include/contact_widgets.php:95
+#: ../../include/widgets.php:305
+msgid "Everything"
+msgstr "Allt"
-#: ../../include/dir_fns.php:74
-msgid "Disable Safe Search"
-msgstr "Avaktivera säker sökning"
+#: ../../include/contact_widgets.php:125
+#, php-format
+msgid "%d connection in common"
+msgid_plural "%d connections in common"
+msgstr[0] "%d gemensam kontakt"
+msgstr[1] "%d gemensamma kontakter"
-#: ../../include/dir_fns.php:76
-msgid "Safe Mode"
-msgstr "Säkert läge"
+#: ../../include/contact_widgets.php:130
+msgid "show more"
+msgstr "visa fler"
#: ../../include/enotify.php:41
msgid "Red Matrix Notification"
@@ -2021,897 +1630,968 @@ msgstr "Kanaler inte i någon krets"
msgid "add"
msgstr "lägg till"
-#: ../../include/features.php:23
-msgid "General Features"
-msgstr "Allmänna funktioner"
+#: ../../include/identity.php:31 ../../mod/item.php:1112
+msgid "Unable to obtain identity information from database"
+msgstr "Kunde inte hämta från databasen"
-#: ../../include/features.php:25
-msgid "Content Expiration"
-msgstr "Tidsbegränsat innehåll"
+#: ../../include/identity.php:66
+msgid "Empty name"
+msgstr "Tomt namn"
-#: ../../include/features.php:25
-msgid "Remove posts/comments and/or private messages at a future time"
-msgstr "Ta bort inlägg/kommentarer och/eller privata meddelanden efter en tid"
+#: ../../include/identity.php:68
+msgid "Name too long"
+msgstr "För långt namn"
-#: ../../include/features.php:26
-msgid "Multiple Profiles"
-msgstr "Flera profiler"
+#: ../../include/identity.php:169
+msgid "No account identifier"
+msgstr "Ingen kontoidentifierare"
-#: ../../include/features.php:26
-msgid "Ability to create multiple profiles"
-msgstr "Möjlighet att skapa flera profiler"
+#: ../../include/identity.php:182
+msgid "Nickname is required."
+msgstr "Smeknamn måste anges."
-#: ../../include/features.php:27
-msgid "Advanced Profiles"
-msgstr "Avancerade profiler"
+#: ../../include/identity.php:196
+msgid "Reserved nickname. Please choose another."
+msgstr "Reserverat smeknamn. Välj ett annat."
-#: ../../include/features.php:27
-msgid "Additional profile sections and selections"
-msgstr "Fler profilinställningar"
+#: ../../include/identity.php:201 ../../include/dimport.php:34
+msgid ""
+"Nickname has unsupported characters or is already being used on this site."
+msgstr "Smeknamnet innehåller otillåtna tecken eller är redan upptaget på den här servern."
-#: ../../include/features.php:28
-msgid "Profile Import/Export"
-msgstr "Profilimport/-export"
+#: ../../include/identity.php:283
+msgid "Unable to retrieve created identity"
+msgstr "Kunde inte hämta den skapade identiteten"
-#: ../../include/features.php:28
-msgid "Save and load profile details across sites/channels"
-msgstr "Spara och ladda profiluppgifter mellan webbplatser/kanaler"
+#: ../../include/identity.php:343
+msgid "Default Profile"
+msgstr "Standardprofil"
-#: ../../include/features.php:29
-msgid "Web Pages"
-msgstr "Webbsidor"
+#: ../../include/identity.php:387 ../../include/identity.php:388
+#: ../../include/identity.php:395 ../../include/widgets.php:428
+#: ../../include/profile_selectors.php:80 ../../mod/settings.php:320
+#: ../../mod/settings.php:324 ../../mod/settings.php:325
+#: ../../mod/settings.php:328 ../../mod/settings.php:339
+#: ../../mod/connedit.php:510
+msgid "Friends"
+msgstr "Vänner"
-#: ../../include/features.php:29
-msgid "Provide managed web pages on your channel"
-msgstr "Tillhandahåll ordnade webbsidor i din kanal"
+#: ../../include/identity.php:643
+msgid "Requested channel is not available."
+msgstr "Den begärda kanalen är inte tillgänglig"
-#: ../../include/features.php:30
-msgid "Private Notes"
-msgstr "Privata anteckningar"
+#: ../../include/identity.php:691 ../../mod/achievements.php:11
+#: ../../mod/profile.php:16 ../../mod/webpages.php:29 ../../mod/blocks.php:29
+#: ../../mod/editblock.php:29 ../../mod/editlayout.php:28
+#: ../../mod/editwebpage.php:28 ../../mod/filestorage.php:48
+#: ../../mod/connect.php:13 ../../mod/layouts.php:29 ../../mod/hcard.php:8
+msgid "Requested profile is not available."
+msgstr "Begärd profil är inte tillgänglig."
-#: ../../include/features.php:30
-msgid "Enables a tool to store notes and reminders"
-msgstr "Aktivera ett verktyg för att spara anteckningar och påminnelser"
+#: ../../include/identity.php:840 ../../include/conversation.php:937
+#: ../../include/widgets.php:136 ../../include/widgets.php:175
+#: ../../include/Contact.php:107 ../../mod/suggest.php:51
+#: ../../mod/match.php:62 ../../mod/directory.php:264
+msgid "Connect"
+msgstr "Ta kontakt"
-#: ../../include/features.php:34
-msgid "Navigation Channel Select"
-msgstr "Kanalväljare i navigation"
+#: ../../include/identity.php:854 ../../mod/profiles.php:740
+msgid "Change profile photo"
+msgstr "Bytprofilfoto"
-#: ../../include/features.php:34
-msgid "Change channels directly from within the navigation dropdown menu"
-msgstr "Välj kanal direkt från navigationslistens rullgardinsmeny"
+#: ../../include/identity.php:860
+msgid "Profiles"
+msgstr "Profiler"
-#: ../../include/features.php:38
-msgid "Extended Identity Sharing"
-msgstr "Utökad identitetsdelning"
+#: ../../include/identity.php:860
+msgid "Manage/edit profiles"
+msgstr "Hantera/redigera profiler"
-#: ../../include/features.php:38
-msgid ""
-"Share your identity with all websites on the internet. When disabled, "
-"identity is only shared with sites in the matrix."
-msgstr "Dela din identitet med alla webbplatser på Internet. Om inaktiverat är identiteten bara delad med platser i matrisen."
+#: ../../include/identity.php:861 ../../mod/profiles.php:741
+msgid "Create New Profile"
+msgstr "Skapa ny profil"
-#: ../../include/features.php:39
-msgid "Expert Mode"
-msgstr "Expertläge"
+#: ../../include/identity.php:864 ../../include/nav.php:103
+msgid "Edit Profile"
+msgstr "Redigera profil"
-#: ../../include/features.php:39
-msgid "Enable Expert Mode to provide advanced configuration options"
-msgstr "Aktivera expertläge för att tillåta avancerade inställningar"
+#: ../../include/identity.php:875 ../../mod/profiles.php:752
+msgid "Profile Image"
+msgstr "Profilbild"
-#: ../../include/features.php:40
-msgid "Premium Channel"
-msgstr "Premiumkanal"
+#: ../../include/identity.php:878
+msgid "visible to everybody"
+msgstr "synlig för alla"
-#: ../../include/features.php:40
-msgid ""
-"Allows you to set restrictions and terms on those that connect with your "
-"channel"
-msgstr "Låter dig ange begränsningar och villkor för dem som vill ansluta till din kanal"
+#: ../../include/identity.php:879 ../../mod/profiles.php:635
+#: ../../mod/profiles.php:756
+msgid "Edit visibility"
+msgstr "Redigera synlighet"
-#: ../../include/features.php:45
-msgid "Post Composition Features"
-msgstr "Skrivfunktioner"
+#: ../../include/identity.php:895 ../../include/identity.php:1132
+msgid "Gender:"
+msgstr "Kön:"
-#: ../../include/features.php:47
-msgid "Use Markdown"
-msgstr "Använd Markdown"
+#: ../../include/identity.php:896 ../../include/identity.php:1176
+msgid "Status:"
+msgstr "Status:"
-#: ../../include/features.php:47
-msgid "Allow use of \"Markdown\" to format posts"
-msgstr "Tillåt att \"Markdown\" används för att formatera inlägg"
+#: ../../include/identity.php:897 ../../include/identity.php:1187
+msgid "Homepage:"
+msgstr "Hemsida:"
-#: ../../include/features.php:48
-msgid "Post Preview"
-msgstr "Förhandsgranskning"
+#: ../../include/identity.php:898
+msgid "Online Now"
+msgstr "Online nu"
-#: ../../include/features.php:48
-msgid "Allow previewing posts and comments before publishing them"
-msgstr "Tillåt förhandsgranskning av inlägg och kommentarer innan de publiceras"
+#: ../../include/identity.php:976 ../../include/identity.php:1056
+#: ../../mod/ping.php:326
+msgid "g A l F d"
+msgstr "l j F \\k\\l G"
-#: ../../include/features.php:49 ../../include/widgets.php:537
-#: ../../mod/sources.php:88
-msgid "Channel Sources"
-msgstr "Kanalkällor"
+#: ../../include/identity.php:977 ../../include/identity.php:1057
+msgid "F d"
+msgstr "j F"
-#: ../../include/features.php:49
-msgid "Automatically import channel content from other channels or feeds"
-msgstr "Importera kanalinnehåll från andra kanaler eller flöden automatiskt"
+#: ../../include/identity.php:1022 ../../include/identity.php:1097
+#: ../../mod/ping.php:348
+msgid "[today]"
+msgstr "[i dag]"
-#: ../../include/features.php:50
-msgid "Even More Encryption"
-msgstr "Ytterligare kryptering"
+#: ../../include/identity.php:1034
+msgid "Birthday Reminders"
+msgstr "Födelsedagspåminnelser"
-#: ../../include/features.php:50
-msgid ""
-"Allow optional encryption of content end-to-end with a shared secret key"
-msgstr "Tillåt änd-till-änd-kryptering av innehåll med en delad hemlig nyckel"
+#: ../../include/identity.php:1035
+msgid "Birthdays this week:"
+msgstr "Födelsedagar den här veckan:"
-#: ../../include/features.php:51
-msgid "Flag Adult Photos"
-msgstr "Flagga vuxenfoton"
+#: ../../include/identity.php:1090
+msgid "[No description]"
+msgstr "[Ingen beskrivning]"
-#: ../../include/features.php:51
-msgid "Provide photo edit option to hide adult photos from default album view"
-msgstr "Gör det möjligt att inte visa foton som är olämpliga för barn i albums standardvy"
+#: ../../include/identity.php:1108
+msgid "Event Reminders"
+msgstr "Händelsepåminnelser"
-#: ../../include/features.php:56
-msgid "Network and Stream Filtering"
-msgstr "Nätverk och strömfiltrering"
+#: ../../include/identity.php:1109
+msgid "Events this week:"
+msgstr "Händelser den här veckan:"
-#: ../../include/features.php:57
-msgid "Search by Date"
-msgstr "Sök på datum"
+#: ../../include/identity.php:1122 ../../include/identity.php:1251
+#: ../../include/apps.php:138 ../../mod/profperm.php:112
+msgid "Profile"
+msgstr "Profil"
-#: ../../include/features.php:57
-msgid "Ability to select posts by date ranges"
-msgstr "Tillåter urval av inlägg baserat på datum"
+#: ../../include/identity.php:1130 ../../mod/settings.php:1012
+msgid "Full Name:"
+msgstr "Fullständigt namn:"
-#: ../../include/features.php:58
-msgid "Collections Filter"
-msgstr "Kretsfilter"
+#: ../../include/identity.php:1137
+msgid "Like this channel"
+msgstr "Gilla den här kanalen"
-#: ../../include/features.php:58
-msgid "Enable widget to display Network posts only from selected collections"
-msgstr "Aktivera en väljare för att visa nätverksinlägg från enbart valda kretsar"
+#: ../../include/identity.php:1161
+msgid "j F, Y"
+msgstr "j F Y"
-#: ../../include/features.php:59 ../../include/widgets.php:272
-msgid "Saved Searches"
-msgstr "Sparade sökningar"
+#: ../../include/identity.php:1162
+msgid "j F"
+msgstr "j F"
-#: ../../include/features.php:59
-msgid "Save search terms for re-use"
-msgstr "Spara sökuttryck för återanvändning"
+#: ../../include/identity.php:1169
+msgid "Birthday:"
+msgstr "Födelsedag:"
-#: ../../include/features.php:60
-msgid "Network Personal Tab"
-msgstr "Personlig nätverksflik"
+#: ../../include/identity.php:1173
+msgid "Age:"
+msgstr "Ålder:"
-#: ../../include/features.php:60
-msgid "Enable tab to display only Network posts that you've interacted on"
-msgstr "Aktivera en flik som visar endast de nätverksinlägg som du har deltagit i"
+#: ../../include/identity.php:1182
+#, php-format
+msgid "for %1$d %2$s"
+msgstr "i %1$d %2$s"
-#: ../../include/features.php:61
-msgid "Network New Tab"
-msgstr "Flik för nytt på nätverket"
+#: ../../include/identity.php:1185 ../../mod/profiles.php:657
+msgid "Sexual Preference:"
+msgstr "Sexuell preferens:"
-#: ../../include/features.php:61
-msgid "Enable tab to display all new Network activity"
-msgstr "Aktivera en flik som visar all ny nätverksaktivitet"
+#: ../../include/identity.php:1189 ../../mod/profiles.php:659
+msgid "Hometown:"
+msgstr "Hemort:"
-#: ../../include/features.php:62
-msgid "Affinity Tool"
-msgstr "Samhörighetsverktyg"
+#: ../../include/identity.php:1191
+msgid "Tags:"
+msgstr "Taggar:"
-#: ../../include/features.php:62
-msgid "Filter stream activity by depth of relationships"
-msgstr "Filtrera strömaktivitet efter hur nära relationen är"
+#: ../../include/identity.php:1193 ../../mod/profiles.php:660
+msgid "Political Views:"
+msgstr "Politisk åskådning:"
-#: ../../include/features.php:63
-msgid "Suggest Channels"
-msgstr "Föreslå kanaler"
+#: ../../include/identity.php:1195
+msgid "Religion:"
+msgstr "Religion:"
-#: ../../include/features.php:63
-msgid "Show channel suggestions"
-msgstr "Visa förslag på kanaler"
+#: ../../include/identity.php:1197
+msgid "About:"
+msgstr "Om:"
-#: ../../include/features.php:68
-msgid "Post/Comment Tools"
-msgstr "Inläggs-/kommentarsverktyg"
+#: ../../include/identity.php:1199
+msgid "Hobbies/Interests:"
+msgstr "Fritidssysselsättning/intressen:"
-#: ../../include/features.php:70
-msgid "Edit Sent Posts"
-msgstr "Redigera sända inlägg"
+#: ../../include/identity.php:1201 ../../mod/profiles.php:663
+msgid "Likes:"
+msgstr "Gillar:"
-#: ../../include/features.php:70
-msgid "Edit and correct posts and comments after sending"
-msgstr "Redigera och korrigera inlägg och kommentarer efter att de skickats"
+#: ../../include/identity.php:1203 ../../mod/profiles.php:664
+msgid "Dislikes:"
+msgstr "Ogillar:"
-#: ../../include/features.php:71
-msgid "Tagging"
-msgstr "Taggning"
+#: ../../include/identity.php:1206
+msgid "Contact information and Social Networks:"
+msgstr "Kontaktinformation och sociala nätverk:"
-#: ../../include/features.php:71
-msgid "Ability to tag existing posts"
-msgstr "Möjlighet att tagga befintliga inlägg"
+#: ../../include/identity.php:1218
+msgid "My other channels:"
+msgstr "Mina andra kanaler:"
-#: ../../include/features.php:72
-msgid "Post Categories"
-msgstr "Inläggskategorier"
+#: ../../include/identity.php:1221
+msgid "Musical interests:"
+msgstr "Musikintressen:"
-#: ../../include/features.php:72
-msgid "Add categories to your posts"
-msgstr "Lägg till kategorier till dina inlägg"
+#: ../../include/identity.php:1223
+msgid "Books, literature:"
+msgstr "Böcker, litteratur:"
-#: ../../include/features.php:73
-msgid "Ability to file posts under folders"
-msgstr "Möjlighet att lägga inlägg i mappar"
+#: ../../include/identity.php:1225
+msgid "Television:"
+msgstr "Tv:"
-#: ../../include/features.php:74
-msgid "Dislike Posts"
-msgstr "Ogilla inlägg"
+#: ../../include/identity.php:1227
+msgid "Film/dance/culture/entertainment:"
+msgstr "Film/dans/kultur/underhållning:"
-#: ../../include/features.php:74
-msgid "Ability to dislike posts/comments"
-msgstr "Möjlighet att ogilla inlägg/kommentarer"
+#: ../../include/identity.php:1229
+msgid "Love/Romance:"
+msgstr "Kärlek/romantik:"
-#: ../../include/features.php:75
-msgid "Star Posts"
-msgstr "Märk inlägg"
+#: ../../include/identity.php:1231
+msgid "Work/employment:"
+msgstr "Arbete/sysselsättning:"
-#: ../../include/features.php:75
-msgid "Ability to mark special posts with a star indicator"
-msgstr "Möjlighet att märka speciella inlägg med en stjärna"
+#: ../../include/identity.php:1233
+msgid "School/education:"
+msgstr "Skola/utbildning:"
-#: ../../include/features.php:76
-msgid "Tag Cloud"
-msgstr "Taggmoln"
+#: ../../include/identity.php:1253
+msgid "Like this thing"
+msgstr "Gilla den här saken"
-#: ../../include/features.php:76
-msgid "Provide a personal tag cloud on your channel page"
-msgstr "Tillhandahåll ett personligt taggmoln på din kanalsida"
+#: ../../include/account.php:23
+msgid "Not a valid email address"
+msgstr "Inte en giltig e-postadress"
-#: ../../include/text.php:321
-msgid "prev"
-msgstr "föregående"
+#: ../../include/account.php:25
+msgid "Your email domain is not among those allowed on this site"
+msgstr "Din e-postdomän är inte bland de som tillåts på den här servern"
-#: ../../include/text.php:323
-msgid "first"
-msgstr "första"
+#: ../../include/account.php:31
+msgid "Your email address is already registered at this site."
+msgstr "Din e-postadress är redan registrerad på den här servern."
-#: ../../include/text.php:352
-msgid "last"
-msgstr "sista"
+#: ../../include/account.php:64
+msgid "An invitation is required."
+msgstr "En inbjudan behövs."
-#: ../../include/text.php:355
-msgid "next"
-msgstr "nästa"
+#: ../../include/account.php:68
+msgid "Invitation could not be verified."
+msgstr "Inbjudningen kunde inte bekräftas."
-#: ../../include/text.php:367
-msgid "older"
-msgstr "äldre"
+#: ../../include/account.php:119
+msgid "Please enter the required information."
+msgstr "Ange den begärda informationen."
-#: ../../include/text.php:369
-msgid "newer"
-msgstr "nyare"
+#: ../../include/account.php:187
+msgid "Failed to store account information."
+msgstr "Misslyckades att spara kontoinformation."
-#: ../../include/text.php:736
-msgid "No connections"
-msgstr "Inga kontakter"
+#: ../../include/account.php:245
+#, php-format
+msgid "Registration confirmation for %s"
+msgstr "Registreringsbekräftelse för %s"
-#: ../../include/text.php:753
+#: ../../include/account.php:313
#, php-format
-msgid "%d Connection"
-msgid_plural "%d Connections"
-msgstr[0] "%d kontakt"
-msgstr[1] "%d kontakter"
+msgid "Registration request at %s"
+msgstr "Registreringsförfrågan på %s"
-#: ../../include/text.php:766
-msgid "View Connections"
-msgstr "Visa kontakter"
+#: ../../include/account.php:315 ../../include/account.php:342
+#: ../../include/account.php:399
+msgid "Administrator"
+msgstr "Administratör"
-#: ../../include/text.php:827 ../../include/text.php:839
-#: ../../include/widgets.php:193 ../../mod/filer.php:50
-#: ../../mod/rbmark.php:28 ../../mod/rbmark.php:98 ../../mod/admin.php:1339
-#: ../../mod/admin.php:1360
-msgid "Save"
-msgstr "Spara"
+#: ../../include/account.php:337
+msgid "your registration password"
+msgstr "ditt registreringslösenord"
-#: ../../include/text.php:905
-msgid "poke"
-msgstr "puffa"
+#: ../../include/account.php:340 ../../include/account.php:397
+#, php-format
+msgid "Registration details for %s"
+msgstr "Registreringsdetaljer för %s"
-#: ../../include/text.php:906
-msgid "ping"
-msgstr "pinga"
+#: ../../include/account.php:406
+msgid "Account approved."
+msgstr "Konto godkänt."
-#: ../../include/text.php:906
-msgid "pinged"
-msgstr "pingade"
+#: ../../include/account.php:440
+#, php-format
+msgid "Registration revoked for %s"
+msgstr "Registrering avslagen för %s"
-#: ../../include/text.php:907
-msgid "prod"
-msgstr "stöt till"
+#: ../../include/account.php:486
+msgid "Account verified. Please login."
+msgstr "Konto bekräftat. Du kan nu logga in."
-#: ../../include/text.php:907
-msgid "prodded"
-msgstr "stötte till"
+#: ../../include/account.php:648 ../../include/account.php:650
+msgid "Click here to upgrade."
+msgstr "Klicka här för att uppgradera."
-#: ../../include/text.php:908
-msgid "slap"
-msgstr "daska till"
+#: ../../include/account.php:656
+msgid "This action exceeds the limits set by your subscription plan."
+msgstr "Den här funktionen går utanför vad som anges i ditt avtal."
-#: ../../include/text.php:908
-msgid "slapped"
-msgstr "daskade till"
+#: ../../include/account.php:661
+msgid "This action is not available under your subscription plan."
+msgstr "Den här funktionen är inte tillgänglig med ditt avtal."
-#: ../../include/text.php:909
-msgid "finger"
-msgstr "fingra på"
+#: ../../include/follow.php:28
+msgid "Channel is blocked on this site."
+msgstr "Kanalen är blockerad på den här servern."
-#: ../../include/text.php:909
-msgid "fingered"
-msgstr "fingrade på"
+#: ../../include/follow.php:33
+msgid "Channel location missing."
+msgstr "Kanalplats saknas."
-#: ../../include/text.php:910
-msgid "rebuff"
-msgstr "stöt tillbaka"
+#: ../../include/follow.php:82
+msgid "Response from remote channel was incomplete."
+msgstr "Svar från den andra kanalen var ofullständigt."
-#: ../../include/text.php:910
-msgid "rebuffed"
-msgstr "stötte tillbaks"
+#: ../../include/follow.php:99
+msgid "Channel was deleted and no longer exists."
+msgstr "Kanalen har tagits bort och finns inte längre."
-#: ../../include/text.php:919
-msgid "happy"
-msgstr "glad"
+#: ../../include/follow.php:135 ../../include/follow.php:202
+msgid "Protocol disabled."
+msgstr "Protokoll inaktiverat."
-#: ../../include/text.php:920
-msgid "sad"
-msgstr "ledsen"
+#: ../../include/follow.php:176
+msgid "Channel discovery failed."
+msgstr "Kanalsökning misslyckades."
-#: ../../include/text.php:921
-msgid "mellow"
-msgstr "lugn"
+#: ../../include/follow.php:192
+msgid "local account not found."
+msgstr "hittade inte lokalt konto."
-#: ../../include/text.php:922
-msgid "tired"
-msgstr "trött"
+#: ../../include/follow.php:220
+msgid "Cannot connect to yourself."
+msgstr "Du kan inte kontakta dig själv."
-#: ../../include/text.php:923
-msgid "perky"
-msgstr "uppåt"
+#: ../../include/api.php:1084
+msgid "Public Timeline"
+msgstr "Offentlig tidslinje"
-#: ../../include/text.php:924
-msgid "angry"
-msgstr "arg"
+#: ../../include/attach.php:221 ../../include/attach.php:275
+msgid "Item was not found."
+msgstr "Posten hittades inte."
-#: ../../include/text.php:925
-msgid "stupified"
-msgstr "virrig"
+#: ../../include/attach.php:331
+msgid "No source file."
+msgstr "Ingen källfil."
-#: ../../include/text.php:926
-msgid "puzzled"
-msgstr "förbryllad"
+#: ../../include/attach.php:348
+msgid "Cannot locate file to replace"
+msgstr "Kan inte hitta fil att ersätta"
-#: ../../include/text.php:927
-msgid "interested"
-msgstr "intresserad"
+#: ../../include/attach.php:366
+msgid "Cannot locate file to revise/update"
+msgstr "Kan inte hitta fil att revidera/uppdatera"
-#: ../../include/text.php:928
-msgid "bitter"
-msgstr "bitter"
+#: ../../include/attach.php:377
+#, php-format
+msgid "File exceeds size limit of %d"
+msgstr "Filen överskrider storleksbegränsningen %d"
-#: ../../include/text.php:929
-msgid "cheerful"
-msgstr "munter"
+#: ../../include/attach.php:389
+#, php-format
+msgid "You have reached your limit of %1$.0f Mbytes attachment storage."
+msgstr "Du har nått begränsningen %1$.0f megabyte utrymme för bilagor."
-#: ../../include/text.php:930
-msgid "alive"
-msgstr "pigg"
+#: ../../include/attach.php:472
+msgid "File upload failed. Possible system limit or action terminated."
+msgstr "Filuppladdning misslyckades. Möjlig systembegränsning eller avbruten åtgärd."
-#: ../../include/text.php:931
-msgid "annoyed"
-msgstr "irriterad"
+#: ../../include/attach.php:484
+msgid "Stored file could not be verified. Upload failed."
+msgstr "Den lagrade filen kunde inte verifieras. Uppladdning misslyckad."
-#: ../../include/text.php:932
-msgid "anxious"
-msgstr "bekymrad"
+#: ../../include/attach.php:526 ../../include/attach.php:543
+msgid "Path not available."
+msgstr "Sökväg inte tillgänglig."
-#: ../../include/text.php:933
-msgid "cranky"
-msgstr "grinig"
+#: ../../include/attach.php:590
+msgid "Empty pathname"
+msgstr "Tom sökväg"
-#: ../../include/text.php:934
-msgid "disturbed"
-msgstr "besvärad"
+#: ../../include/attach.php:606
+msgid "duplicate filename or path"
+msgstr "filnamn eller sökväg finns redan"
-#: ../../include/text.php:935
-msgid "frustrated"
-msgstr "frustrerad"
+#: ../../include/attach.php:630
+msgid "Path not found."
+msgstr "Sökväg hittas inte."
-#: ../../include/text.php:936
-msgid "depressed"
-msgstr "deprimerad"
+#: ../../include/attach.php:681
+msgid "mkdir failed."
+msgstr "mkdir misslyckades."
-#: ../../include/text.php:937
-msgid "motivated"
-msgstr "motiverad"
+#: ../../include/attach.php:685
+msgid "database storage failed."
+msgstr "databaslagring misslyckades."
-#: ../../include/text.php:938
-msgid "relaxed"
-msgstr "avslappnad"
+#: ../../include/chat.php:10
+msgid "Missing room name"
+msgstr "Rumsnamn saknas"
-#: ../../include/text.php:939
-msgid "surprised"
-msgstr "förvånad"
+#: ../../include/chat.php:19
+msgid "Duplicate room name"
+msgstr "Rumsnamnet finns redan"
-#: ../../include/text.php:1103
-msgid "Monday"
-msgstr "måndag"
+#: ../../include/chat.php:68 ../../include/chat.php:76
+msgid "Invalid room specifier."
+msgstr "Ogiltig rumsbeskrivning."
-#: ../../include/text.php:1103
-msgid "Tuesday"
-msgstr "tisdag"
+#: ../../include/chat.php:105
+msgid "Room not found."
+msgstr "Rummet hittades inte."
-#: ../../include/text.php:1103
-msgid "Wednesday"
-msgstr "onsdag"
+#: ../../include/chat.php:126
+msgid "Room is full"
+msgstr "Rummet är fullt"
-#: ../../include/text.php:1103
-msgid "Thursday"
-msgstr "torsdag"
+#: ../../include/bbcode.php:112 ../../include/bbcode.php:677
+#: ../../include/bbcode.php:680 ../../include/bbcode.php:685
+#: ../../include/bbcode.php:688 ../../include/bbcode.php:691
+#: ../../include/bbcode.php:694 ../../include/bbcode.php:699
+#: ../../include/bbcode.php:702 ../../include/bbcode.php:707
+#: ../../include/bbcode.php:710 ../../include/bbcode.php:713
+#: ../../include/bbcode.php:716
+msgid "Image/photo"
+msgstr "Bild/foto"
-#: ../../include/text.php:1103
-msgid "Friday"
-msgstr "fredag"
+#: ../../include/bbcode.php:147 ../../include/bbcode.php:727
+msgid "Encrypted content"
+msgstr "Krypterat innehåll"
-#: ../../include/text.php:1103
-msgid "Saturday"
-msgstr "lördag"
+#: ../../include/bbcode.php:165
+msgid "Install design element: "
+msgstr "Installera designelement: "
-#: ../../include/text.php:1103
-msgid "Sunday"
-msgstr "söndag"
+#: ../../include/bbcode.php:171
+msgid "QR code"
+msgstr "QR-kod"
-#: ../../include/text.php:1107
-msgid "January"
-msgstr "januari"
+#: ../../include/bbcode.php:220
+#, php-format
+msgid "%1$s wrote the following %2$s %3$s"
+msgstr "%1$s skrev följande %2$s %3$s"
-#: ../../include/text.php:1107
-msgid "February"
-msgstr "februari"
+#: ../../include/bbcode.php:222
+msgid "post"
+msgstr "post"
-#: ../../include/text.php:1107
-msgid "March"
-msgstr "mars"
+#: ../../include/bbcode.php:645
+msgid "$1 spoiler"
+msgstr "$1 spoiler"
-#: ../../include/text.php:1107
-msgid "April"
-msgstr "april"
+#: ../../include/bbcode.php:665
+msgid "$1 wrote:"
+msgstr "$1 skrev:"
-#: ../../include/text.php:1107
-msgid "May"
-msgstr "maj"
+#: ../../include/conversation.php:126 ../../mod/like.php:89
+msgid "channel"
+msgstr "kanal"
-#: ../../include/text.php:1107
-msgid "June"
-msgstr "juni"
+#: ../../include/conversation.php:164 ../../include/diaspora.php:1957
+#: ../../mod/like.php:336
+#, php-format
+msgid "%1$s likes %2$s's %3$s"
+msgstr "%1$s gillar %2$ss %3$s"
-#: ../../include/text.php:1107
-msgid "July"
-msgstr "juli"
+#: ../../include/conversation.php:167 ../../mod/like.php:338
+#, php-format
+msgid "%1$s doesn't like %2$s's %3$s"
+msgstr "%1$s gillar inte %2$ss %3$s"
-#: ../../include/text.php:1107
-msgid "August"
-msgstr "augusti"
+#: ../../include/conversation.php:204
+#, php-format
+msgid "%1$s is now connected with %2$s"
+msgstr "%1$s har nu kontakt med %2$s"
-#: ../../include/text.php:1107
-msgid "September"
-msgstr "september"
+#: ../../include/conversation.php:239
+#, php-format
+msgid "%1$s poked %2$s"
+msgstr "%1$s puffade %2$s"
-#: ../../include/text.php:1107
-msgid "October"
-msgstr "oktober"
+#: ../../include/conversation.php:261 ../../mod/mood.php:63
+#, php-format
+msgctxt "mood"
+msgid "%1$s is %2$s"
+msgstr "%1$s är %2$s"
-#: ../../include/text.php:1107
-msgid "November"
-msgstr "november"
+#: ../../include/conversation.php:638 ../../include/ItemObject.php:126
+msgid "Select"
+msgstr "Välj"
-#: ../../include/text.php:1107
-msgid "December"
-msgstr "december"
+#: ../../include/conversation.php:646 ../../include/ItemObject.php:89
+msgid "Private Message"
+msgstr "Privat meddelande"
-#: ../../include/text.php:1185
-msgid "unknown.???"
-msgstr "okänt.???"
+#: ../../include/conversation.php:653 ../../include/ItemObject.php:194
+msgid "Message signature validated"
+msgstr "Meddelandesignatur bekräftad"
-#: ../../include/text.php:1186
-msgid "bytes"
-msgstr "byte"
+#: ../../include/conversation.php:654 ../../include/ItemObject.php:195
+msgid "Message signature incorrect"
+msgstr "Meddelandesignatur felaktig"
-#: ../../include/text.php:1225
-msgid "remove category"
-msgstr "ta bort kategori"
+#: ../../include/conversation.php:674
+#, php-format
+msgid "View %s's profile @ %s"
+msgstr "Visa %ss profil på %s"
-#: ../../include/text.php:1295
-msgid "remove from file"
-msgstr "ta bort från fil"
+#: ../../include/conversation.php:689
+msgid "Categories:"
+msgstr "Kategorier:"
-#: ../../include/text.php:1360 ../../include/text.php:1372
-msgid "Click to open/close"
-msgstr "Klicka för att öppna/stänga"
+#: ../../include/conversation.php:690
+msgid "Filed under:"
+msgstr "Postat under:"
-#: ../../include/text.php:1527 ../../mod/events.php:414
-msgid "Link to Source"
-msgstr "Länk till källa"
+#: ../../include/conversation.php:698 ../../include/ItemObject.php:274
+#, php-format
+msgid " from %s"
+msgstr "från %s"
-#: ../../include/text.php:1546
-msgid "Select a page layout: "
-msgstr "Välj en sidlayout: "
+#: ../../include/conversation.php:701 ../../include/ItemObject.php:277
+#, php-format
+msgid "last edited: %s"
+msgstr "senast redigerat: %s"
-#: ../../include/text.php:1549 ../../include/text.php:1614
-msgid "default"
-msgstr "standard"
+#: ../../include/conversation.php:702 ../../include/ItemObject.php:278
+#, php-format
+msgid "Expires: %s"
+msgstr "Upphör: %s"
-#: ../../include/text.php:1585
-msgid "Page content type: "
-msgstr "Typ av sidinnehåll: "
+#: ../../include/conversation.php:717
+msgid "View in context"
+msgstr "Visa sammanhang"
-#: ../../include/text.php:1626
-msgid "Select an alternate language"
-msgstr "Välj ett alternativt språk"
+#: ../../include/conversation.php:719 ../../include/conversation.php:1142
+#: ../../include/ItemObject.php:325 ../../mod/editpost.php:121
+#: ../../mod/mail.php:238 ../../mod/mail.php:353 ../../mod/photos.php:978
+#: ../../mod/editblock.php:152 ../../mod/editlayout.php:148
+#: ../../mod/editwebpage.php:183
+msgid "Please wait"
+msgstr "Vänta"
-#: ../../include/text.php:1760
-msgid "activity"
-msgstr "aktivitet"
+#: ../../include/conversation.php:835
+msgid "remove"
+msgstr "ta bort"
-#: ../../include/text.php:2046
-msgid "Design"
-msgstr "Design"
+#: ../../include/conversation.php:839 ../../include/nav.php:257
+msgid "Loading..."
+msgstr "Laddar..."
-#: ../../include/text.php:2049
-msgid "Blocks"
-msgstr "Block"
+#: ../../include/conversation.php:840
+msgid "Delete Selected Items"
+msgstr "Ta bort valda poster"
-#: ../../include/text.php:2050
-msgid "Menus"
-msgstr "Menyer"
+#: ../../include/conversation.php:931
+msgid "View Source"
+msgstr "Visa källa"
-#: ../../include/text.php:2051
-msgid "Layouts"
-msgstr "Layouter"
+#: ../../include/conversation.php:932
+msgid "Follow Thread"
+msgstr "Följ tråd"
-#: ../../include/text.php:2052
-msgid "Pages"
-msgstr "Sidor"
+#: ../../include/conversation.php:933
+msgid "View Status"
+msgstr "Visa status"
-#: ../../include/account.php:23
-msgid "Not a valid email address"
-msgstr "Inte en giltig e-postadress"
+#: ../../include/conversation.php:934 ../../include/nav.php:99
+#: ../../mod/connedit.php:429 ../../mod/connedit.php:545
+msgid "View Profile"
+msgstr "Visa profil"
-#: ../../include/account.php:25
-msgid "Your email domain is not among those allowed on this site"
-msgstr "Din e-postdomän är inte bland de som tillåts på den här servern"
+#: ../../include/conversation.php:935
+msgid "View Photos"
+msgstr "Visa foton"
-#: ../../include/account.php:31
-msgid "Your email address is already registered at this site."
-msgstr "Din e-postadress är redan registrerad på den här servern."
+#: ../../include/conversation.php:936
+msgid "Matrix Activity"
+msgstr "Matrisaktivitet"
-#: ../../include/account.php:64
-msgid "An invitation is required."
-msgstr "En inbjudan behövs."
+#: ../../include/conversation.php:938
+msgid "Edit Contact"
+msgstr "Redigera kontakt"
-#: ../../include/account.php:68
-msgid "Invitation could not be verified."
-msgstr "Inbjudningen kunde inte bekräftas."
+#: ../../include/conversation.php:939
+msgid "Send PM"
+msgstr "Skicka meddelande"
-#: ../../include/account.php:119
-msgid "Please enter the required information."
-msgstr "Ange den begärda informationen."
+#: ../../include/conversation.php:940 ../../include/apps.php:145
+msgid "Poke"
+msgstr "Puffa"
-#: ../../include/account.php:187
-msgid "Failed to store account information."
-msgstr "Misslyckades att spara kontoinformation."
+#: ../../include/conversation.php:1013
+#, php-format
+msgid "%s likes this."
+msgstr "%s gillar det här."
-#: ../../include/account.php:245
+#: ../../include/conversation.php:1013
#, php-format
-msgid "Registration confirmation for %s"
-msgstr "Registreringsbekräftelse för %s"
+msgid "%s doesn't like this."
+msgstr "%s gillar inte det här."
-#: ../../include/account.php:313
+#: ../../include/conversation.php:1017
#, php-format
-msgid "Registration request at %s"
-msgstr "Registreringsförfrågan på %s"
+msgid "<span %1$s>%2$d people</span> like this."
+msgid_plural "<span %1$s>%2$d people</span> like this."
+msgstr[0] "<span %1$s>%2$d person</span> gillar det här."
+msgstr[1] "<span %1$s>%2$d personer</span> gillar det här."
-#: ../../include/account.php:315 ../../include/account.php:342
-#: ../../include/account.php:399
-msgid "Administrator"
-msgstr "Administratör"
+#: ../../include/conversation.php:1019
+#, php-format
+msgid "<span %1$s>%2$d people</span> don't like this."
+msgid_plural "<span %1$s>%2$d people</span> don't like this."
+msgstr[0] "<span %1$s>%2$d person</span> gillar inte det här."
+msgstr[1] "<span %1$s>%2$d personer</span> gillar inte det här."
-#: ../../include/account.php:337
-msgid "your registration password"
-msgstr "ditt registreringslösenord"
+#: ../../include/conversation.php:1025
+msgid "and"
+msgstr "och"
-#: ../../include/account.php:340 ../../include/account.php:397
+#: ../../include/conversation.php:1028
#, php-format
-msgid "Registration details for %s"
-msgstr "Registreringsdetaljer för %s"
+msgid ", and %d other people"
+msgid_plural ", and %d other people"
+msgstr[0] ", och %d annan person"
+msgstr[1] ", och %d andra personer"
-#: ../../include/account.php:406
-msgid "Account approved."
-msgstr "Konto godkänt."
+#: ../../include/conversation.php:1029
+#, php-format
+msgid "%s like this."
+msgstr "%s gillar det här."
-#: ../../include/account.php:440
+#: ../../include/conversation.php:1029
#, php-format
-msgid "Registration revoked for %s"
-msgstr "Registrering avslagen för %s"
+msgid "%s don't like this."
+msgstr "%s gillar inte det här."
-#: ../../include/account.php:486
-msgid "Account verified. Please login."
-msgstr "Konto bekräftat. Du kan nu logga in."
+#: ../../include/conversation.php:1086
+msgid "Visible to <strong>everybody</strong>"
+msgstr "Kan ses av <strong>alla</strong>"
-#: ../../include/account.php:648 ../../include/account.php:650
-msgid "Click here to upgrade."
-msgstr "Klicka här för att uppgradera."
+#: ../../include/conversation.php:1087 ../../mod/mail.php:171
+#: ../../mod/mail.php:286
+msgid "Please enter a link URL:"
+msgstr "Ange en länkadress:"
-#: ../../include/account.php:656
-msgid "This action exceeds the limits set by your subscription plan."
-msgstr "Den här funktionen går utanför vad som anges i ditt avtal."
+#: ../../include/conversation.php:1088
+msgid "Please enter a video link/URL:"
+msgstr "Ange en videolänkadress:"
-#: ../../include/account.php:661
-msgid "This action is not available under your subscription plan."
-msgstr "Den här funktionen är inte tillgänglig med ditt avtal."
+#: ../../include/conversation.php:1089
+msgid "Please enter an audio link/URL:"
+msgstr "Ange en ljudlänkadress"
-#: ../../include/permissions.php:13
-msgid "Can view my normal stream and posts"
-msgstr "Kan se mina normala strömmar och inlägg"
+#: ../../include/conversation.php:1090
+msgid "Tag term:"
+msgstr "Tagguttryck"
-#: ../../include/permissions.php:14
-msgid "Can view my default channel profile"
-msgstr "Kan se min standardkanalprofil"
+#: ../../include/conversation.php:1091 ../../mod/filer.php:49
+msgid "Save to Folder:"
+msgstr "Spara i mapp:"
-#: ../../include/permissions.php:15
-msgid "Can view my photo albums"
-msgstr "Kan se mina fotoalbum"
+#: ../../include/conversation.php:1092
+msgid "Where are you right now?"
+msgstr "Var är du just nu?"
-#: ../../include/permissions.php:16
-msgid "Can view my connections"
-msgstr "Kan se mina kontakter"
+#: ../../include/conversation.php:1093 ../../mod/editpost.php:52
+#: ../../mod/mail.php:172 ../../mod/mail.php:287
+msgid "Expires YYYY-MM-DD HH:MM"
+msgstr "Upphör YYYY-MM-DD HH:MM"
-#: ../../include/permissions.php:17
-msgid "Can view my file storage"
-msgstr "Kan se mitt filutrymme"
+#: ../../include/conversation.php:1117 ../../mod/photos.php:977
+#: ../../mod/editblock.php:198 ../../mod/editlayout.php:193
+#: ../../mod/editwebpage.php:230 ../../mod/layouts.php:168
+msgid "Share"
+msgstr "Dela"
-#: ../../include/permissions.php:18
-msgid "Can view my webpages"
-msgstr "Kan se mina webbsidor"
+#: ../../include/conversation.php:1119 ../../mod/editwebpage.php:170
+msgid "Page link title"
+msgstr "Titel på sidlänk"
-#: ../../include/permissions.php:21
-msgid "Can send me their channel stream and posts"
-msgstr "Kan skicka sina kanalströmmar och inlägg till mig"
+#: ../../include/conversation.php:1122
+msgid "Post as"
+msgstr "Posta som"
-#: ../../include/permissions.php:22
-msgid "Can post on my channel page (\"wall\")"
-msgstr "Kan posta inlägg på min kanalsida (\"vägg\")"
+#: ../../include/conversation.php:1123 ../../mod/editpost.php:113
+#: ../../mod/mail.php:235 ../../mod/mail.php:349 ../../mod/editblock.php:144
+#: ../../mod/editlayout.php:140 ../../mod/editwebpage.php:175
+msgid "Upload photo"
+msgstr "Ladda upp foto"
-#: ../../include/permissions.php:23
-msgid "Can comment on or like my posts"
-msgstr "Kan kommentera eller gilla mina inlägg"
+#: ../../include/conversation.php:1124
+msgid "upload photo"
+msgstr "ladda upp foto"
-#: ../../include/permissions.php:24
-msgid "Can send me private mail messages"
-msgstr "Kan skicka privata meddelanden till mig"
+#: ../../include/conversation.php:1125 ../../mod/editpost.php:114
+#: ../../mod/mail.php:236 ../../mod/mail.php:350 ../../mod/editblock.php:145
+#: ../../mod/editlayout.php:141 ../../mod/editwebpage.php:176
+msgid "Attach file"
+msgstr "Bifoga fil"
-#: ../../include/permissions.php:25
-msgid "Can post photos to my photo albums"
-msgstr "Kan lägga till foton i mitt fotoalbum"
+#: ../../include/conversation.php:1126
+msgid "attach file"
+msgstr "bifoga fil"
-#: ../../include/permissions.php:26
-msgid "Can like/dislike stuff"
-msgstr "Kan gilla/ogilla saker"
+#: ../../include/conversation.php:1127 ../../mod/editpost.php:115
+#: ../../mod/mail.php:237 ../../mod/mail.php:351 ../../mod/editblock.php:146
+#: ../../mod/editlayout.php:142 ../../mod/editwebpage.php:177
+msgid "Insert web link"
+msgstr "Infoga webblänk"
-#: ../../include/permissions.php:26
-msgid "Profiles and things other than posts/comments"
-msgstr "Profiler och annat än inlägg/kommentarer"
+#: ../../include/conversation.php:1128
+msgid "web link"
+msgstr "webblänk"
-#: ../../include/permissions.php:28
-msgid "Can forward to all my channel contacts via post @mentions"
-msgstr "Kan vidarebefordra till alla mina kanalkontakter genom @omnämnanden"
+#: ../../include/conversation.php:1129
+msgid "Insert video link"
+msgstr "Infoga videolänk"
-#: ../../include/permissions.php:28
-msgid "Advanced - useful for creating group forum channels"
-msgstr "Avancerat - användbart för att skapa kanaler för gruppforum"
+#: ../../include/conversation.php:1130
+msgid "video link"
+msgstr "videolänk"
-#: ../../include/permissions.php:29
-msgid "Can chat with me (when available)"
-msgstr "Kan chatta med mig (när tillgänglig)"
+#: ../../include/conversation.php:1131
+msgid "Insert audio link"
+msgstr "Infoga ljudlänk"
-#: ../../include/permissions.php:30
-msgid "Can write to my file storage"
-msgstr "Har skrivrättigheter i mitt filutrymme"
+#: ../../include/conversation.php:1132
+msgid "audio link"
+msgstr "ljudlänk"
-#: ../../include/permissions.php:31
-msgid "Can edit my webpages"
-msgstr "Kan redigera mina webbsidor"
+#: ../../include/conversation.php:1133 ../../mod/editpost.php:119
+#: ../../mod/editblock.php:150 ../../mod/editlayout.php:146
+#: ../../mod/editwebpage.php:181
+msgid "Set your location"
+msgstr "Ange din plats"
-#: ../../include/permissions.php:33
-msgid "Can source my public posts in derived channels"
-msgstr "Kan använda mina offentliga inlägg i kanaler nedströms"
+#: ../../include/conversation.php:1134
+msgid "set location"
+msgstr "ange plats"
-#: ../../include/permissions.php:33
-msgid "Somewhat advanced - very useful in open communities"
-msgstr "Ganska avancerat - väldigt användbart i öppna gemenskaper"
+#: ../../include/conversation.php:1135 ../../mod/editpost.php:120
+#: ../../mod/editblock.php:151 ../../mod/editlayout.php:147
+#: ../../mod/editwebpage.php:182
+msgid "Clear browser location"
+msgstr "Rensa webbläsarplats"
-#: ../../include/permissions.php:35
-msgid "Can administer my channel resources"
-msgstr "Kan administrera mina kanalresurser"
+#: ../../include/conversation.php:1136
+msgid "clear location"
+msgstr "rensa plats"
-#: ../../include/permissions.php:35
-msgid ""
-"Extremely advanced. Leave this alone unless you know what you are doing"
-msgstr "Extremt avancerat. Låt detta vara om du inte vet vad du gör"
+#: ../../include/conversation.php:1138 ../../mod/editpost.php:132
+#: ../../mod/editblock.php:164 ../../mod/editlayout.php:159
+#: ../../mod/editwebpage.php:198
+msgid "Title (optional)"
+msgstr "Titel (frivilligt)"
-#: ../../include/permissions.php:785
-msgid "Social Networking"
-msgstr "Socialt nätverkande"
+#: ../../include/conversation.php:1141 ../../mod/editpost.php:134
+#: ../../mod/editblock.php:167 ../../mod/editlayout.php:162
+#: ../../mod/editwebpage.php:200
+msgid "Categories (optional, comma-separated list)"
+msgstr "Kategorier (frivilligt, kommaseparerad lista)"
-#: ../../include/permissions.php:786 ../../include/permissions.php:788
-#: ../../include/permissions.php:790
-msgid "Mostly Public"
-msgstr "Mestadels offentligt"
+#: ../../include/conversation.php:1143 ../../mod/editpost.php:122
+#: ../../mod/editblock.php:153 ../../mod/editlayout.php:149
+#: ../../mod/editwebpage.php:184
+msgid "Permission settings"
+msgstr "Behörighetsinställningar"
-#: ../../include/permissions.php:786 ../../include/permissions.php:788
-#: ../../include/permissions.php:790
-msgid "Restricted"
-msgstr "Begränsat"
+#: ../../include/conversation.php:1144
+msgid "permissions"
+msgstr "behörighet"
-#: ../../include/permissions.php:786 ../../include/permissions.php:788
-msgid "Private"
-msgstr "Privat"
+#: ../../include/conversation.php:1151 ../../mod/editpost.php:129
+#: ../../mod/editblock.php:161 ../../mod/editlayout.php:156
+#: ../../mod/editwebpage.php:193
+msgid "Public post"
+msgstr "Offentligt inlägg"
-#: ../../include/permissions.php:787
-msgid "Community Forum"
-msgstr "Gemenskapsforum"
+#: ../../include/conversation.php:1153 ../../mod/editpost.php:135
+#: ../../mod/editblock.php:168 ../../mod/editlayout.php:163
+#: ../../mod/editwebpage.php:201
+msgid "Example: bob@example.com, mary@example.com"
+msgstr "Exempel: bob@example.com, mary@example.com"
-#: ../../include/permissions.php:789
-msgid "Feed Republish"
-msgstr "Vidarepublicering av flöde"
+#: ../../include/conversation.php:1166 ../../mod/editpost.php:146
+#: ../../mod/mail.php:242 ../../mod/mail.php:356 ../../mod/editblock.php:178
+#: ../../mod/editlayout.php:173 ../../mod/editwebpage.php:210
+msgid "Set expiration date"
+msgstr "Ange utgångsdatum"
-#: ../../include/permissions.php:791
-msgid "Special Purpose"
-msgstr "Särskilt syfte"
+#: ../../include/conversation.php:1168 ../../include/ItemObject.php:641
+#: ../../mod/editpost.php:148 ../../mod/mail.php:244 ../../mod/mail.php:358
+msgid "Encrypt text"
+msgstr "Kryptera text"
-#: ../../include/permissions.php:792
-msgid "Celebrity/Soapbox"
-msgstr "Kändis/talarstol"
+#: ../../include/conversation.php:1170 ../../mod/events.php:580
+#: ../../mod/editpost.php:150
+msgid "OK"
+msgstr "OK"
-#: ../../include/permissions.php:792
-msgid "Group Repository"
-msgstr "Gruppförråd"
+#: ../../include/conversation.php:1171 ../../mod/settings.php:566
+#: ../../mod/settings.php:592 ../../mod/events.php:579
+#: ../../mod/editpost.php:151 ../../mod/fbrowser.php:82
+#: ../../mod/fbrowser.php:117 ../../mod/tagrm.php:11 ../../mod/tagrm.php:134
+msgid "Cancel"
+msgstr "Avbryt"
-#: ../../include/permissions.php:793 ../../include/profile_selectors.php:6
-#: ../../include/profile_selectors.php:23
-#: ../../include/profile_selectors.php:61
-#: ../../include/profile_selectors.php:97
-msgid "Other"
-msgstr "Annat"
+#: ../../include/conversation.php:1415
+msgid "Discover"
+msgstr "Upptäck"
-#: ../../include/permissions.php:794
-msgid "Custom/Expert Mode"
-msgstr "Anpassat/expertläge"
+#: ../../include/conversation.php:1418
+msgid "Imported public streams"
+msgstr "Importerade offentliga strömmar"
-#: ../../include/photos.php:105
-#, php-format
-msgid "Image exceeds website size limit of %lu bytes"
-msgstr "Bild överskrider webbplatsens storleksbegränsning på %lu byte"
+#: ../../include/conversation.php:1423
+msgid "Commented Order"
+msgstr "Kommentarsordning"
-#: ../../include/photos.php:112
-msgid "Image file is empty."
-msgstr "Bildfil är tom."
+#: ../../include/conversation.php:1426
+msgid "Sort by Comment Date"
+msgstr "Ordna efter kommentarsdatum"
-#: ../../include/photos.php:141 ../../mod/profile_photo.php:216
-msgid "Unable to process image"
-msgstr "Kunde inte bearbeta bild"
+#: ../../include/conversation.php:1430
+msgid "Posted Order"
+msgstr "Inläggsordning"
-#: ../../include/photos.php:213
-msgid "Photo storage failed."
-msgstr "Fotolagring misslyckades."
+#: ../../include/conversation.php:1433
+msgid "Sort by Post Date"
+msgstr "Ordna efter när inlägget skrevs"
-#: ../../include/photos.php:345
-msgid "Upload New Photos"
-msgstr "Ladda upp nya foton"
+#: ../../include/conversation.php:1438 ../../include/widgets.php:94
+msgid "Personal"
+msgstr "Personligt"
-#: ../../include/items.php:382 ../../mod/profperm.php:23
-#: ../../mod/subthread.php:49 ../../mod/like.php:246 ../../mod/group.php:68
-#: ../../index.php:389
-msgid "Permission denied"
-msgstr "Behörighet saknas"
+#: ../../include/conversation.php:1441
+msgid "Posts that mention or involve you"
+msgstr "Inlägg som nämner eller berör dig"
-#: ../../include/items.php:969 ../../include/items.php:1014
-msgid "(Unknown)"
-msgstr "(Okänt)"
+#: ../../include/conversation.php:1447 ../../mod/connections.php:211
+#: ../../mod/connections.php:224 ../../mod/menu.php:80
+msgid "New"
+msgstr "Nytt"
-#: ../../include/items.php:1171
-msgid "Visible to anybody on the internet."
-msgstr "Kan ses av vem som helst på Internet."
+#: ../../include/conversation.php:1450
+msgid "Activity Stream - by date"
+msgstr "Aktivitetsström - efter datum"
-#: ../../include/items.php:1173
-msgid "Visible to you only."
-msgstr "Kan bara ses av dig."
+#: ../../include/conversation.php:1456
+msgid "Starred"
+msgstr "Märkt"
-#: ../../include/items.php:1175
-msgid "Visible to anybody in this network."
-msgstr "Kan ses av alla på det här nätverket."
+#: ../../include/conversation.php:1459
+msgid "Favourite Posts"
+msgstr "Favoritinlägg"
-#: ../../include/items.php:1177
-msgid "Visible to anybody authenticated."
-msgstr "Kan ses av alla inloggade."
+#: ../../include/conversation.php:1466
+msgid "Spam"
+msgstr "Skräp"
-#: ../../include/items.php:1179
-#, php-format
-msgid "Visible to anybody on %s."
-msgstr "Kan ses av alla på %s."
+#: ../../include/conversation.php:1469
+msgid "Posts flagged as SPAM"
+msgstr "Inlägg markerade som SKRÄP"
-#: ../../include/items.php:1181
-msgid "Visible to all connections."
-msgstr "Kan ses av alla kontakter."
+#: ../../include/conversation.php:1509 ../../mod/admin.php:865
+msgid "Channel"
+msgstr "Kanal"
-#: ../../include/items.php:1183
-msgid "Visible to approved connections."
-msgstr "Kan ses av godkända kontakter."
+#: ../../include/conversation.php:1512
+msgid "Status Messages and Posts"
+msgstr "Statusmeddelanden och inlägg"
-#: ../../include/items.php:1185
-msgid "Visible to specific connections."
-msgstr "Kan ses av valda kontakter."
+#: ../../include/conversation.php:1521
+msgid "About"
+msgstr "Om"
-#: ../../include/items.php:3952 ../../mod/thing.php:76
-#: ../../mod/display.php:32 ../../mod/filestorage.php:26
-#: ../../mod/admin.php:168 ../../mod/admin.php:896 ../../mod/admin.php:1099
-#: ../../mod/viewsrc.php:20
-msgid "Item not found."
-msgstr "Posten hittades inte."
+#: ../../include/conversation.php:1524
+msgid "Profile Details"
+msgstr "Profildetaljer"
-#: ../../include/items.php:4410 ../../mod/group.php:38 ../../mod/group.php:140
-msgid "Collection not found."
-msgstr "Kretsen hittades inte."
+#: ../../include/conversation.php:1530 ../../include/apps.php:139
+#: ../../include/nav.php:105 ../../mod/fbrowser.php:25
+msgid "Photos"
+msgstr "Foton"
-#: ../../include/items.php:4425
-msgid "Collection is empty."
-msgstr "Kretsen är tom."
+#: ../../include/conversation.php:1542
+msgid "Files and Storage"
+msgstr "Filer och lagring"
-#: ../../include/items.php:4432
-#, php-format
-msgid "Collection: %s"
-msgstr "Krets: %s"
+#: ../../include/conversation.php:1552 ../../include/conversation.php:1555
+msgid "Chatrooms"
+msgstr "Chattrum"
-#: ../../include/items.php:4443
-#, php-format
-msgid "Connection: %s"
-msgstr "Kontakt: %s"
+#: ../../include/conversation.php:1565 ../../include/apps.php:129
+#: ../../include/nav.php:117
+msgid "Bookmarks"
+msgstr "Bokmärken"
-#: ../../include/items.php:4446
-msgid "Connection not found."
-msgstr "Kontakten hittades inte."
+#: ../../include/conversation.php:1568
+msgid "Saved Bookmarks"
+msgstr "Sparade bokmärken"
-#: ../../include/security.php:323
-msgid ""
-"The form security token was not correct. This probably happened because the "
-"form has been opened for too long (>3 hours) before submitting it."
-msgstr "Formulärets kontrollkod var inte korrekt. Antagligen beror det på att formuläret har varit öppet för länge (> 3 timmar) innan det skickades."
+#: ../../include/conversation.php:1576 ../../include/apps.php:136
+#: ../../include/nav.php:121 ../../mod/webpages.php:160
+msgid "Webpages"
+msgstr "Webbsidor"
-#: ../../include/widgets.php:87
+#: ../../include/conversation.php:1579
+msgid "Manage Webpages"
+msgstr "Hantera webbsidor"
+
+#: ../../include/widgets.php:91 ../../include/nav.php:171
+#: ../../mod/apps.php:34
+msgid "Apps"
+msgstr "Appar"
+
+#: ../../include/widgets.php:92
msgid "System"
msgstr "System"
-#: ../../include/widgets.php:90
+#: ../../include/widgets.php:95
msgid "Create Personal App"
msgstr "Skapa personlig app"
-#: ../../include/widgets.php:91
+#: ../../include/widgets.php:96
msgid "Edit Personal App"
msgstr "Redigera personlig app"
-#: ../../include/widgets.php:137 ../../mod/suggest.php:53
+#: ../../include/widgets.php:138 ../../mod/suggest.php:53
msgid "Ignore/Hide"
msgstr "Ignorera/göm"
@@ -2940,111 +2620,482 @@ msgstr "Ange kanaladressen"
msgid "Example: bob@example.com, http://example.com/barbara"
msgstr "Exempel: bob@example.com, http://example.com/barbara"
-#: ../../include/widgets.php:191
+#: ../../include/widgets.php:190
msgid "Notes"
msgstr "Anteckningar"
-#: ../../include/widgets.php:263
+#: ../../include/widgets.php:264
msgid "Remove term"
msgstr "Ta bort uttryck"
-#: ../../include/widgets.php:352
+#: ../../include/widgets.php:347
msgid "Archives"
msgstr "Arkiv"
-#: ../../include/widgets.php:428
+#: ../../include/widgets.php:425
msgid "Refresh"
msgstr "Ladda om"
-#: ../../include/widgets.php:429 ../../mod/connedit.php:506
+#: ../../include/widgets.php:426 ../../mod/connedit.php:506
msgid "Me"
msgstr "Mig själv"
-#: ../../include/widgets.php:430 ../../mod/connedit.php:508
+#: ../../include/widgets.php:427 ../../mod/connedit.php:509
msgid "Best Friends"
msgstr "Bästa vänner"
-#: ../../include/widgets.php:432
+#: ../../include/widgets.php:429
msgid "Co-workers"
msgstr "Kollegor"
-#: ../../include/widgets.php:433 ../../mod/connedit.php:510
+#: ../../include/widgets.php:430 ../../mod/connedit.php:511
msgid "Former Friends"
msgstr "Tidigare vänner"
-#: ../../include/widgets.php:434 ../../mod/connedit.php:511
+#: ../../include/widgets.php:431 ../../mod/connedit.php:512
msgid "Acquaintances"
msgstr "Bekanta"
-#: ../../include/widgets.php:435
+#: ../../include/widgets.php:432
msgid "Everybody"
msgstr "Alla"
-#: ../../include/widgets.php:469
+#: ../../include/widgets.php:466
msgid "Account settings"
msgstr "Kontoinställningar"
-#: ../../include/widgets.php:475
+#: ../../include/widgets.php:472
msgid "Channel settings"
msgstr "Kanalinställningar"
-#: ../../include/widgets.php:481
+#: ../../include/widgets.php:478
msgid "Additional features"
msgstr "Tilläggsfunktioner"
-#: ../../include/widgets.php:487
+#: ../../include/widgets.php:484
msgid "Feature settings"
msgstr "Funktionsinställningar"
-#: ../../include/widgets.php:493
+#: ../../include/widgets.php:490
msgid "Display settings"
msgstr "Utseende"
-#: ../../include/widgets.php:499
+#: ../../include/widgets.php:496
msgid "Connected apps"
msgstr "Anslutna appar"
-#: ../../include/widgets.php:505
+#: ../../include/widgets.php:502
msgid "Export channel"
msgstr "Exportera kanal"
-#: ../../include/widgets.php:511
-msgid "Export content"
-msgstr "Exportera innehåll"
-
-#: ../../include/widgets.php:520 ../../mod/connedit.php:538
+#: ../../include/widgets.php:511 ../../mod/connedit.php:539
msgid "Connection Default Permissions"
msgstr "Standardbehörighet för kontakt"
-#: ../../include/widgets.php:528
+#: ../../include/widgets.php:519
msgid "Premium Channel Settings"
msgstr "Inställningar för premiumkanal"
-#: ../../include/widgets.php:562 ../../mod/mail.php:125
+#: ../../include/widgets.php:535 ../../include/apps.php:134
+#: ../../include/nav.php:218 ../../mod/admin.php:951 ../../mod/admin.php:1156
+msgid "Settings"
+msgstr "Inställningar"
+
+#: ../../include/widgets.php:548 ../../mod/mail.php:125
#: ../../mod/message.php:31
msgid "Messages"
msgstr "Meddelanden"
-#: ../../include/widgets.php:567
+#: ../../include/widgets.php:551
msgid "Check Mail"
msgstr "Hämta meddelanden"
-#: ../../include/widgets.php:648
+#: ../../include/widgets.php:556 ../../include/nav.php:209
+msgid "New Message"
+msgstr "Nytt meddelande"
+
+#: ../../include/widgets.php:634
msgid "Chat Rooms"
msgstr "Chattrum"
-#: ../../include/widgets.php:668
+#: ../../include/widgets.php:654
msgid "Bookmarked Chatrooms"
msgstr "Bokmärkta chattrum"
-#: ../../include/widgets.php:688
+#: ../../include/widgets.php:674
msgid "Suggested Chatrooms"
msgstr "Föreslagna chattrum"
-#: ../../include/widgets.php:817 ../../include/widgets.php:875
+#: ../../include/widgets.php:801 ../../include/widgets.php:859
msgid "photo/image"
msgstr "foto/bild"
+#: ../../include/zot.php:664
+msgid "Invalid data packet"
+msgstr "Ogiltigt datapaket"
+
+#: ../../include/zot.php:680
+msgid "Unable to verify channel signature"
+msgstr "Kunde inte bekräfta kanalsignatur"
+
+#: ../../include/zot.php:1829
+#, php-format
+msgid "Unable to verify site signature for %s"
+msgstr "Kunde inte bekräfta signatur för servern %s"
+
+#: ../../include/ItemObject.php:130
+msgid "Save to Folder"
+msgstr "Spara i mapp"
+
+#: ../../include/ItemObject.php:142 ../../include/ItemObject.php:154
+#: ../../mod/photos.php:1023 ../../mod/photos.php:1035
+msgid "View all"
+msgstr "Visa alla"
+
+#: ../../include/ItemObject.php:151 ../../mod/photos.php:1032
+msgctxt "noun"
+msgid "Dislike"
+msgid_plural "Dislikes"
+msgstr[0] "ogillar detta"
+msgstr[1] "ogillar detta"
+
+#: ../../include/ItemObject.php:179
+msgid "Add Star"
+msgstr "Märk"
+
+#: ../../include/ItemObject.php:180
+msgid "Remove Star"
+msgstr "Ta bort märkning"
+
+#: ../../include/ItemObject.php:181
+msgid "Toggle Star Status"
+msgstr "Växla märkning"
+
+#: ../../include/ItemObject.php:185
+msgid "starred"
+msgstr "märkt"
+
+#: ../../include/ItemObject.php:203
+msgid "Add Tag"
+msgstr "Lägg till en tagg"
+
+#: ../../include/ItemObject.php:221 ../../mod/photos.php:975
+msgid "I like this (toggle)"
+msgstr "Jag gillar det här (växla)"
+
+#: ../../include/ItemObject.php:222 ../../mod/photos.php:976
+msgid "I don't like this (toggle)"
+msgstr "Jag gillar inte det här (växla)"
+
+#: ../../include/ItemObject.php:226
+msgid "Share This"
+msgstr "Dela det här"
+
+#: ../../include/ItemObject.php:226
+msgid "share"
+msgstr "dela"
+
+#: ../../include/ItemObject.php:243
+#, php-format
+msgid "%d comment"
+msgid_plural "%d comments"
+msgstr[0] "%d kommentar"
+msgstr[1] "%d kommentarer"
+
+#: ../../include/ItemObject.php:256 ../../include/ItemObject.php:257
+#, php-format
+msgid "View %s's profile - %s"
+msgstr "Visa %ss profil - %s"
+
+#: ../../include/ItemObject.php:260
+msgid "to"
+msgstr "till"
+
+#: ../../include/ItemObject.php:261
+msgid "via"
+msgstr "via"
+
+#: ../../include/ItemObject.php:262
+msgid "Wall-to-Wall"
+msgstr "Vägg-till-vägg"
+
+#: ../../include/ItemObject.php:263
+msgid "via Wall-To-Wall:"
+msgstr "via vägg-till-vägg"
+
+#: ../../include/ItemObject.php:299
+msgid "Save Bookmarks"
+msgstr "Spara bokmärken"
+
+#: ../../include/ItemObject.php:300
+msgid "Add to Calendar"
+msgstr "Lägg till kalendern"
+
+#: ../../include/ItemObject.php:309
+msgid "Mark all seen"
+msgstr "Märk alla som lästa"
+
+#: ../../include/ItemObject.php:314 ../../mod/photos.php:1143
+msgctxt "noun"
+msgid "Likes"
+msgstr "gillar detta"
+
+#: ../../include/ItemObject.php:315 ../../mod/photos.php:1144
+msgctxt "noun"
+msgid "Dislikes"
+msgstr "ogillar detta"
+
+#: ../../include/ItemObject.php:345 ../../include/js_strings.php:7
+msgid "[+] show all"
+msgstr "[+] visa alla"
+
+#: ../../include/ItemObject.php:626 ../../mod/photos.php:994
+#: ../../mod/photos.php:1104
+msgid "This is you"
+msgstr "Det här är du"
+
+#: ../../include/ItemObject.php:628 ../../include/js_strings.php:6
+#: ../../mod/photos.php:996 ../../mod/photos.php:1106
+msgid "Comment"
+msgstr "Kommentera"
+
+#: ../../include/ItemObject.php:629 ../../mod/mood.php:135
+#: ../../mod/settings.php:565 ../../mod/settings.php:677
+#: ../../mod/settings.php:706 ../../mod/settings.php:730
+#: ../../mod/settings.php:812 ../../mod/settings.php:1004
+#: ../../mod/group.php:81 ../../mod/poke.php:166 ../../mod/setup.php:313
+#: ../../mod/setup.php:358 ../../mod/sources.php:104 ../../mod/sources.php:138
+#: ../../mod/events.php:598 ../../mod/chat.php:177 ../../mod/chat.php:211
+#: ../../mod/connedit.php:556 ../../mod/mail.php:352 ../../mod/photos.php:594
+#: ../../mod/photos.php:671 ../../mod/photos.php:957 ../../mod/photos.php:997
+#: ../../mod/photos.php:1107 ../../mod/pdledit.php:58 ../../mod/thing.php:284
+#: ../../mod/thing.php:327 ../../mod/fsuggest.php:108
+#: ../../mod/filestorage.php:146 ../../mod/connect.php:93
+#: ../../mod/locs.php:99 ../../mod/import.php:504 ../../mod/profiles.php:633
+#: ../../mod/admin.php:412 ../../mod/admin.php:723 ../../mod/admin.php:859
+#: ../../mod/admin.php:992 ../../mod/admin.php:1191 ../../mod/admin.php:1278
+#: ../../mod/invite.php:142 ../../mod/xchan.php:11 ../../mod/appman.php:99
+#: ../../mod/poll.php:68 ../../view/theme/apw/php/config.php:256
+#: ../../view/theme/redbasic/php/config.php:99
+msgid "Submit"
+msgstr "Skicka"
+
+#: ../../include/ItemObject.php:630
+msgid "Bold"
+msgstr "Fet"
+
+#: ../../include/ItemObject.php:631
+msgid "Italic"
+msgstr "Kursiv"
+
+#: ../../include/ItemObject.php:632
+msgid "Underline"
+msgstr "Understruken"
+
+#: ../../include/ItemObject.php:633
+msgid "Quote"
+msgstr "Citat"
+
+#: ../../include/ItemObject.php:634
+msgid "Code"
+msgstr "Kod"
+
+#: ../../include/ItemObject.php:635
+msgid "Image"
+msgstr "Bild"
+
+#: ../../include/ItemObject.php:636
+msgid "Link"
+msgstr "Länk"
+
+#: ../../include/ItemObject.php:637
+msgid "Video"
+msgstr "Video"
+
+#: ../../include/datetime.php:43 ../../include/datetime.php:45
+msgid "Miscellaneous"
+msgstr "Övrigt"
+
+#: ../../include/datetime.php:142
+msgid "YYYY-MM-DD or MM-DD"
+msgstr "ÅÅÅÅ-MM-DD eller MM-DD"
+
+#: ../../include/datetime.php:259
+msgid "never"
+msgstr "aldrig"
+
+#: ../../include/datetime.php:265
+msgid "less than a second ago"
+msgstr "mindre än en sekund sedan"
+
+#: ../../include/datetime.php:268
+msgid "year"
+msgstr "år"
+
+#: ../../include/datetime.php:268
+msgid "years"
+msgstr "år"
+
+#: ../../include/datetime.php:269
+msgid "month"
+msgstr "månad"
+
+#: ../../include/datetime.php:269
+msgid "months"
+msgstr "månader"
+
+#: ../../include/datetime.php:270
+msgid "week"
+msgstr "vecka"
+
+#: ../../include/datetime.php:270
+msgid "weeks"
+msgstr "veckor"
+
+#: ../../include/datetime.php:271
+msgid "day"
+msgstr "dag"
+
+#: ../../include/datetime.php:271
+msgid "days"
+msgstr "dagar"
+
+#: ../../include/datetime.php:272
+msgid "hour"
+msgstr "timme"
+
+#: ../../include/datetime.php:272
+msgid "hours"
+msgstr "timmar"
+
+#: ../../include/datetime.php:273
+msgid "minute"
+msgstr "minut"
+
+#: ../../include/datetime.php:273
+msgid "minutes"
+msgstr "minuter"
+
+#: ../../include/datetime.php:274
+msgid "second"
+msgstr "sekund"
+
+#: ../../include/datetime.php:274
+msgid "seconds"
+msgstr "sekunder"
+
+#: ../../include/datetime.php:283
+#, php-format
+msgid "%1$d %2$s ago"
+msgstr "%1$d %2$s sedan"
+
+#: ../../include/datetime.php:491
+#, php-format
+msgid "%1$s's birthday"
+msgstr "%1$ss födelsedag"
+
+#: ../../include/datetime.php:492
+#, php-format
+msgid "Happy Birthday %1$s"
+msgstr "Grattis på födelsedagen %1$s"
+
+#: ../../include/apps.php:128
+msgid "Site Admin"
+msgstr "Serveradministrator"
+
+#: ../../include/apps.php:130
+msgid "Address Book"
+msgstr "Adressbok"
+
+#: ../../include/apps.php:131 ../../include/nav.php:125 ../../boot.php:1540
+msgid "Login"
+msgstr "Logga in"
+
+#: ../../include/apps.php:132 ../../include/nav.php:216
+#: ../../mod/manage.php:148
+msgid "Channel Manager"
+msgstr "Kanalhanterare"
+
+#: ../../include/apps.php:133 ../../include/nav.php:190
+msgid "Matrix"
+msgstr "Matris"
+
+#: ../../include/apps.php:137 ../../include/nav.php:193
+msgid "Channel Home"
+msgstr "Kanalhem"
+
+#: ../../include/apps.php:140 ../../include/nav.php:212
+#: ../../mod/events.php:442
+msgid "Events"
+msgstr "Händelser"
+
+#: ../../include/apps.php:141 ../../include/nav.php:176
+#: ../../mod/directory.php:321
+msgid "Directory"
+msgstr "Katalog"
+
+#: ../../include/apps.php:142 ../../include/nav.php:168 ../../mod/help.php:58
+#: ../../mod/help.php:63
+msgid "Help"
+msgstr "Hjälp"
+
+#: ../../include/apps.php:143 ../../include/nav.php:204
+msgid "Mail"
+msgstr "Privat meddelande"
+
+#: ../../include/apps.php:144 ../../mod/mood.php:131
+msgid "Mood"
+msgstr "Sinnesstämning"
+
+#: ../../include/apps.php:146 ../../include/nav.php:111
+msgid "Chat"
+msgstr "Chatt"
+
+#: ../../include/apps.php:148
+msgid "Probe"
+msgstr "Sond"
+
+#: ../../include/apps.php:149
+msgid "Suggest"
+msgstr "Föreslå"
+
+#: ../../include/apps.php:150
+msgid "Random Channel"
+msgstr "Slumpvald kanal"
+
+#: ../../include/apps.php:151
+msgid "Invite"
+msgstr "Bjud in"
+
+#: ../../include/apps.php:152
+msgid "Features"
+msgstr "Funktioner"
+
+#: ../../include/apps.php:153
+msgid "Language"
+msgstr "Språk"
+
+#: ../../include/apps.php:154
+msgid "Post"
+msgstr "Inlägg"
+
+#: ../../include/apps.php:155
+msgid "Profile Photo"
+msgstr "Profilfoto"
+
+#: ../../include/apps.php:247 ../../mod/settings.php:81
+#: ../../mod/settings.php:591
+msgid "Update"
+msgstr "Uppdatera"
+
+#: ../../include/apps.php:247
+msgid "Install"
+msgstr "Installera"
+
+#: ../../include/apps.php:252
+msgid "Purchase"
+msgstr "Köp"
+
#: ../../include/Contact.php:123
msgid "New window"
msgstr "Nytt fönster"
@@ -3053,7 +3104,7 @@ msgstr "Nytt fönster"
msgid "Open the selected location in a different window or browser tab"
msgstr "Öppna den valda platsen i ett annat fönster eller en annan webbläsarflik"
-#: ../../include/Contact.php:211 ../../mod/admin.php:646
+#: ../../include/Contact.php:214 ../../mod/admin.php:646
#, php-format
msgid "User '%s' deleted"
msgstr "Användare '%s' borttagen"
@@ -3062,15 +3113,6 @@ msgstr "Användare '%s' borttagen"
msgid "Delete this item?"
msgstr "Ta bort den här posten?"
-#: ../../include/js_strings.php:6 ../../include/ItemObject.php:620
-#: ../../mod/photos.php:996 ../../mod/photos.php:1106
-msgid "Comment"
-msgstr "Kommentar"
-
-#: ../../include/js_strings.php:7 ../../include/ItemObject.php:337
-msgid "[+] show all"
-msgstr "[+] visa alla"
-
#: ../../include/js_strings.php:8
msgid "[-] show less"
msgstr "[-] visa färre"
@@ -3424,258 +3466,283 @@ msgstr "Bryr mig inte"
msgid "Ask me"
msgstr "Fråga mig"
-#: ../../include/apps.php:126
-msgid "Site Admin"
-msgstr "Serveradministrator"
+#: ../../include/nav.php:95 ../../include/nav.php:128 ../../boot.php:1539
+msgid "Logout"
+msgstr "Logga ut"
-#: ../../include/apps.php:128
-msgid "Address Book"
-msgstr "Adressbok"
+#: ../../include/nav.php:95 ../../include/nav.php:128
+msgid "End this session"
+msgstr "Avsluta sessionen"
-#: ../../include/apps.php:142 ../../mod/mood.php:131
-msgid "Mood"
-msgstr "Sinnesstämning"
+#: ../../include/nav.php:98 ../../include/nav.php:159
+msgid "Home"
+msgstr "Hem"
-#: ../../include/apps.php:146
-msgid "Probe"
-msgstr "Sond"
+#: ../../include/nav.php:98
+msgid "Your posts and conversations"
+msgstr "Dina inlägg och konversationer"
-#: ../../include/apps.php:147
-msgid "Suggest"
-msgstr "Föreslå"
+#: ../../include/nav.php:99
+msgid "Your profile page"
+msgstr "Din profilsida"
-#: ../../include/apps.php:148
-msgid "Random Channel"
-msgstr "Slumpvald kanal"
+#: ../../include/nav.php:101
+msgid "Edit Profiles"
+msgstr "Redigera profiler"
-#: ../../include/apps.php:149
-msgid "Invite"
-msgstr "Bjud in"
+#: ../../include/nav.php:101
+msgid "Manage/Edit profiles"
+msgstr "Hantera/redigera profiler"
-#: ../../include/apps.php:150
-msgid "Features"
-msgstr "Funktioner"
+#: ../../include/nav.php:103
+msgid "Edit your profile"
+msgstr "Redigera din profil"
-#: ../../include/apps.php:151
-msgid "Language"
-msgstr "Språk"
+#: ../../include/nav.php:105
+msgid "Your photos"
+msgstr "Dina foton"
-#: ../../include/apps.php:152
-msgid "Post"
-msgstr "Inlägg"
+#: ../../include/nav.php:106
+msgid "Your files"
+msgstr "Dina filer"
-#: ../../include/apps.php:153
-msgid "Profile Photo"
-msgstr "Profilfoto"
+#: ../../include/nav.php:111
+msgid "Your chatrooms"
+msgstr "Dina chattrum"
-#: ../../include/apps.php:242 ../../mod/settings.php:81
-#: ../../mod/settings.php:589
-msgid "Update"
-msgstr "Uppdatera"
+#: ../../include/nav.php:117
+msgid "Your bookmarks"
+msgstr "Dina bokmärken"
-#: ../../include/apps.php:242
-msgid "Install"
-msgstr "Installera"
+#: ../../include/nav.php:121
+msgid "Your webpages"
+msgstr "Dina webbsidor"
-#: ../../include/apps.php:247
-msgid "Purchase"
-msgstr "Köp"
+#: ../../include/nav.php:125
+msgid "Sign in"
+msgstr "Logga in"
-#: ../../include/auth.php:116
-msgid "Logged out."
-msgstr "Utloggad."
+#: ../../include/nav.php:142
+#, php-format
+msgid "%s - click to logout"
+msgstr "%s - klicka för att logga ut"
-#: ../../include/auth.php:257
-msgid "Failed authentication"
-msgstr "Inloggning misslyckades"
+#: ../../include/nav.php:145
+msgid "Remote authentication"
+msgstr "Fjärrinloggning"
-#: ../../include/auth.php:271 ../../mod/openid.php:190
-msgid "Login failed."
-msgstr "Inloggning misslyckades."
+#: ../../include/nav.php:145
+msgid "Click to authenticate to your home hub"
+msgstr "Klicka för att autentisera mot din hemmahubb"
-#: ../../include/ItemObject.php:130
-msgid "Save to Folder"
-msgstr "Spara i mapp"
+#: ../../include/nav.php:159
+msgid "Home Page"
+msgstr "Hemsida"
-#: ../../include/ItemObject.php:142 ../../include/ItemObject.php:154
-#: ../../mod/photos.php:1023 ../../mod/photos.php:1035
-msgid "View all"
-msgstr "Visa alla"
+#: ../../include/nav.php:163 ../../mod/register.php:224 ../../boot.php:1516
+msgid "Register"
+msgstr "Skapa konto"
-#: ../../include/ItemObject.php:151 ../../mod/photos.php:1032
-msgctxt "noun"
-msgid "Dislike"
-msgid_plural "Dislikes"
-msgstr[0] "ogillar detta"
-msgstr[1] "ogillar detta"
+#: ../../include/nav.php:163
+msgid "Create an account"
+msgstr "Skapa ett konto"
-#: ../../include/ItemObject.php:179
-msgid "Add Star"
-msgstr "Märk"
+#: ../../include/nav.php:168
+msgid "Help and documentation"
+msgstr "Hjälp och dokumentation"
-#: ../../include/ItemObject.php:180
-msgid "Remove Star"
-msgstr "Ta bort märkning"
+#: ../../include/nav.php:171
+msgid "Applications, utilities, links, games"
+msgstr "Applikationer, verktyg, länkar, spel"
-#: ../../include/ItemObject.php:181
-msgid "Toggle Star Status"
-msgstr "Växla märkning"
+#: ../../include/nav.php:173
+msgid "Search site content"
+msgstr "Sök innehåll"
-#: ../../include/ItemObject.php:185
-msgid "starred"
-msgstr "märkt"
+#: ../../include/nav.php:176
+msgid "Channel Directory"
+msgstr "Kanalkatalog"
-#: ../../include/ItemObject.php:203
-msgid "Add Tag"
-msgstr "Lägg till en tagg"
+#: ../../include/nav.php:190
+msgid "Your matrix"
+msgstr "Din matris"
-#: ../../include/ItemObject.php:221 ../../mod/photos.php:975
-msgid "I like this (toggle)"
-msgstr "Jag gillar det här (växla)"
+#: ../../include/nav.php:191
+msgid "Mark all matrix notifications seen"
+msgstr "Märk alla matrisnotifieringar som lästa"
-#: ../../include/ItemObject.php:222 ../../mod/photos.php:976
-msgid "I don't like this (toggle)"
-msgstr "Jag gillar inte det här (växla)"
+#: ../../include/nav.php:193
+msgid "Channel home"
+msgstr "Kanalhem"
-#: ../../include/ItemObject.php:226
-msgid "Share This"
-msgstr "Dela det här"
+#: ../../include/nav.php:194
+msgid "Mark all channel notifications seen"
+msgstr "Märk alla kanalnotifieringar som lästa"
-#: ../../include/ItemObject.php:226
-msgid "share"
-msgstr "dela"
+#: ../../include/nav.php:197 ../../mod/connections.php:406
+msgid "Connections"
+msgstr "Kontakter"
-#: ../../include/ItemObject.php:236
-#, php-format
-msgid "%d comment"
-msgid_plural "%d comments"
-msgstr[0] "%d kommentar"
-msgstr[1] "%d kommentarer"
+#: ../../include/nav.php:200
+msgid "Notices"
+msgstr "Meddelanden"
-#: ../../include/ItemObject.php:249 ../../include/ItemObject.php:250
-#, php-format
-msgid "View %s's profile - %s"
-msgstr "Visa %ss profil - %s"
+#: ../../include/nav.php:200
+msgid "Notifications"
+msgstr "Notifieringar"
-#: ../../include/ItemObject.php:252
-msgid "to"
-msgstr "till"
+#: ../../include/nav.php:201
+msgid "See all notifications"
+msgstr "Se alla notifieringar"
-#: ../../include/ItemObject.php:253
-msgid "via"
-msgstr "via"
+#: ../../include/nav.php:202 ../../mod/notifications.php:99
+msgid "Mark all system notifications seen"
+msgstr "Märk alla systemnotifieringar som lästa"
-#: ../../include/ItemObject.php:254
-msgid "Wall-to-Wall"
-msgstr "Vägg-till-vägg"
+#: ../../include/nav.php:204
+msgid "Private mail"
+msgstr "Privat meddelande"
-#: ../../include/ItemObject.php:255
-msgid "via Wall-To-Wall:"
-msgstr "via vägg-till-vägg"
+#: ../../include/nav.php:205
+msgid "See all private messages"
+msgstr "Se alla privata meddelanden"
-#: ../../include/ItemObject.php:291
-msgid "Save Bookmarks"
-msgstr "Spara bokmärken"
+#: ../../include/nav.php:206
+msgid "Mark all private messages seen"
+msgstr "Märk alla privata meddelanden som lästa"
-#: ../../include/ItemObject.php:292
-msgid "Add to Calendar"
-msgstr "Lägg till kalendern"
+#: ../../include/nav.php:207
+msgid "Inbox"
+msgstr "Inkorg"
-#: ../../include/ItemObject.php:301
-msgid "Mark all seen"
-msgstr "Märk alla som lästa"
+#: ../../include/nav.php:208
+msgid "Outbox"
+msgstr "Utkorg"
-#: ../../include/ItemObject.php:306 ../../mod/photos.php:1143
-msgctxt "noun"
-msgid "Likes"
-msgstr "gillar detta"
+#: ../../include/nav.php:212
+msgid "Event Calendar"
+msgstr "Kalender"
-#: ../../include/ItemObject.php:307 ../../mod/photos.php:1144
-msgctxt "noun"
-msgid "Dislikes"
-msgstr "ogillar detta"
+#: ../../include/nav.php:213
+msgid "See all events"
+msgstr "Se alla händelser"
-#: ../../include/ItemObject.php:618 ../../mod/photos.php:994
-#: ../../mod/photos.php:1104
-msgid "This is you"
-msgstr "Det här är du"
+#: ../../include/nav.php:214
+msgid "Mark all events seen"
+msgstr "Märk alla händelser som lästa"
-#: ../../include/ItemObject.php:621 ../../mod/mood.php:135
-#: ../../mod/sources.php:104 ../../mod/sources.php:138 ../../mod/poke.php:166
-#: ../../mod/setup.php:313 ../../mod/setup.php:358 ../../mod/settings.php:563
-#: ../../mod/settings.php:675 ../../mod/settings.php:704
-#: ../../mod/settings.php:728 ../../mod/settings.php:805
-#: ../../mod/settings.php:997 ../../mod/events.php:598 ../../mod/chat.php:177
-#: ../../mod/chat.php:211 ../../mod/connect.php:93 ../../mod/connedit.php:555
-#: ../../mod/thing.php:284 ../../mod/thing.php:327 ../../mod/profiles.php:633
-#: ../../mod/pdledit.php:58 ../../mod/fsuggest.php:108
-#: ../../mod/filestorage.php:146 ../../mod/group.php:81
-#: ../../mod/import.php:480 ../../mod/admin.php:412 ../../mod/admin.php:723
-#: ../../mod/admin.php:859 ../../mod/admin.php:992 ../../mod/admin.php:1191
-#: ../../mod/admin.php:1278 ../../mod/locs.php:99 ../../mod/mail.php:352
-#: ../../mod/invite.php:142 ../../mod/xchan.php:11 ../../mod/photos.php:594
-#: ../../mod/photos.php:671 ../../mod/photos.php:957 ../../mod/photos.php:997
-#: ../../mod/photos.php:1107 ../../mod/appman.php:99 ../../mod/poll.php:68
-#: ../../view/theme/apw/php/config.php:256
-#: ../../view/theme/redbasic/php/config.php:99
-msgid "Submit"
-msgstr "Skicka"
+#: ../../include/nav.php:216
+msgid "Manage Your Channels"
+msgstr "Hantera dina kanaler"
-#: ../../include/ItemObject.php:622
-msgid "Bold"
-msgstr "Fet"
+#: ../../include/nav.php:218
+msgid "Account/Channel Settings"
+msgstr "Konto-/kanalinställningar"
-#: ../../include/ItemObject.php:623
-msgid "Italic"
-msgstr "Kursiv"
+#: ../../include/nav.php:226 ../../mod/admin.php:123
+msgid "Admin"
+msgstr "Administration"
-#: ../../include/ItemObject.php:624
-msgid "Underline"
-msgstr "Understruken"
+#: ../../include/nav.php:226
+msgid "Site Setup and Configuration"
+msgstr "Serverinställning och -konfiguration"
-#: ../../include/ItemObject.php:625
-msgid "Quote"
-msgstr "Citat"
+#: ../../include/nav.php:262
+msgid "@name, #tag, content"
+msgstr "@namn, #tagg, innehåll"
-#: ../../include/ItemObject.php:626
-msgid "Code"
-msgstr "Kod"
+#: ../../include/nav.php:263
+msgid "Please wait..."
+msgstr "Vänta..."
-#: ../../include/ItemObject.php:627
-msgid "Image"
-msgstr "Bild"
+#: ../../include/security.php:357
+msgid ""
+"The form security token was not correct. This probably happened because the "
+"form has been opened for too long (>3 hours) before submitting it."
+msgstr "Formulärets kontrollkod var inte korrekt. Antagligen beror det på att formuläret har varit öppet för länge (> 3 timmar) innan det skickades."
-#: ../../include/ItemObject.php:628
-msgid "Link"
-msgstr "Länk"
+#: ../../mod/mood.php:132
+msgid "Set your current mood and tell your friends"
+msgstr "Ange din nuvarande sinnesstämning och visa för dina vänner"
-#: ../../include/ItemObject.php:629
-msgid "Video"
-msgstr "Video"
+#: ../../mod/register.php:44
+msgid "Maximum daily site registrations exceeded. Please try again tomorrow."
+msgstr "Maximalt antal dagliga serverregistreringar överskridet. Försök igen i morgon."
-#: ../../include/chat.php:10
-msgid "Missing room name"
-msgstr "Rumsnamn saknas"
+#: ../../mod/register.php:50
+msgid ""
+"Please indicate acceptance of the Terms of Service. Registration failed."
+msgstr "Välj huruvida du accepterar användarvillkoren. Registrering misslyckades."
-#: ../../include/chat.php:19
-msgid "Duplicate room name"
-msgstr "Rumsnamnet finns redan"
+#: ../../mod/register.php:84
+msgid "Passwords do not match."
+msgstr "Lösenorden stämmer inte överens."
-#: ../../include/chat.php:68 ../../include/chat.php:76
-msgid "Invalid room specifier."
-msgstr "Ogiltig rumsbeskrivning."
+#: ../../mod/register.php:117
+msgid ""
+"Registration successful. Please check your email for validation "
+"instructions."
+msgstr "Registrering lyckades. Kontrollera din e-post för valideringsinstruktioner."
-#: ../../include/chat.php:105
-msgid "Room not found."
-msgstr "Rummet hittades inte."
+#: ../../mod/register.php:123
+msgid "Your registration is pending approval by the site owner."
+msgstr "Din registrering väntar på att bli godkänd av serverägaren."
-#: ../../include/chat.php:126
-msgid "Room is full"
-msgstr "Rummet är fullt"
+#: ../../mod/register.php:126
+msgid "Your registration can not be processed."
+msgstr "Din registrering kan inte behandlas."
-#: ../../mod/mood.php:132
-msgid "Set your current mood and tell your friends"
-msgstr "Ange din nuvarande sinnesstämning och visa för dina vänner"
+#: ../../mod/register.php:163
+msgid "Registration on this site/hub is by approval only."
+msgstr "Registrering på den här servern/hubben måste godkännas."
+
+#: ../../mod/register.php:164
+msgid "<a href=\"pubsites\">Register at another affiliated site/hub</a>"
+msgstr "<a href=\"pubsites\">Skapa konto på en annan ansluten server/hubb</a>"
+
+#: ../../mod/register.php:174
+msgid ""
+"This site has exceeded the number of allowed daily account registrations. "
+"Please try again tomorrow."
+msgstr "Antal dagliga registreringar som tillåts på den här servern har överskridits. Försök igen i morgon."
+
+#: ../../mod/register.php:185
+msgid "Terms of Service"
+msgstr "användarvillkor"
+
+#: ../../mod/register.php:191
+#, php-format
+msgid "I accept the %s for this website"
+msgstr "Jag accepterar den här webbplatsens %s"
+
+#: ../../mod/register.php:193
+#, php-format
+msgid "I am over 13 years of age and accept the %s for this website"
+msgstr "Jag är över 13 år och accepterar den här webbplatsens %s"
+
+#: ../../mod/register.php:207 ../../mod/admin.php:413
+msgid "Registration"
+msgstr "Registrering"
+
+#: ../../mod/register.php:212
+msgid "Membership on this site is by invitation only."
+msgstr "Medlemskap på den här servern kan endast fås genom inbjudan."
+
+#: ../../mod/register.php:213
+msgid "Please enter your invitation code"
+msgstr "Ange din inbjudningskod"
+
+#: ../../mod/register.php:216
+msgid "Your email address"
+msgstr "Din e-postadress"
+
+#: ../../mod/register.php:217
+msgid "Choose a password"
+msgstr "Välj ett lösenord"
+
+#: ../../mod/register.php:218
+msgid "Please re-enter your password"
+msgstr "Ange lösenordet igen"
#: ../../mod/mitem.php:24 ../../mod/menu.php:108
msgid "Menu not found."
@@ -3745,7 +3812,7 @@ msgstr "Nytt menyval"
msgid "Menu Item Permissions"
msgstr "Behörighet för menyval"
-#: ../../mod/mitem.php:161 ../../mod/mitem.php:204 ../../mod/settings.php:1032
+#: ../../mod/mitem.php:161 ../../mod/mitem.php:204 ../../mod/settings.php:1039
msgid "(click to open/close)"
msgstr "(klicka för att öppna/stänga)"
@@ -3797,171 +3864,628 @@ msgstr "Ändra"
msgid "Some blurb about what to do when you're new here"
msgstr "Lite text om vad man kan göra som ny här"
-#: ../../mod/register.php:44
-msgid "Maximum daily site registrations exceeded. Please try again tomorrow."
-msgstr "Maximalt antal dagliga serverregistreringar överskridet. Försök igen i morgon."
+#: ../../mod/settings.php:73
+msgid "Name is required"
+msgstr "Namn är obligatoriskt"
-#: ../../mod/register.php:50
-msgid ""
-"Please indicate acceptance of the Terms of Service. Registration failed."
-msgstr "Välj huruvida du accepterar användarvillkoren. Registrering misslyckades."
+#: ../../mod/settings.php:77
+msgid "Key and Secret are required"
+msgstr "Nyckel och kod är obligatoriska"
-#: ../../mod/register.php:84
-msgid "Passwords do not match."
-msgstr "Lösenorden stämmer inte överens."
+#: ../../mod/settings.php:213
+msgid "Passwords do not match. Password unchanged."
+msgstr "Lösenorden stämmer inte överens. Lösenordet har inte ändrats."
-#: ../../mod/register.php:117
-msgid ""
-"Registration successful. Please check your email for validation "
-"instructions."
-msgstr "Registrering lyckades. Kontrollera din e-post för valideringsinstruktioner."
+#: ../../mod/settings.php:217
+msgid "Empty passwords are not allowed. Password unchanged."
+msgstr "Tomma lösenord tillåts inte. Lösenordet har inte ändrats."
-#: ../../mod/register.php:123
-msgid "Your registration is pending approval by the site owner."
-msgstr "Din registrering väntar på att bli godkänd av serverägaren."
+#: ../../mod/settings.php:231
+msgid "Password changed."
+msgstr "Lösenordet ändrat."
-#: ../../mod/register.php:126
-msgid "Your registration can not be processed."
-msgstr "Din registrering kan inte behandlas."
+#: ../../mod/settings.php:233
+msgid "Password update failed. Please try again."
+msgstr "Lösenordsuppdatering misslyckades. Försök igen."
-#: ../../mod/register.php:163
-msgid "Registration on this site/hub is by approval only."
-msgstr "Registrering på den här servern/hubben måste godkännas."
+#: ../../mod/settings.php:247
+msgid "Not valid email."
+msgstr "Inte en giltig e-postadress."
-#: ../../mod/register.php:164
-msgid "<a href=\"pubsites\">Register at another affiliated site/hub</a>"
-msgstr "<a href=\"pubsites\">Skapa konto på en annan ansluten server/hubb</a>"
+#: ../../mod/settings.php:250
+msgid "Protected email address. Cannot change to that email."
+msgstr "Skyddad e-postadress. Kan inte ändra till den."
-#: ../../mod/register.php:174
+#: ../../mod/settings.php:259
+msgid "System failure storing new email. Please try again."
+msgstr "Systemfel när ny e-postadress skulle sparas. Försök igen."
+
+#: ../../mod/settings.php:495
+msgid "Settings updated."
+msgstr "Inställningar uppdaterade."
+
+#: ../../mod/settings.php:564 ../../mod/settings.php:590
+#: ../../mod/settings.php:626
+msgid "Add application"
+msgstr "Lägg till applikation"
+
+#: ../../mod/settings.php:567
+msgid "Name of application"
+msgstr "Applikationens namn"
+
+#: ../../mod/settings.php:568 ../../mod/settings.php:594
+msgid "Consumer Key"
+msgstr "Nyckel för konsument"
+
+#: ../../mod/settings.php:568 ../../mod/settings.php:569
+msgid "Automatically generated - change if desired. Max length 20"
+msgstr "Automatiskt genererad - ändra om så önskas. Maxlängd 20"
+
+#: ../../mod/settings.php:569 ../../mod/settings.php:595
+msgid "Consumer Secret"
+msgstr "Kod för konsument"
+
+#: ../../mod/settings.php:570 ../../mod/settings.php:596
+msgid "Redirect"
+msgstr "Omdirigering"
+
+#: ../../mod/settings.php:570
msgid ""
-"This site has exceeded the number of allowed daily account registrations. "
-"Please try again tomorrow."
-msgstr "Antal dagliga registreringar som tillåts på den här servern har överskridits. Försök igen i morgon."
+"Redirect URI - leave blank unless your application specifically requires "
+"this"
+msgstr "Omdirigerings-URI - lämna blankt om inte din applikation specifikt behöver det"
-#: ../../mod/register.php:185
-msgid "Terms of Service"
-msgstr "användarvillkor"
+#: ../../mod/settings.php:571 ../../mod/settings.php:597
+msgid "Icon url"
+msgstr "Ikon-URL"
-#: ../../mod/register.php:191
-#, php-format
-msgid "I accept the %s for this website"
-msgstr "Jag accepterar den här webbplatsens %s"
+#: ../../mod/settings.php:571
+msgid "Optional"
+msgstr "Frivillig"
-#: ../../mod/register.php:193
+#: ../../mod/settings.php:582
+msgid "You can't edit this application."
+msgstr "Du kan inte redigera den här applikationen."
+
+#: ../../mod/settings.php:625
+msgid "Connected Apps"
+msgstr "Anslutna appar"
+
+#: ../../mod/settings.php:629
+msgid "Client key starts with"
+msgstr "Klientnyckel börjar med"
+
+#: ../../mod/settings.php:630
+msgid "No name"
+msgstr "Inget namn"
+
+#: ../../mod/settings.php:631
+msgid "Remove authorization"
+msgstr "Ta bort behörighet"
+
+#: ../../mod/settings.php:642
+msgid "No feature settings configured"
+msgstr "Inga funktionsinställningar konfigurerade"
+
+#: ../../mod/settings.php:650
+msgid "Feature Settings"
+msgstr "Funktionsinställningar"
+
+#: ../../mod/settings.php:673
+msgid "Account Settings"
+msgstr "Kontoinställningar"
+
+#: ../../mod/settings.php:674
+msgid "Password Settings"
+msgstr "Lösenordsinställningar"
+
+#: ../../mod/settings.php:675
+msgid "New Password:"
+msgstr "Nytt lösenord:"
+
+#: ../../mod/settings.php:676
+msgid "Confirm:"
+msgstr "Bekräfta:"
+
+#: ../../mod/settings.php:676
+msgid "Leave password fields blank unless changing"
+msgstr "Lämna lösenordsfälten blanka om lösenordet inte ska ändras"
+
+#: ../../mod/settings.php:678 ../../mod/settings.php:1013
+msgid "Email Address:"
+msgstr "E-postadress"
+
+#: ../../mod/settings.php:679 ../../mod/removeaccount.php:61
+msgid "Remove Account"
+msgstr "Ta bort konto"
+
+#: ../../mod/settings.php:680
+msgid "Remove this account from this server including all its channels"
+msgstr "Ta bort det här kontot från servern, inklusive alla dess kanaler"
+
+#: ../../mod/settings.php:681 ../../mod/settings.php:1095
+msgid "Warning: This action is permanent and cannot be reversed."
+msgstr "Varning: Den här handlingen är permanent och kan inte återställas."
+
+#: ../../mod/settings.php:697
+msgid "Off"
+msgstr "Av"
+
+#: ../../mod/settings.php:697
+msgid "On"
+msgstr "På"
+
+#: ../../mod/settings.php:704
+msgid "Additional Features"
+msgstr "Ytterligare funktioner"
+
+#: ../../mod/settings.php:729
+msgid "Connector Settings"
+msgstr "Anslutningsinställningar"
+
+#: ../../mod/settings.php:768
+msgid "No special theme for mobile devices"
+msgstr "Inget särskilt tema för mobila enheter"
+
+#: ../../mod/settings.php:771
#, php-format
-msgid "I am over 13 years of age and accept the %s for this website"
-msgstr "Jag är över 13 år och accepterar den här webbplatsens %s"
+msgid "%s - (Experimental)"
+msgstr "%s - (experimentellt)"
-#: ../../mod/register.php:207 ../../mod/admin.php:413
-msgid "Registration"
-msgstr "Registrering"
+#: ../../mod/settings.php:774 ../../mod/admin.php:363
+msgid "mobile"
+msgstr "mobilt"
-#: ../../mod/register.php:212
-msgid "Membership on this site is by invitation only."
-msgstr "Medlemskap på den här servern kan endast fås genom inbjudan."
+#: ../../mod/settings.php:810
+msgid "Display Settings"
+msgstr "Utseende"
-#: ../../mod/register.php:213
-msgid "Please enter your invitation code"
-msgstr "Ange din inbjudningskod"
+#: ../../mod/settings.php:816
+msgid "Display Theme:"
+msgstr "Tema för utseende:"
-#: ../../mod/register.php:216
-msgid "Your email address"
-msgstr "Din e-postadress"
+#: ../../mod/settings.php:817
+msgid "Mobile Theme:"
+msgstr "Mobilt tema:"
-#: ../../mod/register.php:217
-msgid "Choose a password"
-msgstr "Välj ett lösenord"
+#: ../../mod/settings.php:818
+msgid "Enable user zoom on mobile devices"
+msgstr "Tillåt användare att zooma på mobila enheter"
-#: ../../mod/register.php:218
-msgid "Please re-enter your password"
-msgstr "Ange lösenordet igen"
+#: ../../mod/settings.php:819
+msgid "Update browser every xx seconds"
+msgstr "Uppdatera webbläsaren var xx sekund"
-#: ../../mod/filer.php:49
-msgid "- select -"
-msgstr "- välj -"
+#: ../../mod/settings.php:819
+msgid "Minimum of 10 seconds, no maximum"
+msgstr "Minst 10 sekunder, inget maximum"
-#: ../../mod/profperm.php:29 ../../mod/profperm.php:58
-msgid "Invalid profile identifier."
-msgstr "Ogiltigt profil-ID."
+#: ../../mod/settings.php:820
+msgid "Maximum number of conversations to load at any time:"
+msgstr "Högsta antal konversationer att ladda åt gången:"
-#: ../../mod/profperm.php:110
-msgid "Profile Visibility Editor"
-msgstr "Redigera profilsynlighet"
+#: ../../mod/settings.php:820
+msgid "Maximum of 100 items"
+msgstr "Maximalt 100 poster"
-#: ../../mod/profperm.php:114
-msgid "Click on a contact to add or remove."
-msgstr "Klicka på en kontakt för att lägga till eller ta bort."
+#: ../../mod/settings.php:821
+msgid "Don't show emoticons"
+msgstr "Visa inte känsloikoner"
-#: ../../mod/profperm.php:123
-msgid "Visible To"
-msgstr "Kan ses av"
+#: ../../mod/settings.php:822
+msgid "Link post titles to source"
+msgstr "Länka inläggstitlar till källan"
-#: ../../mod/profperm.php:139 ../../mod/connections.php:279
-msgid "All Connections"
+#: ../../mod/settings.php:823
+msgid "System Page Layout Editor - (advanced)"
+msgstr "Redigera systemets sidlayout (avancerat)"
+
+#: ../../mod/settings.php:826
+msgid "Use blog/list mode on channel page"
+msgstr "Använd blogg-/listläge på kanalsida"
+
+#: ../../mod/settings.php:826 ../../mod/settings.php:827
+msgid "(comments displayed separately)"
+msgstr "(kommentarer visas separat)"
+
+#: ../../mod/settings.php:827
+msgid "Use blog/list mode on matrix page"
+msgstr "Använd blogg-/listläge på matrissida"
+
+#: ../../mod/settings.php:828
+msgid "Channel page max height of content (in pixels)"
+msgstr "Maxhöjd för innehåll på kanalsidor (i pixels)"
+
+#: ../../mod/settings.php:828 ../../mod/settings.php:829
+msgid "click to expand content exceeding this height"
+msgstr "klicka för att fälla ut innehåll som överskrider den här höjden"
+
+#: ../../mod/settings.php:829
+msgid "Matrix page max height of content (in pixels)"
+msgstr "Maxhöjd för innehåll på matrissidan (i pixels)"
+
+#: ../../mod/settings.php:863
+msgid "Nobody except yourself"
+msgstr "Ingen utom dig själv"
+
+#: ../../mod/settings.php:864
+msgid "Only those you specifically allow"
+msgstr "Endast utvalda"
+
+#: ../../mod/settings.php:865
+msgid "Approved connections"
+msgstr "Godkända kontakter"
+
+#: ../../mod/settings.php:866
+msgid "Any connections"
msgstr "Alla kontakter"
-#: ../../mod/sources.php:32
-msgid "Failed to create source. No channel selected."
-msgstr "Misslyckades att skapa källa. Ingen kanal vald."
+#: ../../mod/settings.php:867
+msgid "Anybody on this website"
+msgstr "Vem som helst på den här servern"
-#: ../../mod/sources.php:45
-msgid "Source created."
-msgstr "Källa skapad."
+#: ../../mod/settings.php:868
+msgid "Anybody in this network"
+msgstr "Vem som helst i det här nätverket"
-#: ../../mod/sources.php:57
-msgid "Source updated."
-msgstr "Källa uppdaterad."
+#: ../../mod/settings.php:869
+msgid "Anybody authenticated"
+msgstr "Vem som helst som har autentiserat sig"
-#: ../../mod/sources.php:82
-msgid "*"
-msgstr "*"
+#: ../../mod/settings.php:870
+msgid "Anybody on the internet"
+msgstr "Vem som helst på Internet"
-#: ../../mod/sources.php:89
-msgid "Manage remote sources of content for your channel."
-msgstr "Hantera fjärrkällor med innehåll för din kanal."
+#: ../../mod/settings.php:944
+msgid "Publish your default profile in the network directory"
+msgstr "Publicera din standardprofil i nätverkskatalogen"
-#: ../../mod/sources.php:90 ../../mod/sources.php:100
-msgid "New Source"
-msgstr "Ny källa"
+#: ../../mod/settings.php:944 ../../mod/settings.php:949
+#: ../../mod/settings.php:1032 ../../mod/api.php:106
+#: ../../mod/profiles.php:592 ../../mod/admin.php:390
+msgid "No"
+msgstr "Nej"
-#: ../../mod/sources.php:101 ../../mod/sources.php:133
+#: ../../mod/settings.php:944 ../../mod/settings.php:949
+#: ../../mod/settings.php:1032 ../../mod/api.php:105
+#: ../../mod/profiles.php:591 ../../mod/admin.php:392
+msgid "Yes"
+msgstr "Ja"
+
+#: ../../mod/settings.php:949
+msgid "Allow us to suggest you as a potential friend to new members?"
+msgstr "Tillåt oss att föreslå dig som möjlig vän för nya medlemmar"
+
+#: ../../mod/settings.php:953 ../../mod/profile_photo.php:365
+msgid "or"
+msgstr "eller"
+
+#: ../../mod/settings.php:958
+msgid "Your channel address is"
+msgstr "Din kanaladress är"
+
+#: ../../mod/settings.php:1002
+msgid "Channel Settings"
+msgstr "Kanalinställningar"
+
+#: ../../mod/settings.php:1011
+msgid "Basic Settings"
+msgstr "Grundläggande inställningar"
+
+#: ../../mod/settings.php:1014
+msgid "Your Timezone:"
+msgstr "Din tidszon:"
+
+#: ../../mod/settings.php:1015
+msgid "Default Post Location:"
+msgstr "Standardplats:"
+
+#: ../../mod/settings.php:1015
+msgid "Geographical location to display on your posts"
+msgstr "Geografisk plats att visa för dina inlägg"
+
+#: ../../mod/settings.php:1016
+msgid "Use Browser Location:"
+msgstr "Använd webbläsarens position:"
+
+#: ../../mod/settings.php:1018
+msgid "Adult Content"
+msgstr "Innehåll olämpligt för barn"
+
+#: ../../mod/settings.php:1018
msgid ""
-"Import all or selected content from the following channel into this channel "
-"and distribute it according to your channel settings."
-msgstr "Importera allt eller valt innehåll från följande kanal till den här kanalen och distribuera det enligt dina kanalinställningar."
+"This channel frequently or regularly publishes adult content. (Please tag "
+"any adult material and/or nudity with #NSFW)"
+msgstr "Den här kanalen publicerar ofta eller regelbundet innehåll som är olämpligt för barn. (Tagga allt pornografiskt material och/eller nakenhet med #NSFW, tack)"
-#: ../../mod/sources.php:102 ../../mod/sources.php:134
-msgid "Only import content with these words (one per line)"
-msgstr "Importera endast innehåll med de här orden (ett per rad)"
+#: ../../mod/settings.php:1020
+msgid "Security and Privacy Settings"
+msgstr "Säkerhets- och integritetsinställningar"
-#: ../../mod/sources.php:102 ../../mod/sources.php:134
-msgid "Leave blank to import all public content"
-msgstr "Lämna blankt för att importera allt offentligt innehåll"
+#: ../../mod/settings.php:1022
+msgid "Your permissions are already configured. Click to view/adjust"
+msgstr "Dina behörigheter har redan ställts in. Klicka för att visa/ändra"
-#: ../../mod/sources.php:103 ../../mod/sources.php:137
-#: ../../mod/new_channel.php:112
-msgid "Channel Name"
-msgstr "Kanalnamn"
+#: ../../mod/settings.php:1024
+msgid "Hide my online presence"
+msgstr "Visa inte min online-närvaro"
-#: ../../mod/sources.php:123 ../../mod/sources.php:150
-msgid "Source not found."
-msgstr "Källa hittades inte."
+#: ../../mod/settings.php:1024
+msgid "Prevents displaying in your profile that you are online"
+msgstr "Förhindrar att det syns i din profil att du är online"
-#: ../../mod/sources.php:130
-msgid "Edit Source"
-msgstr "Redigera källa"
+#: ../../mod/settings.php:1026
+msgid "Simple Privacy Settings:"
+msgstr "Enkla integritetsinställningar:"
-#: ../../mod/sources.php:131
-msgid "Delete Source"
-msgstr "Ta bort källa"
+#: ../../mod/settings.php:1027
+msgid ""
+"Very Public - <em>extremely permissive (should be used with caution)</em>"
+msgstr "Väldigt offentligt - <em>extremt tillåtande (bör användas försiktigt)</em>"
-#: ../../mod/sources.php:158
-msgid "Source removed"
-msgstr "Källa borttagen"
+#: ../../mod/settings.php:1028
+msgid ""
+"Typical - <em>default public, privacy when desired (similar to social "
+"network permissions but with improved privacy)</em>"
+msgstr "Typiskt - <em>offentligt som standard, privat när så önskas (liknande behörigheter som på sociala nätverk men med förbättrad integritet)</em>"
-#: ../../mod/sources.php:160
-msgid "Unable to remove source."
-msgstr "Kunde inte ta bort källa."
+#: ../../mod/settings.php:1029
+msgid "Private - <em>default private, never open or public</em>"
+msgstr "Privat - <em>privat som standard, aldrig öppet eller offentligt</em>"
+
+#: ../../mod/settings.php:1030
+msgid "Blocked - <em>default blocked to/from everybody</em>"
+msgstr "Blockera - <em>som standard blockerat till/från alla</em>"
+
+#: ../../mod/settings.php:1032
+msgid "Allow others to tag your posts"
+msgstr "Låt andra tagga dina inlägg"
+
+#: ../../mod/settings.php:1032
+msgid ""
+"Often used by the community to retro-actively flag inappropriate content"
+msgstr "Ofta använt av gemenskapen för att i efterhand flagga olämpligt innehåll"
+
+#: ../../mod/settings.php:1034
+msgid "Advanced Privacy Settings"
+msgstr "Avancerade integritetsinställningar"
+
+#: ../../mod/settings.php:1036
+msgid "Expire other channel content after this many days"
+msgstr "Låt annat kanalinnehåll upphöra efter efter så här många dagar"
+
+#: ../../mod/settings.php:1036
+msgid "0 or blank prevents expiration"
+msgstr "0 eller blankt förhindrar upphörande"
+
+#: ../../mod/settings.php:1037
+msgid "Maximum Friend Requests/Day:"
+msgstr "Högsta antal vänförfrågningar per dag:"
+
+#: ../../mod/settings.php:1037
+msgid "May reduce spam activity"
+msgstr "Kan reducera spamaktivitet"
+
+#: ../../mod/settings.php:1038
+msgid "Default Post Permissions"
+msgstr "Standardbehörighet för inlägg"
+
+#: ../../mod/settings.php:1043
+msgid "Channel permissions category:"
+msgstr "Kanalens behörighetskategori:"
+
+#: ../../mod/settings.php:1051
+msgid "Maximum private messages per day from unknown people:"
+msgstr "Högsta antal privata meddelanden per dag från okända personer:"
+
+#: ../../mod/settings.php:1051
+msgid "Useful to reduce spamming"
+msgstr "Användbart för att minska skräputskick"
+
+#: ../../mod/settings.php:1054
+msgid "Notification Settings"
+msgstr "Notifieringsinställningar"
+
+#: ../../mod/settings.php:1055
+msgid "By default post a status message when:"
+msgstr "Skicka som standard ett statusmeddelande när:"
+
+#: ../../mod/settings.php:1056
+msgid "accepting a friend request"
+msgstr "du accepterar en vänförfrågan"
+
+#: ../../mod/settings.php:1057
+msgid "joining a forum/community"
+msgstr "du går med i ett forum/en gemenskap"
+
+#: ../../mod/settings.php:1058
+msgid "making an <em>interesting</em> profile change"
+msgstr "du gör en <em>intressant</em> ändring av profilen"
+
+#: ../../mod/settings.php:1059
+msgid "Send a notification email when:"
+msgstr "Skicka en notifiering via e-post när:"
+
+#: ../../mod/settings.php:1060
+msgid "You receive a connection request"
+msgstr "Du får en kontaktförfrågan"
+
+#: ../../mod/settings.php:1061
+msgid "Your connections are confirmed"
+msgstr "Dina kontakter bekräftas"
+
+#: ../../mod/settings.php:1062
+msgid "Someone writes on your profile wall"
+msgstr "Någon skriver på din profilvägg"
+
+#: ../../mod/settings.php:1063
+msgid "Someone writes a followup comment"
+msgstr "Någon skriver en uppföljande kommentar"
+
+#: ../../mod/settings.php:1064
+msgid "You receive a private message"
+msgstr "Du tar emot ett privat meddelande"
+
+#: ../../mod/settings.php:1065
+msgid "You receive a friend suggestion"
+msgstr "Du tar emot ett vänförslag"
+
+#: ../../mod/settings.php:1066
+msgid "You are tagged in a post"
+msgstr "Du taggas i ett inlägg"
+
+#: ../../mod/settings.php:1067
+msgid "You are poked/prodded/etc. in a post"
+msgstr "Du puffas/stöts till/etc. i ett inlägg"
+
+#: ../../mod/settings.php:1070
+msgid "Show visual notifications including:"
+msgstr "Visa visuella notifieringar vid:"
+
+#: ../../mod/settings.php:1072
+msgid "Unseen matrix activity"
+msgstr "Oläst matrisaktivitet"
+
+#: ../../mod/settings.php:1073
+msgid "Unseen channel activity"
+msgstr "Oläst kanalaktivitet"
+
+#: ../../mod/settings.php:1074
+msgid "Unseen private messages"
+msgstr "Olästa privata meddelanden"
+
+#: ../../mod/settings.php:1074 ../../mod/settings.php:1079
+#: ../../mod/settings.php:1080 ../../mod/settings.php:1081
+msgid "Recommended"
+msgstr "Rekommenderas"
+
+#: ../../mod/settings.php:1075
+msgid "Upcoming events"
+msgstr "Kommande händelser"
+
+#: ../../mod/settings.php:1076
+msgid "Events today"
+msgstr "Dagens händelser"
+
+#: ../../mod/settings.php:1077
+msgid "Upcoming birthdays"
+msgstr "Kommande födelsedagar"
+
+#: ../../mod/settings.php:1077
+msgid "Not available in all themes"
+msgstr "Inte tillgänglig i alla teman"
+
+#: ../../mod/settings.php:1078
+msgid "System (personal) notifications"
+msgstr "Systemmeddelanden (personliga)"
+
+#: ../../mod/settings.php:1079
+msgid "System info messages"
+msgstr "Systemmeddelanden"
+
+#: ../../mod/settings.php:1080
+msgid "System critical alerts"
+msgstr "Systemkritiska varningar"
+
+#: ../../mod/settings.php:1081
+msgid "New connections"
+msgstr "Nya kontakter"
+
+#: ../../mod/settings.php:1082
+msgid "System Registrations"
+msgstr "Systemregistreringar"
+
+#: ../../mod/settings.php:1084
+msgid "Notify me of events this many days in advance"
+msgstr "Meddela mig om händelser så här många dagar i förväg"
+
+#: ../../mod/settings.php:1084
+msgid "Must be greater than 0"
+msgstr "Måste vara större än 0"
+
+#: ../../mod/settings.php:1086
+msgid "Advanced Account/Page Type Settings"
+msgstr "Avancerade konto-/sidtypsinställningar"
+
+#: ../../mod/settings.php:1087
+msgid "Change the behaviour of this account for special situations"
+msgstr "Ändra det här kontots beteende i särskilda situationer"
+
+#: ../../mod/settings.php:1090
+msgid ""
+"Please enable expert mode (in <a href=\"settings/features\">Settings > "
+"Additional features</a>) to adjust!"
+msgstr "Aktivera expertläge (i <a href=\"settings/features\">Inställningar > Ytterligare funktioner</a>) för att göra ändringar!"
+
+#: ../../mod/settings.php:1091
+msgid "Miscellaneous Settings"
+msgstr "Diverse inställningar"
+
+#: ../../mod/settings.php:1093
+msgid "Personal menu to display in your channel pages"
+msgstr "Personlig meny att visa i dina kanalsidor"
+
+#: ../../mod/settings.php:1094
+msgid "Remove this channel"
+msgstr "Ta bort den här kanalen"
+
+#: ../../mod/group.php:20
+msgid "Collection created."
+msgstr "Krets skapad."
+
+#: ../../mod/group.php:26
+msgid "Could not create collection."
+msgstr "Kunde inte skapa krets."
+
+#: ../../mod/group.php:54
+msgid "Collection updated."
+msgstr "Kretsen uppdaterad."
+
+#: ../../mod/group.php:86
+msgid "Create a collection of channels."
+msgstr "Skapa en krets av kanaler."
+
+#: ../../mod/group.php:87 ../../mod/group.php:183
+msgid "Collection Name: "
+msgstr "Namn på krets: "
+
+#: ../../mod/group.php:89 ../../mod/group.php:186
+msgid "Members are visible to other channels"
+msgstr "Medlemmar kan ses av andra kanaler"
+
+#: ../../mod/group.php:107
+msgid "Collection removed."
+msgstr "Krets borttagen."
+
+#: ../../mod/group.php:109
+msgid "Unable to remove collection."
+msgstr "Kunde inte ta bort krets."
+
+#: ../../mod/group.php:182
+msgid "Collection Editor"
+msgstr "Redigera krets"
+
+#: ../../mod/group.php:196
+msgid "Members"
+msgstr "Medlemmar"
+
+#: ../../mod/group.php:198
+msgid "All Connected Channels"
+msgstr "Alla anslutna kanaler"
+
+#: ../../mod/group.php:233
+msgid "Click on a channel to add or remove."
+msgstr "Klicka på en kanal för att lägga till eller ta bort."
+
+#: ../../mod/search.php:13 ../../mod/photos.php:458 ../../mod/display.php:9
+#: ../../mod/viewconnections.php:17 ../../mod/directory.php:22
+msgid "Public access denied."
+msgstr "Offentlig behörighet saknas."
+
+#: ../../mod/subthread.php:103
+#, php-format
+msgid "%1$s is following %2$s's %3$s"
+msgstr "%1$s följer %2$ss %3$s"
#: ../../mod/poke.php:159
msgid "Poke/Prod"
@@ -4001,55 +4525,6 @@ msgid ""
" and/or create new posts for you?"
msgstr "Vill du låta den här applikationen få tillgång till dina inlägg och kontakter, och/eller skapa nya inlägg åt dig?"
-#: ../../mod/api.php:105 ../../mod/settings.php:937 ../../mod/settings.php:942
-#: ../../mod/settings.php:1025 ../../mod/profiles.php:591
-#: ../../mod/admin.php:392
-msgid "Yes"
-msgstr "Ja"
-
-#: ../../mod/api.php:106 ../../mod/settings.php:937 ../../mod/settings.php:942
-#: ../../mod/settings.php:1025 ../../mod/profiles.php:592
-#: ../../mod/admin.php:390
-msgid "No"
-msgstr "Nej"
-
-#: ../../mod/search.php:13 ../../mod/display.php:9
-#: ../../mod/viewconnections.php:17 ../../mod/directory.php:15
-#: ../../mod/photos.php:458
-msgid "Public access denied."
-msgstr "Offentlig behörighet saknas."
-
-#: ../../mod/attach.php:9
-msgid "Item not available."
-msgstr "Post inte tillgänglig."
-
-#: ../../mod/probe.php:23 ../../mod/probe.php:29
-#, php-format
-msgid "Fetching URL returns error: %1$s"
-msgstr "Hämtning av URL returnerade fel: %1$s"
-
-#: ../../mod/block.php:27 ../../mod/page.php:33
-msgid "Invalid item."
-msgstr "Ogiltig post."
-
-#: ../../mod/block.php:39 ../../mod/wall_upload.php:29 ../../mod/page.php:45
-msgid "Channel not found."
-msgstr "Kanalen hittas inte."
-
-#: ../../mod/block.php:75 ../../mod/display.php:102 ../../mod/help.php:70
-#: ../../mod/page.php:81 ../../index.php:241
-msgid "Page not found."
-msgstr "Sidan hittas inte."
-
-#: ../../mod/subthread.php:103
-#, php-format
-msgid "%1$s is following %2$s's %3$s"
-msgstr "%1$s följer %2$ss %3$s"
-
-#: ../../mod/blocks.php:99
-msgid "Block Name"
-msgstr "Blocknamn"
-
#: ../../mod/setup.php:166
msgid "Red Matrix Server - Setup"
msgstr "Red Matrix-server - inställningar"
@@ -4439,554 +4914,229 @@ msgid ""
"poller."
msgstr "VIKTIGT: Du behöver ställa in en schemalagd för hämtningsrutinen [manuellt]"
-#: ../../mod/settings.php:73
-msgid "Name is required"
-msgstr "Namn är obligatoriskt"
-
-#: ../../mod/settings.php:77
-msgid "Key and Secret are required"
-msgstr "Nyckel och kod är obligatoriska"
-
-#: ../../mod/settings.php:211
-msgid "Passwords do not match. Password unchanged."
-msgstr "Lösenorden stämmer inte överens. Lösenordet har inte ändrats."
-
-#: ../../mod/settings.php:215
-msgid "Empty passwords are not allowed. Password unchanged."
-msgstr "Tomma lösenord tillåts inte. Lösenordet har inte ändrats."
-
-#: ../../mod/settings.php:229
-msgid "Password changed."
-msgstr "Lösenordet ändrat."
-
-#: ../../mod/settings.php:231
-msgid "Password update failed. Please try again."
-msgstr "Lösenordsuppdatering misslyckades. Försök igen."
-
-#: ../../mod/settings.php:245
-msgid "Not valid email."
-msgstr "Inte en giltig e-postadress."
-
-#: ../../mod/settings.php:248
-msgid "Protected email address. Cannot change to that email."
-msgstr "Skyddad e-postadress. Kan inte ändra till den."
-
-#: ../../mod/settings.php:257
-msgid "System failure storing new email. Please try again."
-msgstr "Systemfel när ny e-postadress skulle sparas. Försök igen."
-
-#: ../../mod/settings.php:493
-msgid "Settings updated."
-msgstr "Inställningar uppdaterade."
-
-#: ../../mod/settings.php:562 ../../mod/settings.php:588
-#: ../../mod/settings.php:624
-msgid "Add application"
-msgstr "Lägg till applikation"
+#: ../../mod/attach.php:9
+msgid "Item not available."
+msgstr "Post inte tillgänglig."
-#: ../../mod/settings.php:565
-msgid "Name of application"
-msgstr "Applikationens namn"
+#: ../../mod/probe.php:23 ../../mod/probe.php:29
+#, php-format
+msgid "Fetching URL returns error: %1$s"
+msgstr "Hämtning av URL returnerade fel: %1$s"
-#: ../../mod/settings.php:566 ../../mod/settings.php:592
-msgid "Consumer Key"
-msgstr "Nyckel för konsument"
+#: ../../mod/block.php:27 ../../mod/page.php:33
+msgid "Invalid item."
+msgstr "Ogiltig post."
-#: ../../mod/settings.php:566 ../../mod/settings.php:567
-msgid "Automatically generated - change if desired. Max length 20"
-msgstr "Automatiskt genererad - ändra om så önskas. Maxlängd 20"
+#: ../../mod/block.php:39 ../../mod/wall_upload.php:29 ../../mod/page.php:45
+msgid "Channel not found."
+msgstr "Kanalen hittas inte."
-#: ../../mod/settings.php:567 ../../mod/settings.php:593
-msgid "Consumer Secret"
-msgstr "Kod för konsument"
+#: ../../mod/block.php:75 ../../mod/display.php:102 ../../mod/help.php:70
+#: ../../mod/page.php:81 ../../index.php:241
+msgid "Page not found."
+msgstr "Sidan hittas inte."
-#: ../../mod/settings.php:568 ../../mod/settings.php:594
-msgid "Redirect"
-msgstr "Omdirigering"
+#: ../../mod/uexport.php:33 ../../mod/uexport.php:34
+msgid "Export Channel"
+msgstr "Exportera kanal"
-#: ../../mod/settings.php:568
+#: ../../mod/uexport.php:35
msgid ""
-"Redirect URI - leave blank unless your application specifically requires "
-"this"
-msgstr "Omdirigerings-URI - lämna blankt om inte din applikation specifikt behöver det"
-
-#: ../../mod/settings.php:569 ../../mod/settings.php:595
-msgid "Icon url"
-msgstr "Ikon-URL"
-
-#: ../../mod/settings.php:569
-msgid "Optional"
-msgstr "Frivillig"
-
-#: ../../mod/settings.php:580
-msgid "You can't edit this application."
-msgstr "Du kan inte redigera den här applikationen."
-
-#: ../../mod/settings.php:623
-msgid "Connected Apps"
-msgstr "Anslutna appar"
-
-#: ../../mod/settings.php:627
-msgid "Client key starts with"
-msgstr "Klientnyckel börjar med"
-
-#: ../../mod/settings.php:628
-msgid "No name"
-msgstr "Inget namn"
-
-#: ../../mod/settings.php:629
-msgid "Remove authorization"
-msgstr "Ta bort behörighet"
-
-#: ../../mod/settings.php:640
-msgid "No feature settings configured"
-msgstr "Inga funktionsinställningar konfigurerade"
-
-#: ../../mod/settings.php:648
-msgid "Feature Settings"
-msgstr "Funktionsinställningar"
-
-#: ../../mod/settings.php:671
-msgid "Account Settings"
-msgstr "Kontoinställningar"
-
-#: ../../mod/settings.php:672
-msgid "Password Settings"
-msgstr "Lösenordsinställningar"
-
-#: ../../mod/settings.php:673
-msgid "New Password:"
-msgstr "Nytt lösenord:"
-
-#: ../../mod/settings.php:674
-msgid "Confirm:"
-msgstr "Bekräfta:"
+"Export your basic channel information to a small file. This acts as a "
+"backup of your connections, permissions, profile and basic data, which can "
+"be used to import your data to a new hub, but\tdoes not contain your "
+"content."
+msgstr "Exportera kanalens basinformation till en liten fil. Denna fungerar som en säkerhetskopia av dina anslutningar, behörigheter, profil, och grundläggande data, och kan användas för att importera dina data till en ny hubb, men tar inte med ditt innehåll."
+
+#: ../../mod/uexport.php:36
+msgid "Export Content"
+msgstr "Exportera innehåll"
-#: ../../mod/settings.php:674
-msgid "Leave password fields blank unless changing"
-msgstr "Lämna lösenordsfälten blanka om lösenordet inte ska ändras"
+#: ../../mod/uexport.php:37
+msgid ""
+"Export your channel information and all the content to a JSON backup. This "
+"backs up all of your connections, permissions, profile data and all of your "
+"content, but is generally not suitable for importing a channel to a new hub "
+"as this file may be VERY large. Please be patient - it may take several "
+"minutes for this download to begin."
+msgstr "Exportera din kanalinformation och allt innehåll till en säkerhetskopia i JSON-format. Detta kopierar alla dina anslutningar, behörigheter, profildata och allt ditt innehåll, men är generellt inte lämpligt för att importera en kanal till en ny hubb, eftersom filen kan vara VÄLDIGT stor. Ha tålamod - det kan ta flera minuter innan nedladdningen börjar."
-#: ../../mod/settings.php:676 ../../mod/settings.php:1006
-msgid "Email Address:"
-msgstr "E-postadress"
+#: ../../mod/delegate.php:95
+msgid "No potential page delegates located."
+msgstr "Inga potentiella sid-ombud funna."
-#: ../../mod/settings.php:677 ../../mod/removeaccount.php:61
-msgid "Remove Account"
-msgstr "Ta bort konto"
+#: ../../mod/delegate.php:121
+msgid "Delegate Page Management"
+msgstr "Delegera sidhantering"
-#: ../../mod/settings.php:678
-msgid "Remove this account from this server including all its channels"
-msgstr "Ta bort det här kontot från servern, inklusive alla dess kanaler"
+#: ../../mod/delegate.php:123
+msgid ""
+"Delegates are able to manage all aspects of this account/page except for "
+"basic account settings. Please do not delegate your personal account to "
+"anybody that you do not trust completely."
+msgstr "Ombud kan hantera alla aspekter av det här kontot/den här sidan förutom grundläggande kontoinställningar. Delegera inte ditt personliga konto till någon som du inte litar fullständigt på."
-#: ../../mod/settings.php:679 ../../mod/settings.php:1088
-msgid "Warning: This action is permanent and cannot be reversed."
-msgstr "Varning: Den här handlingen är permanent och kan inte återställas."
+#: ../../mod/delegate.php:124
+msgid "Existing Page Managers"
+msgstr "Befintliga sid-ansvariga"
-#: ../../mod/settings.php:695
-msgid "Off"
-msgstr "Av"
+#: ../../mod/delegate.php:126
+msgid "Existing Page Delegates"
+msgstr "Befintliga sid-ombud"
-#: ../../mod/settings.php:695
-msgid "On"
-msgstr "På"
+#: ../../mod/delegate.php:128
+msgid "Potential Delegates"
+msgstr "Potentiella ombud"
-#: ../../mod/settings.php:702
-msgid "Additional Features"
-msgstr "Ytterligare funktioner"
+#: ../../mod/delegate.php:130 ../../mod/photos.php:905 ../../mod/tagrm.php:133
+msgid "Remove"
+msgstr "Ta bort"
-#: ../../mod/settings.php:727
-msgid "Connector Settings"
-msgstr "Anslutningsinställningar"
+#: ../../mod/delegate.php:131
+msgid "Add"
+msgstr "Lägg till"
-#: ../../mod/settings.php:758
-msgid "No special theme for mobile devices"
-msgstr "Inget särskilt tema för mobila enheter"
+#: ../../mod/delegate.php:132
+msgid "No entries."
+msgstr "Inga poster."
-#: ../../mod/settings.php:767
+#: ../../mod/siteinfo.php:93
#, php-format
-msgid "%s - (Experimental)"
-msgstr "%s - (experimentellt)"
-
-#: ../../mod/settings.php:803
-msgid "Display Settings"
-msgstr "Utseende"
-
-#: ../../mod/settings.php:809
-msgid "Display Theme:"
-msgstr "Tema för utseende:"
-
-#: ../../mod/settings.php:810
-msgid "Mobile Theme:"
-msgstr "Mobilt tema:"
-
-#: ../../mod/settings.php:811
-msgid "Enable user zoom on mobile devices"
-msgstr "Tillåt användare att zooma på mobila enheter"
-
-#: ../../mod/settings.php:812
-msgid "Update browser every xx seconds"
-msgstr "Uppdatera webbläsaren var xx sekund"
-
-#: ../../mod/settings.php:812
-msgid "Minimum of 10 seconds, no maximum"
-msgstr "Minst 10 sekunder, inget maximum"
-
-#: ../../mod/settings.php:813
-msgid "Maximum number of conversations to load at any time:"
-msgstr "Högsta antal konversationer att ladda åt gången:"
-
-#: ../../mod/settings.php:813
-msgid "Maximum of 100 items"
-msgstr "Maximalt 100 poster"
-
-#: ../../mod/settings.php:814
-msgid "Don't show emoticons"
-msgstr "Visa inte känsloikoner"
-
-#: ../../mod/settings.php:815
-msgid "Link post titles to source"
-msgstr "Länka inläggstitlar till källan"
-
-#: ../../mod/settings.php:816
-msgid "System Page Layout Editor - (advanced)"
-msgstr "Redigera systemets sidlayout (avancerat)"
-
-#: ../../mod/settings.php:819
-msgid "Use blog/list mode on channel page"
-msgstr "Använd blogg-/listläge på kanalsida"
-
-#: ../../mod/settings.php:819 ../../mod/settings.php:820
-msgid "(comments displayed separately)"
-msgstr "(kommentarer visas separat)"
-
-#: ../../mod/settings.php:820
-msgid "Use blog/list mode on matrix page"
-msgstr "Använd blogg-/listläge på matrissida"
-
-#: ../../mod/settings.php:821
-msgid "Channel page max height of content (in pixels)"
-msgstr "Maxhöjd för innehåll på kanalsidor (i pixels)"
-
-#: ../../mod/settings.php:821 ../../mod/settings.php:822
-msgid "click to expand content exceeding this height"
-msgstr "klicka för att fälla ut innehåll som överskrider den här höjden"
-
-#: ../../mod/settings.php:822
-msgid "Matrix page max height of content (in pixels)"
-msgstr "Maxhöjd för innehåll på matrissidan (i pixels)"
-
-#: ../../mod/settings.php:856
-msgid "Nobody except yourself"
-msgstr "Ingen utom dig själv"
-
-#: ../../mod/settings.php:857
-msgid "Only those you specifically allow"
-msgstr "Endast utvalda"
-
-#: ../../mod/settings.php:858
-msgid "Approved connections"
-msgstr "Godkända kontakter"
-
-#: ../../mod/settings.php:859
-msgid "Any connections"
-msgstr "Alla kontakter"
-
-#: ../../mod/settings.php:860
-msgid "Anybody on this website"
-msgstr "Vem som helst på den här servern"
-
-#: ../../mod/settings.php:861
-msgid "Anybody in this network"
-msgstr "Vem som helst i det här nätverket"
-
-#: ../../mod/settings.php:862
-msgid "Anybody authenticated"
-msgstr "Vem som helst som har autentiserat sig"
-
-#: ../../mod/settings.php:863
-msgid "Anybody on the internet"
-msgstr "Vem som helst på Internet"
-
-#: ../../mod/settings.php:937
-msgid "Publish your default profile in the network directory"
-msgstr "Publicera din standardprofil i nätverkskatalogen"
-
-#: ../../mod/settings.php:942
-msgid "Allow us to suggest you as a potential friend to new members?"
-msgstr "Tillåt oss att föreslå dig som möjlig vän för nya medlemmar"
-
-#: ../../mod/settings.php:946 ../../mod/profile_photo.php:365
-msgid "or"
-msgstr "eller"
-
-#: ../../mod/settings.php:951
-msgid "Your channel address is"
-msgstr "Din kanaladress är"
-
-#: ../../mod/settings.php:995
-msgid "Channel Settings"
-msgstr "Kanalinställningar"
-
-#: ../../mod/settings.php:1004
-msgid "Basic Settings"
-msgstr "Grundläggande inställningar"
-
-#: ../../mod/settings.php:1007
-msgid "Your Timezone:"
-msgstr "Din tidszon:"
-
-#: ../../mod/settings.php:1008
-msgid "Default Post Location:"
-msgstr "Standardplats:"
+msgid "Version %s"
+msgstr "Version %s"
-#: ../../mod/settings.php:1008
-msgid "Geographical location to display on your posts"
-msgstr "Geografisk plats att visa för dina inlägg"
+#: ../../mod/siteinfo.php:114
+msgid "Installed plugins/addons/apps:"
+msgstr "Installerade tillägg/moduler/appar:"
-#: ../../mod/settings.php:1009
-msgid "Use Browser Location:"
-msgstr "Använd webbläsarens position:"
+#: ../../mod/siteinfo.php:127
+msgid "No installed plugins/addons/apps"
+msgstr "Inga installerade tillägg/moduler/appar"
-#: ../../mod/settings.php:1011
-msgid "Adult Content"
-msgstr "Innehåll olämpligt för barn"
+#: ../../mod/siteinfo.php:135
+msgid "Red"
+msgstr "Red"
-#: ../../mod/settings.php:1011
+#: ../../mod/siteinfo.php:136
msgid ""
-"This channel frequently or regularly publishes adult content. (Please tag "
-"any adult material and/or nudity with #NSFW)"
-msgstr "Den här kanalen publicerar ofta eller regelbundet innehåll som är olämpligt för barn. (Tagga allt pornografiskt material och/eller nakenhet med #NSFW, tack)"
-
-#: ../../mod/settings.php:1013
-msgid "Security and Privacy Settings"
-msgstr "Säkerhets- och integritetsinställningar"
-
-#: ../../mod/settings.php:1015
-msgid "Your permissions are already configured. Click to view/adjust"
-msgstr "Dina behörigheter har redan ställts in. Klicka för att visa/ändra"
-
-#: ../../mod/settings.php:1017
-msgid "Hide my online presence"
-msgstr "Visa inte min online-närvaro"
+"This is a hub of the Red Matrix - a global cooperative network of "
+"decentralized privacy enhanced websites."
+msgstr "Det här är en hubb som ingår i Red Matrix - ett globalt samverkande nätverk av decentraliserade webbplatser med bättre integritetskydd."
-#: ../../mod/settings.php:1017
-msgid "Prevents displaying in your profile that you are online"
-msgstr "Förhindrar att det syns i din profil att du är online"
+#: ../../mod/siteinfo.php:138
+msgid "Tag: "
+msgstr "Tagg: "
-#: ../../mod/settings.php:1019
-msgid "Simple Privacy Settings:"
-msgstr "Enkla integritetsinställningar:"
+#: ../../mod/siteinfo.php:140
+msgid "Last background fetch: "
+msgstr "Senaste bakgrundshämtning: "
-#: ../../mod/settings.php:1020
-msgid ""
-"Very Public - <em>extremely permissive (should be used with caution)</em>"
-msgstr "Väldigt offentligt - <em>extremt tillåtande (bör användas försiktigt)</em>"
+#: ../../mod/siteinfo.php:143
+msgid "Running at web location"
+msgstr "Kör på webbutrymmet"
-#: ../../mod/settings.php:1021
+#: ../../mod/siteinfo.php:144
msgid ""
-"Typical - <em>default public, privacy when desired (similar to social "
-"network permissions but with improved privacy)</em>"
-msgstr "Typiskt - <em>offentligt som standard, privat när så önskas (liknande behörigheter som på sociala nätverk men med förbättrad integritet)</em>"
+"Please visit <a href=\"https://redmatrix.me\">RedMatrix.me</a> to learn more"
+" about the Red Matrix."
+msgstr "Besök <a href=\"https://redmatrix.me\">RedMatrix.me</a> för att lära dig mer om Red Matrix."
-#: ../../mod/settings.php:1022
-msgid "Private - <em>default private, never open or public</em>"
-msgstr "Privat - <em>privat som standard, aldrig öppet eller offentligt</em>"
-
-#: ../../mod/settings.php:1023
-msgid "Blocked - <em>default blocked to/from everybody</em>"
-msgstr "Blockera - <em>som standard blockerat till/från alla</em>"
-
-#: ../../mod/settings.php:1025
-msgid "Allow others to tag your posts"
-msgstr "Låt andra tagga dina inlägg"
+#: ../../mod/siteinfo.php:145
+msgid "Bug reports and issues: please visit"
+msgstr "Buggrapporter och problem: besök"
-#: ../../mod/settings.php:1025
+#: ../../mod/siteinfo.php:148
msgid ""
-"Often used by the community to retro-actively flag inappropriate content"
-msgstr "Ofta använt av gemenskapen för att i efterhand flagga olämpligt innehåll"
-
-#: ../../mod/settings.php:1027
-msgid "Advanced Privacy Settings"
-msgstr "Avancerade integritetsinställningar"
-
-#: ../../mod/settings.php:1029
-msgid "Expire other channel content after this many days"
-msgstr "Låt annat kanalinnehåll upphöra efter efter så här många dagar"
-
-#: ../../mod/settings.php:1029
-msgid "0 or blank prevents expiration"
-msgstr "0 eller blankt förhindrar upphörande"
-
-#: ../../mod/settings.php:1030
-msgid "Maximum Friend Requests/Day:"
-msgstr "Högsta antal vänförfrågningar per dag:"
-
-#: ../../mod/settings.php:1030
-msgid "May reduce spam activity"
-msgstr "Kan reducera spamaktivitet"
-
-#: ../../mod/settings.php:1031
-msgid "Default Post Permissions"
-msgstr "Standardbehörighet för inlägg"
-
-#: ../../mod/settings.php:1036
-msgid "Channel permissions category:"
-msgstr "Kanalens behörighetskategori:"
-
-#: ../../mod/settings.php:1044
-msgid "Maximum private messages per day from unknown people:"
-msgstr "Högsta antal privata meddelanden per dag från okända personer:"
-
-#: ../../mod/settings.php:1044
-msgid "Useful to reduce spamming"
-msgstr "Användbart för att minska skräputskick"
-
-#: ../../mod/settings.php:1047
-msgid "Notification Settings"
-msgstr "Notifieringsinställningar"
-
-#: ../../mod/settings.php:1048
-msgid "By default post a status message when:"
-msgstr "Skicka som standard ett statusmeddelande när:"
-
-#: ../../mod/settings.php:1049
-msgid "accepting a friend request"
-msgstr "du accepterar en vänförfrågan"
-
-#: ../../mod/settings.php:1050
-msgid "joining a forum/community"
-msgstr "du går med i ett forum/en gemenskap"
-
-#: ../../mod/settings.php:1051
-msgid "making an <em>interesting</em> profile change"
-msgstr "du gör en <em>intressant</em> ändring av profilen"
-
-#: ../../mod/settings.php:1052
-msgid "Send a notification email when:"
-msgstr "Skicka en notifiering via e-post när:"
-
-#: ../../mod/settings.php:1053
-msgid "You receive a connection request"
-msgstr "Du får en kontaktförfrågan"
-
-#: ../../mod/settings.php:1054
-msgid "Your connections are confirmed"
-msgstr "Dina kontakter bekräftas"
-
-#: ../../mod/settings.php:1055
-msgid "Someone writes on your profile wall"
-msgstr "Någon skriver på din profilvägg"
-
-#: ../../mod/settings.php:1056
-msgid "Someone writes a followup comment"
-msgstr "Någon skriver en uppföljande kommentar"
-
-#: ../../mod/settings.php:1057
-msgid "You receive a private message"
-msgstr "Du tar emot ett privat meddelande"
-
-#: ../../mod/settings.php:1058
-msgid "You receive a friend suggestion"
-msgstr "Du tar emot ett vänförslag"
-
-#: ../../mod/settings.php:1059
-msgid "You are tagged in a post"
-msgstr "Du taggas i ett inlägg"
-
-#: ../../mod/settings.php:1060
-msgid "You are poked/prodded/etc. in a post"
-msgstr "Du puffas/stöts till/etc. i ett inlägg"
-
-#: ../../mod/settings.php:1063
-msgid "Show visual notifications including:"
-msgstr "Visa visuella notifieringar vid:"
+"Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot "
+"com"
+msgstr "Förslag, uppskattning, etc. - maila \"redmatrix\" at librelist - dot com"
-#: ../../mod/settings.php:1065
-msgid "Unseen matrix activity"
-msgstr "Oläst matrisaktivitet"
+#: ../../mod/siteinfo.php:150
+msgid "Site Administrators"
+msgstr "Serveradministratörer"
-#: ../../mod/settings.php:1066
-msgid "Unseen channel activity"
-msgstr "Oläst kanalaktivitet"
+#: ../../mod/sources.php:32
+msgid "Failed to create source. No channel selected."
+msgstr "Misslyckades att skapa källa. Ingen kanal vald."
-#: ../../mod/settings.php:1067
-msgid "Unseen private messages"
-msgstr "Olästa privata meddelanden"
+#: ../../mod/sources.php:45
+msgid "Source created."
+msgstr "Källa skapad."
-#: ../../mod/settings.php:1067 ../../mod/settings.php:1072
-#: ../../mod/settings.php:1073 ../../mod/settings.php:1074
-msgid "Recommended"
-msgstr "Rekommenderas"
+#: ../../mod/sources.php:57
+msgid "Source updated."
+msgstr "Källa uppdaterad."
-#: ../../mod/settings.php:1068
-msgid "Upcoming events"
-msgstr "Kommande händelser"
+#: ../../mod/sources.php:82
+msgid "*"
+msgstr "*"
-#: ../../mod/settings.php:1069
-msgid "Events today"
-msgstr "Dagens händelser"
+#: ../../mod/sources.php:89
+msgid "Manage remote sources of content for your channel."
+msgstr "Hantera fjärrkällor med innehåll för din kanal."
-#: ../../mod/settings.php:1070
-msgid "Upcoming birthdays"
-msgstr "Kommande födelsedagar"
+#: ../../mod/sources.php:90 ../../mod/sources.php:100
+msgid "New Source"
+msgstr "Ny källa"
-#: ../../mod/settings.php:1070
-msgid "Not available in all themes"
-msgstr "Inte tillgänglig i alla teman"
+#: ../../mod/sources.php:101 ../../mod/sources.php:133
+msgid ""
+"Import all or selected content from the following channel into this channel "
+"and distribute it according to your channel settings."
+msgstr "Importera allt eller valt innehåll från följande kanal till den här kanalen och distribuera det enligt dina kanalinställningar."
-#: ../../mod/settings.php:1071
-msgid "System (personal) notifications"
-msgstr "Systemmeddelanden (personliga)"
+#: ../../mod/sources.php:102 ../../mod/sources.php:134
+msgid "Only import content with these words (one per line)"
+msgstr "Importera endast innehåll med de här orden (ett per rad)"
-#: ../../mod/settings.php:1072
-msgid "System info messages"
-msgstr "Systemmeddelanden"
+#: ../../mod/sources.php:102 ../../mod/sources.php:134
+msgid "Leave blank to import all public content"
+msgstr "Lämna blankt för att importera allt offentligt innehåll"
-#: ../../mod/settings.php:1073
-msgid "System critical alerts"
-msgstr "Systemkritiska varningar"
+#: ../../mod/sources.php:103 ../../mod/sources.php:137
+#: ../../mod/new_channel.php:112
+msgid "Channel Name"
+msgstr "Kanalnamn"
-#: ../../mod/settings.php:1074
-msgid "New connections"
-msgstr "Nya kontakter"
+#: ../../mod/sources.php:123 ../../mod/sources.php:150
+msgid "Source not found."
+msgstr "Källa hittades inte."
-#: ../../mod/settings.php:1075
-msgid "System Registrations"
-msgstr "Systemregistreringar"
+#: ../../mod/sources.php:130
+msgid "Edit Source"
+msgstr "Redigera källa"
-#: ../../mod/settings.php:1077
-msgid "Notify me of events this many days in advance"
-msgstr "Meddela mig om händelser så här många dagar i förväg"
+#: ../../mod/sources.php:131
+msgid "Delete Source"
+msgstr "Ta bort källa"
-#: ../../mod/settings.php:1077
-msgid "Must be greater than 0"
-msgstr "Måste vara större än 0"
+#: ../../mod/sources.php:158
+msgid "Source removed"
+msgstr "Källa borttagen"
-#: ../../mod/settings.php:1079
-msgid "Advanced Account/Page Type Settings"
-msgstr "Avancerade konto-/sidtypsinställningar"
+#: ../../mod/sources.php:160
+msgid "Unable to remove source."
+msgstr "Kunde inte ta bort källa."
-#: ../../mod/settings.php:1080
-msgid "Change the behaviour of this account for special situations"
-msgstr "Ändra det här kontots beteende i särskilda situationer"
+#: ../../mod/profperm.php:29 ../../mod/profperm.php:58
+msgid "Invalid profile identifier."
+msgstr "Ogiltigt profil-ID."
-#: ../../mod/settings.php:1083
-msgid ""
-"Please enable expert mode (in <a href=\"settings/features\">Settings > "
-"Additional features</a>) to adjust!"
-msgstr "Aktivera expertläge (i <a href=\"settings/features\">Inställningar > Ytterligare funktioner</a>) för att göra ändringar!"
+#: ../../mod/profperm.php:110
+msgid "Profile Visibility Editor"
+msgstr "Redigera profilsynlighet"
-#: ../../mod/settings.php:1084
-msgid "Miscellaneous Settings"
-msgstr "Diverse inställningar"
+#: ../../mod/profperm.php:114
+msgid "Click on a contact to add or remove."
+msgstr "Klicka på en kontakt för att lägga till eller ta bort."
-#: ../../mod/settings.php:1086
-msgid "Personal menu to display in your channel pages"
-msgstr "Personlig meny att visa i dina kanalsidor"
+#: ../../mod/profperm.php:123
+msgid "Visible To"
+msgstr "Kan ses av"
-#: ../../mod/settings.php:1087
-msgid "Remove this channel"
-msgstr "Ta bort den här kanalen"
+#: ../../mod/profperm.php:139 ../../mod/connections.php:279
+msgid "All Connections"
+msgstr "Alla kontakter"
#: ../../mod/events.php:81
msgid "Event can not end before it has started."
@@ -5028,6 +5178,10 @@ msgstr "Detaljer för händelse"
msgid "Starting date and Title are required."
msgstr "Startdatum och titel är obligatoriska."
+#: ../../mod/events.php:574
+msgid "Categories (comma-separated list)"
+msgstr "Kategorier (kommaseparerad lista)"
+
#: ../../mod/events.php:576
msgid "Event Starts:"
msgstr "Händelsen börjar:"
@@ -5094,7 +5248,7 @@ msgstr "Plats"
msgid "You must be logged in to see this page."
msgstr "Du måste vara inloggad för att se den här sidan."
-#: ../../mod/channel.php:86
+#: ../../mod/channel.php:87
msgid "Insufficient permissions. Request redirected to profile page."
msgstr "Otillräckliga behörigheter. Förfrågan omdirigerad till profilsidan."
@@ -5155,53 +5309,6 @@ msgstr "Namn på chattrum"
msgid "%1$s's Chatrooms"
msgstr "%1$ss chattrum"
-#: ../../mod/siteinfo.php:92
-#, php-format
-msgid "Version %s"
-msgstr "Version %s"
-
-#: ../../mod/siteinfo.php:113
-msgid "Installed plugins/addons/apps:"
-msgstr "Installerade tillägg/moduler/appar:"
-
-#: ../../mod/siteinfo.php:126
-msgid "No installed plugins/addons/apps"
-msgstr "Inga installerade tillägg/moduler/appar"
-
-#: ../../mod/siteinfo.php:134
-msgid "Red"
-msgstr "Red"
-
-#: ../../mod/siteinfo.php:135
-msgid ""
-"This is a hub of the Red Matrix - a global cooperative network of "
-"decentralized privacy enhanced websites."
-msgstr "Det här är en hubb som ingår i Red Matrix - ett globalt samverkande nätverk av decentraliserade webbplatser med bättre integritetskydd."
-
-#: ../../mod/siteinfo.php:139
-msgid "Running at web location"
-msgstr "Kör på webbutrymmet"
-
-#: ../../mod/siteinfo.php:140
-msgid ""
-"Please visit <a href=\"http://getzot.com\">GetZot.com</a> to learn more "
-"about the Red Matrix."
-msgstr "Besök <a href=\"http://getzot.com\">GetZot.com</a> lära dig mer om Red Matrix."
-
-#: ../../mod/siteinfo.php:141
-msgid "Bug reports and issues: please visit"
-msgstr "Buggrapporter och problem: besök"
-
-#: ../../mod/siteinfo.php:144
-msgid ""
-"Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot "
-"com"
-msgstr "Förslag, uppskattning, etc. - maila \"redmatrix\" at librelist - dot com"
-
-#: ../../mod/siteinfo.php:146
-msgid "Site Administrators"
-msgstr "Serveradministratörer"
-
#: ../../mod/chatsvc.php:111
msgid "Away"
msgstr "Borta"
@@ -5214,48 +5321,38 @@ msgstr "Online"
msgid "Please login."
msgstr "Logga in."
-#: ../../mod/connect.php:56 ../../mod/connect.php:104
-msgid "Continue"
-msgstr "Fortsätt"
-
-#: ../../mod/connect.php:85
-msgid "Premium Channel Setup"
-msgstr "Inställning av premiumkanal"
-
-#: ../../mod/connect.php:87
-msgid "Enable premium channel connection restrictions"
-msgstr "Aktivera kontaktrestriktioner för premiumkanal"
+#: ../../mod/editpost.php:20 ../../mod/editblock.php:79
+#: ../../mod/editblock.php:95 ../../mod/editlayout.php:78
+#: ../../mod/editwebpage.php:77
+msgid "Item not found"
+msgstr "Posten hittas inte"
-#: ../../mod/connect.php:88
-msgid ""
-"Please enter your restrictions or conditions, such as paypal receipt, usage "
-"guidelines, etc."
-msgstr "Ange dina restriktioner och villkor, som Paypal-kvitto, användarriktlinjer, etc."
+#: ../../mod/editpost.php:31
+msgid "Item is not editable"
+msgstr "Posten går ej att redigera"
-#: ../../mod/connect.php:90 ../../mod/connect.php:110
-msgid ""
-"This channel may require additional steps or acknowledgement of the "
-"following conditions prior to connecting:"
-msgstr "Den här kanalen kan kräva ytterligare steg eller godkännande av följande villkor innan anslutning:"
+#: ../../mod/editpost.php:42 ../../mod/rpost.php:97
+msgid "Edit post"
+msgstr "Redigera inlägg"
-#: ../../mod/connect.php:91
-msgid ""
-"Potential connections will then see the following text before proceeding:"
-msgstr "Potentiella kontakter kommer sedan att se följande text innan de går vidare:"
+#: ../../mod/editpost.php:53
+msgid "Delete item?"
+msgstr "Ta bort posten?"
-#: ../../mod/connect.php:92 ../../mod/connect.php:113
-msgid ""
-"By continuing, I certify that I have complied with any instructions provided"
-" on this page."
-msgstr "Genom att fortsätta intygar jag att jag har följt alla instruktioner som ges på den här sidan."
+#: ../../mod/editpost.php:116 ../../mod/editblock.php:147
+#: ../../mod/editlayout.php:143 ../../mod/editwebpage.php:178
+msgid "Insert YouTube video"
+msgstr "Infoga Youtube-video"
-#: ../../mod/connect.php:101
-msgid "(No specific instructions have been provided by the channel owner.)"
-msgstr "(Inga specifika instruktioner har givits av kanalägaren.)"
+#: ../../mod/editpost.php:117 ../../mod/editblock.php:148
+#: ../../mod/editlayout.php:144 ../../mod/editwebpage.php:179
+msgid "Insert Vorbis [.ogg] video"
+msgstr "Infoga Vorbis [.ogg]-video"
-#: ../../mod/connect.php:109
-msgid "Restricted or Premium Channel"
-msgstr "Begränsad kanal eller premiumkanal"
+#: ../../mod/editpost.php:118 ../../mod/editblock.php:149
+#: ../../mod/editlayout.php:145 ../../mod/editwebpage.php:180
+msgid "Insert Vorbis [.ogg] audio"
+msgstr "Infoga Vorbis [.ogg]-ljud"
#: ../../mod/removeme.php:29
msgid ""
@@ -5329,54 +5426,78 @@ msgstr "Ange din kanaladress (t.ex. kanal@example.com)"
msgid "Authenticate"
msgstr "Autentisera"
-#: ../../mod/like.php:15
-msgid "Like/Dislike"
-msgstr "Gilla/ogilla"
+#: ../../mod/lostpass.php:15
+msgid "No valid account found."
+msgstr "Inget giltigt konto hittades."
-#: ../../mod/like.php:20
-msgid "This action is restricted to members."
-msgstr "Den här åtgärden fungerar bara för medlemmar."
+#: ../../mod/lostpass.php:29
+msgid "Password reset request issued. Check your email."
+msgstr "Lösenordsåterställning har skickats. Kontrollera din e-post."
-#: ../../mod/like.php:21
-msgid ""
-"Please <a href=\"rmagic\">login with your RedMatrix ID</a> or <a "
-"href=\"register\">register as a new RedMatrix member</a> to continue."
-msgstr "<a href=\"rmagic\">Logga in med ditt RedMatrix-ID</a> eller <a href=\"register\">registrera dig som ny RedMatrix medlem</a> för att fortsätta."
+#: ../../mod/lostpass.php:35 ../../mod/lostpass.php:102
+#, php-format
+msgid "Site Member (%s)"
+msgstr "Servermedlem (%s)"
-#: ../../mod/like.php:77 ../../mod/like.php:104 ../../mod/like.php:142
-msgid "Invalid request."
-msgstr "Ogiltig begäran."
+#: ../../mod/lostpass.php:40
+#, php-format
+msgid "Password reset requested at %s"
+msgstr "Lösenordsåterställning begärd på %s"
-#: ../../mod/like.php:119
-msgid "thing"
-msgstr "sak"
+#: ../../mod/lostpass.php:63
+msgid ""
+"Request could not be verified. (You may have previously submitted it.) "
+"Password reset failed."
+msgstr "Begäran kunde inte bekräftas. (Du kan ha skickat den tidigare.) Lösenordsåterställningen misslyckades."
-#: ../../mod/like.php:165
-msgid "Channel unavailable."
-msgstr "Kanalen kan ej nås."
+#: ../../mod/lostpass.php:85 ../../boot.php:1548
+msgid "Password Reset"
+msgstr "Lösenordsåterställning"
-#: ../../mod/like.php:204
-msgid "Previous action reversed."
-msgstr "Föregående åtgärd återställdes."
+#: ../../mod/lostpass.php:86
+msgid "Your password has been reset as requested."
+msgstr "Ditt lösenord har återställts som begärt."
-#: ../../mod/like.php:422
-msgid "Action completed."
-msgstr "Åtgärden slutfördes."
+#: ../../mod/lostpass.php:87
+msgid "Your new password is"
+msgstr "Ditt nya lösenord är"
-#: ../../mod/like.php:423
-msgid "Thank you."
-msgstr "Tack."
+#: ../../mod/lostpass.php:88
+msgid "Save or copy your new password - and then"
+msgstr "Spara eller kopiera ditt nya lösenord - "
-#: ../../mod/post.php:229
+#: ../../mod/lostpass.php:89
+msgid "click here to login"
+msgstr "klicka sedan här för att logga in"
+
+#: ../../mod/lostpass.php:90
msgid ""
-"Remote authentication blocked. You are logged into this site locally. Please"
-" logout and retry."
-msgstr "Fjärrinloggning blockerades. Du är inloggad på den här servern lokalt. Logga ut och försök igen."
+"Your password may be changed from the <em>Settings</em> page after "
+"successful login."
+msgstr "Ditt lösenord kan bytas från sidan <em>Inställningar</em> när du är inloggad."
-#: ../../mod/post.php:261 ../../mod/openid.php:72 ../../mod/openid.php:180
+#: ../../mod/lostpass.php:107
#, php-format
-msgid "Welcome %s. Remote authentication successful."
-msgstr "Välkommen %s. Fjärrinloggning lyckades."
+msgid "Your password has changed at %s"
+msgstr "Ditt lösenord byttes på %s"
+
+#: ../../mod/lostpass.php:122
+msgid "Forgot your Password?"
+msgstr "Glömt lösenordet?"
+
+#: ../../mod/lostpass.php:123
+msgid ""
+"Enter your email address and submit to have your password reset. Then check "
+"your email for further instructions."
+msgstr "Ange din e-postadress och skicka för att återställa ditt lösenord. Kontrollera sedan din e-post för vidare instruktioner."
+
+#: ../../mod/lostpass.php:124
+msgid "Email Address"
+msgstr "E-postadress"
+
+#: ../../mod/lostpass.php:125
+msgid "Reset"
+msgstr "Återställ"
#: ../../mod/connections.php:37 ../../mod/connedit.php:64
msgid "Could not access contact record."
@@ -5471,13 +5592,17 @@ msgstr "Sök bland dina kontakter"
msgid "Finding: "
msgstr "Sökning efter: "
-#: ../../mod/openid.php:26
-msgid "OpenID protocol error. No ID returned."
-msgstr "Protokollfel för OpenID. Inget ID returnerades."
+#: ../../mod/ping.php:265
+msgid "sent you a private message"
+msgstr "skickade ett privat meddelande till dig"
-#: ../../mod/rpost.php:97 ../../mod/editpost.php:42
-msgid "Edit post"
-msgstr "Redigera inlägg"
+#: ../../mod/ping.php:316
+msgid "added your channel"
+msgstr "lade till din kanal"
+
+#: ../../mod/ping.php:357
+msgid "posted an event"
+msgstr "skapade en händelse"
#: ../../mod/connedit.php:189
msgid "is now connected to"
@@ -5562,12 +5687,12 @@ msgstr "Senaste aktiviteten"
msgid "View recent posts and comments"
msgstr "Visa de senaste inläggen och kommentarerna"
-#: ../../mod/connedit.php:450 ../../mod/connedit.php:594
+#: ../../mod/connedit.php:450 ../../mod/connedit.php:595
#: ../../mod/admin.php:732
msgid "Unblock"
msgstr "Avblockera"
-#: ../../mod/connedit.php:450 ../../mod/connedit.php:594
+#: ../../mod/connedit.php:450 ../../mod/connedit.php:595
#: ../../mod/admin.php:731
msgid "Block"
msgstr "Blockera"
@@ -5576,11 +5701,11 @@ msgstr "Blockera"
msgid "Block or Unblock this connection"
msgstr "Blockera eller häv blockering av den här kontakten"
-#: ../../mod/connedit.php:457 ../../mod/connedit.php:595
+#: ../../mod/connedit.php:457 ../../mod/connedit.php:596
msgid "Unignore"
msgstr "Sluta att ignorera"
-#: ../../mod/connedit.php:457 ../../mod/connedit.php:595
+#: ../../mod/connedit.php:457 ../../mod/connedit.php:596
#: ../../mod/notifications.php:51
msgid "Ignore"
msgstr "Ignorera"
@@ -5617,101 +5742,101 @@ msgstr "Dölj eller sluta att dölja den här kontakten"
msgid "Delete this connection"
msgstr "Ta bort den här kontakten"
-#: ../../mod/connedit.php:522 ../../mod/connedit.php:552
+#: ../../mod/connedit.php:523 ../../mod/connedit.php:553
msgid "Approve this connection"
msgstr "Godkänn den här kontakten"
-#: ../../mod/connedit.php:522
+#: ../../mod/connedit.php:523
msgid "Accept connection to allow communication"
msgstr "Acceptera kontakten för att tillåta kommunikation"
-#: ../../mod/connedit.php:538
+#: ../../mod/connedit.php:539
#, php-format
msgid "Connections: settings for %s"
msgstr "Kontakter: inställningar för %s"
-#: ../../mod/connedit.php:539
+#: ../../mod/connedit.php:540
msgid "Apply these permissions automatically"
msgstr "Använd de här rättigheterna automatiskt"
-#: ../../mod/connedit.php:543
+#: ../../mod/connedit.php:544
msgid "Apply the permissions indicated on this page to all new connections."
msgstr "Använd rättigheterna angivna på den här sidan för alla nya kontakter."
-#: ../../mod/connedit.php:545
+#: ../../mod/connedit.php:546
msgid "Slide to adjust your degree of friendship"
msgstr "Dra för att justera er vänskapsnivå"
-#: ../../mod/connedit.php:551
+#: ../../mod/connedit.php:552
msgid "inherited"
msgstr "ärvd"
-#: ../../mod/connedit.php:553
+#: ../../mod/connedit.php:554
msgid "Connection has no individual permissions!"
msgstr "Kontakten har inga individuella behörigheter!"
-#: ../../mod/connedit.php:554
+#: ../../mod/connedit.php:555
msgid ""
"This may be appropriate based on your <a href=\"settings\">privacy "
"settings</a>, though you may wish to review the \"Advanced Permissions\"."
msgstr "Det här kan vara lämpligt beroende på dina <a href=\"settings\">integritetsinställningar</a>, men du vill kanske se över de \"Avancerade inställningarna\"."
-#: ../../mod/connedit.php:556
+#: ../../mod/connedit.php:557
msgid "Profile Visibility"
msgstr "Profilsynlighet"
-#: ../../mod/connedit.php:557
+#: ../../mod/connedit.php:558
#, php-format
msgid ""
"Please choose the profile you would like to display to %s when viewing your "
"profile securely."
msgstr "Välj profilen som du vill ska synas när %s ser din profil på ett säkert sätt."
-#: ../../mod/connedit.php:558
+#: ../../mod/connedit.php:559
msgid "Contact Information / Notes"
msgstr "Kontaktinformation / anteckningar"
-#: ../../mod/connedit.php:559
+#: ../../mod/connedit.php:560
msgid "Edit contact notes"
msgstr "Redigera anteckningar för kontakten"
-#: ../../mod/connedit.php:561
+#: ../../mod/connedit.php:562
msgid "Their Settings"
msgstr "Deras inställningar"
-#: ../../mod/connedit.php:562
+#: ../../mod/connedit.php:563
msgid "My Settings"
msgstr "Mina inställningar"
-#: ../../mod/connedit.php:564
+#: ../../mod/connedit.php:565
msgid "Clear/Disable Automatic Permissions"
msgstr "Rensa/inaktivera automatiska behörigheter"
-#: ../../mod/connedit.php:565
+#: ../../mod/connedit.php:566
msgid "Forum Members"
msgstr "Forummedlemmar"
-#: ../../mod/connedit.php:566
+#: ../../mod/connedit.php:567
msgid "Soapbox"
msgstr "Talarstol"
-#: ../../mod/connedit.php:567
+#: ../../mod/connedit.php:568
msgid "Full Sharing (typical social network permissions)"
msgstr "Full delning (typiska behörigheter för sociala nätverk)"
-#: ../../mod/connedit.php:568
+#: ../../mod/connedit.php:569
msgid "Cautious Sharing "
msgstr "Försiktig delning"
-#: ../../mod/connedit.php:569
+#: ../../mod/connedit.php:570
msgid "Follow Only"
msgstr "Följ endast"
-#: ../../mod/connedit.php:570
+#: ../../mod/connedit.php:571
msgid "Individual Permissions"
msgstr "Individuella behörigheter"
-#: ../../mod/connedit.php:571
+#: ../../mod/connedit.php:572
msgid ""
"Some permissions may be inherited from your channel <a "
"href=\"settings\">privacy settings</a>, which have higher priority than "
@@ -5719,488 +5844,316 @@ msgid ""
"have no effect."
msgstr "Vissa behörigheter kan ärvas från din kanals <a href=\"settings\">integritetsinställningar</a>, vilka har högre prioritet än individuella inställningar. Ändring av de ärvda inställningarna på den här sidan har ingen effekt."
-#: ../../mod/connedit.php:572
+#: ../../mod/connedit.php:573
msgid "Advanced Permissions"
msgstr "Avancerade behörighetsinställningar"
-#: ../../mod/connedit.php:573
+#: ../../mod/connedit.php:574
msgid "Simple Permissions (select one and submit)"
msgstr "Enkla behörighetsinställningar (välj en och spara)"
-#: ../../mod/connedit.php:577
+#: ../../mod/connedit.php:578
#, php-format
msgid "Visit %s's profile - %s"
msgstr "Besök %ss profil - %s"
-#: ../../mod/connedit.php:578
+#: ../../mod/connedit.php:579
msgid "Block/Unblock contact"
msgstr "Blockera/häv blockering av kontakt"
-#: ../../mod/connedit.php:579
+#: ../../mod/connedit.php:580
msgid "Ignore contact"
msgstr "Ignorera kontakt"
-#: ../../mod/connedit.php:580
+#: ../../mod/connedit.php:581
msgid "Repair URL settings"
msgstr "Reparera URL-inställningar"
-#: ../../mod/connedit.php:581
+#: ../../mod/connedit.php:582
msgid "View conversations"
msgstr "Visa konversationer"
-#: ../../mod/connedit.php:583
+#: ../../mod/connedit.php:584
msgid "Delete contact"
msgstr "Ta bort kontakt"
-#: ../../mod/connedit.php:586
+#: ../../mod/connedit.php:587
msgid "Last update:"
msgstr "Senaste uppdatering:"
-#: ../../mod/connedit.php:588
+#: ../../mod/connedit.php:589
msgid "Update public posts"
msgstr "Uppdatera offentliga inlägg"
-#: ../../mod/connedit.php:590
+#: ../../mod/connedit.php:591
msgid "Update now"
msgstr "Uppdatera nu"
-#: ../../mod/connedit.php:596
+#: ../../mod/connedit.php:597
msgid "Currently blocked"
msgstr "Blockerad"
-#: ../../mod/connedit.php:597
+#: ../../mod/connedit.php:598
msgid "Currently ignored"
msgstr "Ignorerad"
-#: ../../mod/connedit.php:598
+#: ../../mod/connedit.php:599
msgid "Currently archived"
msgstr "Arkiverad"
-#: ../../mod/connedit.php:599
+#: ../../mod/connedit.php:600
msgid "Currently pending"
msgstr "Inväntar svar"
-#: ../../mod/connedit.php:600
+#: ../../mod/connedit.php:601
msgid "Hide this contact from others"
msgstr "Dölj den här kontakten för andra"
-#: ../../mod/connedit.php:600
+#: ../../mod/connedit.php:601
msgid ""
"Replies/likes to your public posts <strong>may</strong> still be visible"
msgstr "Svar/gilla-reaktioner på dina offentliga inlägg <strong>kan</strong> fortfarande synas"
-#: ../../mod/thing.php:96
-msgid "Thing updated"
-msgstr "Föremål uppdaterat"
-
-#: ../../mod/thing.php:156
-msgid "Object store: failed"
-msgstr "Objektlagring: misslyckades"
-
-#: ../../mod/thing.php:160
-msgid "Thing added"
-msgstr "Föremål tillagt"
-
-#: ../../mod/thing.php:180
-#, php-format
-msgid "OBJ: %1$s %2$s %3$s"
-msgstr "OBJ: %1$s %2$s %3$s"
-
-#: ../../mod/thing.php:232
-msgid "Show Thing"
-msgstr "Visa föremål"
-
-#: ../../mod/thing.php:239
-msgid "item not found."
-msgstr "föremål hittades inte."
-
-#: ../../mod/thing.php:270
-msgid "Edit Thing"
-msgstr "Redigera föremål"
-
-#: ../../mod/thing.php:272 ../../mod/thing.php:319
-msgid "Select a profile"
-msgstr "Välj en profil"
-
-#: ../../mod/thing.php:276 ../../mod/thing.php:322
-msgid "Post an activity"
-msgstr "Posta en aktivitet"
-
-#: ../../mod/thing.php:276 ../../mod/thing.php:322
-msgid "Only sends to viewers of the applicable profile"
-msgstr "Skickar bara till de som tittar på den aktuella profilen"
-
-#: ../../mod/thing.php:278 ../../mod/thing.php:324
-msgid "Name of thing e.g. something"
-msgstr "Namn på föremål, t.ex. någonting"
+#: ../../mod/mail.php:33
+msgid "Unable to lookup recipient."
+msgstr "Kunde inte hitta mottagare."
-#: ../../mod/thing.php:280 ../../mod/thing.php:325
-msgid "URL of thing (optional)"
-msgstr "URL för föremål (frivilligt)"
+#: ../../mod/mail.php:41
+msgid "Unable to communicate with requested channel."
+msgstr "Kunde inte kommunicera med den begärda kanalen."
-#: ../../mod/thing.php:282 ../../mod/thing.php:326
-msgid "URL for photo of thing (optional)"
-msgstr "URL för foto på föremål (frivilligt)"
+#: ../../mod/mail.php:48
+msgid "Cannot verify requested channel."
+msgstr "Kan inte bekräfta den begärda kanalen."
-#: ../../mod/thing.php:317
-msgid "Add Thing to your Profile"
-msgstr "Lägg till föremål till din profil"
+#: ../../mod/mail.php:74
+msgid "Selected channel has private message restrictions. Send failed."
+msgstr "Den valda kanalen har restriktioner för privata meddelanden. Misslyckades att skicka."
-#: ../../mod/lostpass.php:15
-msgid "No valid account found."
-msgstr "Inget giltigt konto hittades."
+#: ../../mod/mail.php:136
+msgid "Message deleted."
+msgstr "Meddelande borttaget."
-#: ../../mod/lostpass.php:29
-msgid "Password reset request issued. Check your email."
-msgstr "Lösenordsåterställning har skickats. Kontrollera din e-post."
+#: ../../mod/mail.php:153
+msgid "Message recalled."
+msgstr "Meddelande återkallat."
-#: ../../mod/lostpass.php:35 ../../mod/lostpass.php:102
-#, php-format
-msgid "Site Member (%s)"
-msgstr "Servermedlem (%s)"
+#: ../../mod/mail.php:222
+msgid "Send Private Message"
+msgstr "Skicka privat meddelande."
-#: ../../mod/lostpass.php:40
-#, php-format
-msgid "Password reset requested at %s"
-msgstr "Lösenordsåterställning begärd på %s"
+#: ../../mod/mail.php:223 ../../mod/mail.php:340
+msgid "To:"
+msgstr "Till:"
-#: ../../mod/lostpass.php:63
-msgid ""
-"Request could not be verified. (You may have previously submitted it.) "
-"Password reset failed."
-msgstr "Begäran kunde inte bekräftas. (Du kan ha skickat den tidigare.) Lösenordsåterställningen misslyckades."
+#: ../../mod/mail.php:228 ../../mod/mail.php:342
+msgid "Subject:"
+msgstr "Ämne:"
-#: ../../mod/lostpass.php:85 ../../boot.php:1494
-msgid "Password Reset"
-msgstr "Lösenordsåterställning"
+#: ../../mod/mail.php:232 ../../mod/mail.php:345 ../../mod/invite.php:131
+msgid "Your message:"
+msgstr "Ditt meddelande:"
-#: ../../mod/lostpass.php:86
-msgid "Your password has been reset as requested."
-msgstr "Ditt lösenord har återställts som begärt."
+#: ../../mod/mail.php:239
+msgid "Send"
+msgstr "Skicka"
-#: ../../mod/lostpass.php:87
-msgid "Your new password is"
-msgstr "Ditt nya lösenord är"
+#: ../../mod/mail.php:266
+msgid "Message not found."
+msgstr "Meddelandet hittades inte."
-#: ../../mod/lostpass.php:88
-msgid "Save or copy your new password - and then"
-msgstr "Spara eller kopiera ditt nya lösenord - "
+#: ../../mod/mail.php:309
+msgid "Delete message"
+msgstr "Ta bort meddelande"
-#: ../../mod/lostpass.php:89
-msgid "click here to login"
-msgstr "klicka sedan här för att logga in"
+#: ../../mod/mail.php:310
+msgid "Recall message"
+msgstr "Återkalla meddelande"
-#: ../../mod/lostpass.php:90
-msgid ""
-"Your password may be changed from the <em>Settings</em> page after "
-"successful login."
-msgstr "Ditt lösenord kan bytas från sidan <em>Inställningar</em> när du är inloggad."
+#: ../../mod/mail.php:312
+msgid "Message has been recalled."
+msgstr "Meddelandet har återkallats."
-#: ../../mod/lostpass.php:107
-#, php-format
-msgid "Your password has changed at %s"
-msgstr "Ditt lösenord byttes på %s"
+#: ../../mod/mail.php:329
+msgid "Private Conversation"
+msgstr "Privat konversation"
-#: ../../mod/lostpass.php:122
-msgid "Forgot your Password?"
-msgstr "Glömt lösenordet?"
+#: ../../mod/mail.php:333 ../../mod/message.php:72
+msgid "Delete conversation"
+msgstr "Ta bort konversation"
-#: ../../mod/lostpass.php:123
+#: ../../mod/mail.php:335
msgid ""
-"Enter your email address and submit to have your password reset. Then check "
-"your email for further instructions."
-msgstr "Ange din e-postadress och skicka för att återställa ditt lösenord. Kontrollera sedan din e-post för vidare instruktioner."
-
-#: ../../mod/lostpass.php:124
-msgid "Email Address"
-msgstr "E-postadress"
-
-#: ../../mod/lostpass.php:125
-msgid "Reset"
-msgstr "Återställ"
-
-#: ../../mod/bookmarks.php:38
-msgid "Bookmark added"
-msgstr "Bokmärke tillagt"
-
-#: ../../mod/bookmarks.php:60
-msgid "My Bookmarks"
-msgstr "Mina bokmärken"
-
-#: ../../mod/bookmarks.php:71
-msgid "My Connections Bookmarks"
-msgstr "Mina kontakters bokmärken"
-
-#: ../../mod/dirsearch.php:21
-msgid "This site is not a directory server"
-msgstr "Den här servern är inte en katalogserver"
-
-#: ../../mod/cloud.php:130
-msgid "RedMatrix - Guests: Username: {your email address}, Password: +++"
-msgstr "RedMatrix - Gäster: Användarnamn {din e-postadress}, Lösenord: +++"
-
-#: ../../mod/profiles.php:18 ../../mod/profiles.php:165
-#: ../../mod/profiles.php:222 ../../mod/profiles.php:565
-msgid "Profile not found."
-msgstr "Profil hittades inte."
-
-#: ../../mod/profiles.php:38
-msgid "Profile deleted."
-msgstr "Profil borttagen."
-
-#: ../../mod/profiles.php:56 ../../mod/profiles.php:92
-msgid "Profile-"
-msgstr "Profil-"
-
-#: ../../mod/profiles.php:77 ../../mod/profiles.php:120
-msgid "New profile created."
-msgstr "Ny profil skapad."
-
-#: ../../mod/profiles.php:98
-msgid "Profile unavailable to clone."
-msgstr "Profil inte tillgänglig för kloning."
-
-#: ../../mod/profiles.php:136
-msgid "Profile unavailable to export."
-msgstr "Profil inte tillgänglig för export."
-
-#: ../../mod/profiles.php:232
-msgid "Profile Name is required."
-msgstr "Profilnamn krävs."
-
-#: ../../mod/profiles.php:378
-msgid "Marital Status"
-msgstr "Civilstånd"
-
-#: ../../mod/profiles.php:382
-msgid "Romantic Partner"
-msgstr "Romantisk partner"
-
-#: ../../mod/profiles.php:386
-msgid "Likes"
-msgstr "Gillar"
-
-#: ../../mod/profiles.php:390
-msgid "Dislikes"
-msgstr "Ogillar"
-
-#: ../../mod/profiles.php:394
-msgid "Work/Employment"
-msgstr "Arbete/sysselsättning"
-
-#: ../../mod/profiles.php:397
-msgid "Religion"
-msgstr "Religion"
-
-#: ../../mod/profiles.php:401
-msgid "Political Views"
-msgstr "Politisk åskådning"
-
-#: ../../mod/profiles.php:405
-msgid "Gender"
-msgstr "Kön"
-
-#: ../../mod/profiles.php:409
-msgid "Sexual Preference"
-msgstr "Sexuell preferens"
-
-#: ../../mod/profiles.php:413
-msgid "Homepage"
-msgstr "Hemsida"
-
-#: ../../mod/profiles.php:417
-msgid "Interests"
-msgstr "Intressen"
-
-#: ../../mod/profiles.php:421 ../../mod/admin.php:866
-msgid "Address"
-msgstr "Adress"
-
-#: ../../mod/profiles.php:511
-msgid "Profile updated."
-msgstr "Profil uppdaterad."
-
-#: ../../mod/profiles.php:590
-msgid "Hide your contact/friend list from viewers of this profile?"
-msgstr "Dölj din kontakt-/vänlista för de som ser den här profilen"
-
-#: ../../mod/profiles.php:632
-msgid "Edit Profile Details"
-msgstr "Redigera profildetaljer"
-
-#: ../../mod/profiles.php:634
-msgid "View this profile"
-msgstr "Visa den här profilen"
-
-#: ../../mod/profiles.php:636
-msgid "Change Profile Photo"
-msgstr "Byt profilfoto"
+"No secure communications available. You <strong>may</strong> be able to "
+"respond from the sender's profile page."
+msgstr "Ingen säker kommunikationskanal tillgänglig. Du kan <strong>möjligtvis</strong> svara från avsändarens profilsida."
-#: ../../mod/profiles.php:637
-msgid "Create a new profile using these settings"
-msgstr "Skapa en ny profil utifrån de här inställningarna"
+#: ../../mod/mail.php:339
+msgid "Send Reply"
+msgstr "Skicka svar"
-#: ../../mod/profiles.php:638
-msgid "Clone this profile"
-msgstr "Klona den här profilen"
+#: ../../mod/photos.php:77
+msgid "Page owner information could not be retrieved."
+msgstr "Information om sidans ägare kunde inte hittas."
-#: ../../mod/profiles.php:639
-msgid "Delete this profile"
-msgstr "Ta bort den här profilen"
+#: ../../mod/photos.php:97
+msgid "Album not found."
+msgstr "Albumet hittades inte."
-#: ../../mod/profiles.php:641
-msgid "Import profile from file"
-msgstr "Importera profil från fil"
+#: ../../mod/photos.php:119 ../../mod/photos.php:672
+msgid "Delete Album"
+msgstr "Ta bort album"
-#: ../../mod/profiles.php:642
-msgid "Export profile to file"
-msgstr "Exportera profil som fil"
+#: ../../mod/photos.php:159 ../../mod/photos.php:958
+msgid "Delete Photo"
+msgstr "Ta bort foto"
-#: ../../mod/profiles.php:643
-msgid "Profile Name:"
-msgstr "Profilnamn:"
+#: ../../mod/photos.php:469
+msgid "No photos selected"
+msgstr "Inga foton valda"
-#: ../../mod/profiles.php:644
-msgid "Your Full Name:"
-msgstr "Ditt fulllständiga namn:"
+#: ../../mod/photos.php:513
+msgid "Access to this item is restricted."
+msgstr "Åtkomst till den här posten är begränsat."
-#: ../../mod/profiles.php:645
-msgid "Title/Description:"
-msgstr "Titel/beskrivning:"
+#: ../../mod/photos.php:552
+#, php-format
+msgid "%1$.2f MB of %2$.2f MB photo storage used."
+msgstr "%1$.2f MB av %2$.2f MB fotolagring använt."
-#: ../../mod/profiles.php:646
-msgid "Your Gender:"
-msgstr "Ditt kön:"
+#: ../../mod/photos.php:555
+#, php-format
+msgid "%1$.2f MB photo storage used."
+msgstr "%1$.2f MB fotolagring använt."
-#: ../../mod/profiles.php:647
-msgid "Birthday :"
-msgstr "Födelsedag:"
+#: ../../mod/photos.php:579
+msgid "Upload Photos"
+msgstr "Ladda upp foton"
-#: ../../mod/profiles.php:648
-msgid "Street Address:"
-msgstr "Gatuadress:"
+#: ../../mod/photos.php:583 ../../mod/photos.php:665 ../../mod/photos.php:943
+msgid "Enter a new album name"
+msgstr "Ange ett nytt albumnamn"
-#: ../../mod/profiles.php:649
-msgid "Locality/City:"
-msgstr "Ort:"
+#: ../../mod/photos.php:584 ../../mod/photos.php:666 ../../mod/photos.php:944
+msgid "or select an existing one (doubleclick)"
+msgstr "eller välj ett befintligt (dubbelklicka)"
-#: ../../mod/profiles.php:650
-msgid "Postal/Zip Code:"
-msgstr "Postnummer:"
+#: ../../mod/photos.php:585
+msgid "Do not show a status post for this upload"
+msgstr "Visa inte en statusuppdatering för den här uppladdningen"
-#: ../../mod/profiles.php:651
-msgid "Country:"
-msgstr "Land:"
+#: ../../mod/photos.php:613
+msgid "Album name could not be decoded"
+msgstr "Albumnamn kunde inte tolkas"
-#: ../../mod/profiles.php:652
-msgid "Region/State:"
-msgstr "Region:"
+#: ../../mod/photos.php:654 ../../mod/photos.php:1167
+#: ../../mod/photos.php:1183
+msgid "Contact Photos"
+msgstr "Kontaktfoton"
-#: ../../mod/profiles.php:653
-msgid "<span class=\"heart\">&hearts;</span> Marital Status:"
-msgstr "<span class=\"heart\">&hearts;</span> Civilstånd:"
+#: ../../mod/photos.php:678
+msgid "Show Newest First"
+msgstr "Visa nyast först"
-#: ../../mod/profiles.php:654
-msgid "Who: (if applicable)"
-msgstr "Vem: (om tillämpligt)"
+#: ../../mod/photos.php:680
+msgid "Show Oldest First"
+msgstr "Visa äldst först"
-#: ../../mod/profiles.php:655
-msgid "Examples: cathy123, Cathy Williams, cathy@example.com"
-msgstr "Exempel: cathy123, Cathy Williams, cathy@example.com"
+#: ../../mod/photos.php:707 ../../mod/photos.php:1215
+msgid "View Photo"
+msgstr "Visa foto"
-#: ../../mod/profiles.php:656
-msgid "Since [date]:"
-msgstr "Sedan [datum]"
+#: ../../mod/photos.php:736
+msgid "Edit Album"
+msgstr "Redigera album"
-#: ../../mod/profiles.php:658
-msgid "Homepage URL:"
-msgstr "Hemsideadress:"
+#: ../../mod/photos.php:781
+msgid "Permission denied. Access to this item may be restricted."
+msgstr "Behörighet saknas. Åtkomst till den här posten kan vara begränsat."
-#: ../../mod/profiles.php:661
-msgid "Religious Views:"
-msgstr "Religion/livsåskådning:"
+#: ../../mod/photos.php:783
+msgid "Photo not available"
+msgstr "Foto inte tillgängligt"
-#: ../../mod/profiles.php:662
-msgid "Keywords:"
-msgstr "Nyckelord:"
+#: ../../mod/photos.php:841
+msgid "Use as profile photo"
+msgstr "Använd som profilfoto"
-#: ../../mod/profiles.php:665
-msgid "Example: fishing photography software"
-msgstr "Exempel: fiske fotografering mjukvara"
+#: ../../mod/photos.php:848
+msgid "Private Photo"
+msgstr "Privat foto"
-#: ../../mod/profiles.php:666
-msgid "Used in directory listings"
-msgstr "Används i kataloglistningar"
+#: ../../mod/photos.php:863
+msgid "View Full Size"
+msgstr "Visa fullstorlek"
-#: ../../mod/profiles.php:667
-msgid "Tell us about yourself..."
-msgstr "Beskriv dig själv..."
+#: ../../mod/photos.php:937
+msgid "Edit photo"
+msgstr "Redigera foto"
-#: ../../mod/profiles.php:668
-msgid "Hobbies/Interests"
-msgstr "Fritidssysselsättning/intressen"
+#: ../../mod/photos.php:939
+msgid "Rotate CW (right)"
+msgstr "Rotera medurs (höger)"
-#: ../../mod/profiles.php:669
-msgid "Contact information and Social Networks"
-msgstr "Kontaktinformation och sociala nätverk"
+#: ../../mod/photos.php:940
+msgid "Rotate CCW (left)"
+msgstr "Rotera moturs (vänster)"
-#: ../../mod/profiles.php:670
-msgid "My other channels"
-msgstr "Mina andra kanaler"
+#: ../../mod/photos.php:947
+msgid "Caption"
+msgstr "Bildtext"
-#: ../../mod/profiles.php:671
-msgid "Musical interests"
-msgstr "Musikintressen"
+#: ../../mod/photos.php:949
+msgid "Add a Tag"
+msgstr "Lägg till en tagg"
-#: ../../mod/profiles.php:672
-msgid "Books, literature"
-msgstr "Böcker, litteratur"
+#: ../../mod/photos.php:953
+msgid "Example: @bob, @Barbara_Jensen, @jim@example.com"
+msgstr "Exempel: @bob, @Barbara_Jensen, @jim@example.com"
-#: ../../mod/profiles.php:673
-msgid "Television"
-msgstr "Tv"
+#: ../../mod/photos.php:956
+msgid "Flag as adult in album view"
+msgstr "Flagga som olämpligt för barn i albumvyn"
-#: ../../mod/profiles.php:674
-msgid "Film/dance/culture/entertainment"
-msgstr "Film/dans/kultur/underhållning"
+#: ../../mod/photos.php:1133
+msgid "In This Photo:"
+msgstr "På fotot:"
-#: ../../mod/profiles.php:675
-msgid "Love/romance"
-msgstr "Kärlek/romantik"
+#: ../../mod/photos.php:1221
+msgid "View Album"
+msgstr "Visa album"
-#: ../../mod/profiles.php:676
-msgid "Work/employment"
-msgstr "Arbete/sysselsättning"
+#: ../../mod/photos.php:1244
+msgid "Recent Photos"
+msgstr "Nya foton"
-#: ../../mod/profiles.php:677
-msgid "School/education"
-msgstr "Skola/utbildning"
+#: ../../mod/bookmarks.php:38
+msgid "Bookmark added"
+msgstr "Bokmärke tillagt"
-#: ../../mod/profiles.php:683
-msgid "This is your default profile."
-msgstr "Det här är din standardprofil."
+#: ../../mod/bookmarks.php:60
+msgid "My Bookmarks"
+msgstr "Mina bokmärken"
-#: ../../mod/profiles.php:694 ../../mod/directory.php:159
-msgid "Age: "
-msgstr "Ålder:"
+#: ../../mod/bookmarks.php:71
+msgid "My Connections Bookmarks"
+msgstr "Mina kontakters bokmärken"
-#: ../../mod/profiles.php:737
-msgid "Edit/Manage Profiles"
-msgstr "Redigera/hantera profiler"
+#: ../../mod/dirsearch.php:21
+msgid "This site is not a directory server"
+msgstr "Den här servern är inte en katalogserver"
-#: ../../mod/profiles.php:738
-msgid "Add profile things"
-msgstr "Lägg till profilsaker"
+#: ../../mod/cloud.php:130
+msgid "RedMatrix - Guests: Username: {your email address}, Password: +++"
+msgstr "RedMatrix - Gäster: Användarnamn {din e-postadress}, Lösenord: +++"
-#: ../../mod/profiles.php:739
-msgid "Include desirable objects in your profile"
-msgstr "Inkludera fina prylar i din profil"
+#: ../../mod/acl.php:245
+msgid "network"
+msgstr "nätverk"
-#: ../../mod/editblock.php:79 ../../mod/editblock.php:95
-#: ../../mod/editlayout.php:78 ../../mod/editpost.php:20
-#: ../../mod/editwebpage.php:77
-msgid "Item not found"
-msgstr "Posten hittas inte"
+#: ../../mod/blocks.php:99
+msgid "Block Name"
+msgstr "Blocknamn"
#: ../../mod/editblock.php:115
msgid "Edit Block"
@@ -6210,21 +6163,6 @@ msgstr "Redigera block"
msgid "Delete block?"
msgstr "Ta bort block?"
-#: ../../mod/editblock.php:147 ../../mod/editlayout.php:143
-#: ../../mod/editpost.php:116 ../../mod/editwebpage.php:178
-msgid "Insert YouTube video"
-msgstr "Infoga Youtube-video"
-
-#: ../../mod/editblock.php:148 ../../mod/editlayout.php:144
-#: ../../mod/editpost.php:117 ../../mod/editwebpage.php:179
-msgid "Insert Vorbis [.ogg] video"
-msgstr "Infoga Vorbis [.ogg]-video"
-
-#: ../../mod/editblock.php:149 ../../mod/editlayout.php:145
-#: ../../mod/editpost.php:118 ../../mod/editwebpage.php:180
-msgid "Insert Vorbis [.ogg] audio"
-msgstr "Infoga Vorbis [.ogg]-ljud"
-
#: ../../mod/editblock.php:183
msgid "Delete Block"
msgstr "Ta bort block"
@@ -6261,13 +6199,14 @@ msgstr "Ta bort layout?"
msgid "Delete Layout"
msgstr "Ta bort layout"
-#: ../../mod/editpost.php:31
-msgid "Item is not editable"
-msgstr "Posten går ej att redigera"
+#: ../../mod/home.php:48
+msgid "Red Matrix - &quot;The Network&quot;"
+msgstr "Red Matrix - &quot;Nätverket&quot;"
-#: ../../mod/editpost.php:53
-msgid "Delete item?"
-msgstr "Ta bort posten?"
+#: ../../mod/home.php:101
+#, php-format
+msgid "Welcome to %s"
+msgstr "Välkommen till %s"
#: ../../mod/editwebpage.php:140
msgid "Edit Webpage"
@@ -6370,31 +6309,108 @@ msgstr "Bilduppladdning misslyckades."
msgid "Image size reduction [%s] failed."
msgstr "Krympning av bilden [%s] misslyckades."
-#: ../../mod/item.php:159
-msgid "Unable to locate original post."
-msgstr "Kunde inte hitta originalinlägget."
+#: ../../mod/like.php:15
+msgid "Like/Dislike"
+msgstr "Gilla/ogilla"
-#: ../../mod/item.php:418
-msgid "Empty post discarded."
-msgstr "Tomt inlägg förkastat."
+#: ../../mod/like.php:20
+msgid "This action is restricted to members."
+msgstr "Den här åtgärden fungerar bara för medlemmar."
-#: ../../mod/item.php:460
-msgid "Executable content type not permitted to this channel."
-msgstr "Körbart innehåll tillåts inte i den här kanalen."
+#: ../../mod/like.php:21
+msgid ""
+"Please <a href=\"rmagic\">login with your RedMatrix ID</a> or <a "
+"href=\"register\">register as a new RedMatrix member</a> to continue."
+msgstr "<a href=\"rmagic\">Logga in med ditt RedMatrix-ID</a> eller <a href=\"register\">registrera dig som ny RedMatrix medlem</a> för att fortsätta."
-#: ../../mod/item.php:898
-msgid "System error. Post not saved."
-msgstr "Systemfel. Inlägget inte sparat."
+#: ../../mod/like.php:77 ../../mod/like.php:104 ../../mod/like.php:142
+msgid "Invalid request."
+msgstr "Ogiltig begäran."
-#: ../../mod/item.php:1373
-#, php-format
-msgid "You have reached your limit of %1$.0f top level posts."
-msgstr "Du har nått din gräns på %1$.0f toppnivåinlägg."
+#: ../../mod/like.php:119
+msgid "thing"
+msgstr "sak"
+
+#: ../../mod/like.php:165
+msgid "Channel unavailable."
+msgstr "Kanalen kan ej nås."
+
+#: ../../mod/like.php:204
+msgid "Previous action reversed."
+msgstr "Föregående åtgärd återställdes."
+
+#: ../../mod/like.php:422
+msgid "Action completed."
+msgstr "Åtgärden slutfördes."
+
+#: ../../mod/like.php:423
+msgid "Thank you."
+msgstr "Tack."
+
+#: ../../mod/help.php:41 ../../mod/help.php:47 ../../mod/help.php:53
+msgid "Help:"
+msgstr "Hjälp:"
+
+#: ../../mod/help.php:67 ../../index.php:238
+msgid "Not Found"
+msgstr "Hittas inte"
-#: ../../mod/item.php:1379
+#: ../../mod/thing.php:96
+msgid "Thing updated"
+msgstr "Föremål uppdaterat"
+
+#: ../../mod/thing.php:156
+msgid "Object store: failed"
+msgstr "Objektlagring: misslyckades"
+
+#: ../../mod/thing.php:160
+msgid "Thing added"
+msgstr "Föremål tillagt"
+
+#: ../../mod/thing.php:180
#, php-format
-msgid "You have reached your limit of %1$.0f webpages."
-msgstr "Du har nått din gräns på %1$.0f webbsidor."
+msgid "OBJ: %1$s %2$s %3$s"
+msgstr "OBJ: %1$s %2$s %3$s"
+
+#: ../../mod/thing.php:232
+msgid "Show Thing"
+msgstr "Visa föremål"
+
+#: ../../mod/thing.php:239
+msgid "item not found."
+msgstr "föremål hittades inte."
+
+#: ../../mod/thing.php:270
+msgid "Edit Thing"
+msgstr "Redigera föremål"
+
+#: ../../mod/thing.php:272 ../../mod/thing.php:319
+msgid "Select a profile"
+msgstr "Välj en profil"
+
+#: ../../mod/thing.php:276 ../../mod/thing.php:322
+msgid "Post an activity"
+msgstr "Posta en aktivitet"
+
+#: ../../mod/thing.php:276 ../../mod/thing.php:322
+msgid "Only sends to viewers of the applicable profile"
+msgstr "Skickar bara till de som tittar på den aktuella profilen"
+
+#: ../../mod/thing.php:278 ../../mod/thing.php:324
+msgid "Name of thing e.g. something"
+msgstr "Namn på föremål, t.ex. någonting"
+
+#: ../../mod/thing.php:280 ../../mod/thing.php:325
+msgid "URL of thing (optional)"
+msgstr "URL för föremål (frivilligt)"
+
+#: ../../mod/thing.php:282 ../../mod/thing.php:326
+msgid "URL for photo of thing (optional)"
+msgstr "URL för foto på föremål (frivilligt)"
+
+#: ../../mod/thing.php:317
+msgid "Add Thing to your Profile"
+msgstr "Lägg till föremål till din profil"
#: ../../mod/fsuggest.php:20 ../../mod/fsuggest.php:92
msgid "Contact not found."
@@ -6445,123 +6461,84 @@ msgstr "Kopiera/klistra in den här koden för att bifoga filen i ett inlägg"
msgid "Copy/paste this URL to link file from a web page"
msgstr "Kopiera/klistra in den här URL:en för att länka till filen från en webbsida"
-#: ../../mod/help.php:41 ../../mod/help.php:47 ../../mod/help.php:53
-msgid "Help:"
-msgstr "Hjälp:"
-
-#: ../../mod/help.php:67 ../../index.php:238
-msgid "Not Found"
-msgstr "Hittas inte"
-
-#: ../../mod/acl.php:245
-msgid "network"
-msgstr "nätverk"
+#: ../../mod/connect.php:56 ../../mod/connect.php:104
+msgid "Continue"
+msgstr "Fortsätt"
-#: ../../mod/delegate.php:95
-msgid "No potential page delegates located."
-msgstr "Inga potentiella sid-ombud funna."
+#: ../../mod/connect.php:85
+msgid "Premium Channel Setup"
+msgstr "Inställning av premiumkanal"
-#: ../../mod/delegate.php:121
-msgid "Delegate Page Management"
-msgstr "Delegera sidhantering"
+#: ../../mod/connect.php:87
+msgid "Enable premium channel connection restrictions"
+msgstr "Aktivera kontaktrestriktioner för premiumkanal"
-#: ../../mod/delegate.php:123
+#: ../../mod/connect.php:88
msgid ""
-"Delegates are able to manage all aspects of this account/page except for "
-"basic account settings. Please do not delegate your personal account to "
-"anybody that you do not trust completely."
-msgstr "Ombud kan hantera alla aspekter av det här kontot/den här sidan förutom grundläggande kontoinställningar. Delegera inte ditt personliga konto till någon som du inte litar fullständigt på."
-
-#: ../../mod/delegate.php:124
-msgid "Existing Page Managers"
-msgstr "Befintliga sid-ansvariga"
-
-#: ../../mod/delegate.php:126
-msgid "Existing Page Delegates"
-msgstr "Befintliga sid-ombud"
-
-#: ../../mod/delegate.php:128
-msgid "Potential Delegates"
-msgstr "Potentiella ombud"
-
-#: ../../mod/delegate.php:130 ../../mod/tagrm.php:133 ../../mod/photos.php:905
-msgid "Remove"
-msgstr "Ta bort"
-
-#: ../../mod/delegate.php:131
-msgid "Add"
-msgstr "Lägg till"
-
-#: ../../mod/delegate.php:132
-msgid "No entries."
-msgstr "Inga poster."
-
-#: ../../mod/follow.php:25
-msgid "Channel added."
-msgstr "Kanal tillagd."
-
-#: ../../mod/group.php:20
-msgid "Collection created."
-msgstr "Krets skapad."
+"Please enter your restrictions or conditions, such as paypal receipt, usage "
+"guidelines, etc."
+msgstr "Ange dina restriktioner och villkor, som Paypal-kvitto, användarriktlinjer, etc."
-#: ../../mod/group.php:26
-msgid "Could not create collection."
-msgstr "Kunde inte skapa krets."
+#: ../../mod/connect.php:90 ../../mod/connect.php:110
+msgid ""
+"This channel may require additional steps or acknowledgement of the "
+"following conditions prior to connecting:"
+msgstr "Den här kanalen kan kräva ytterligare steg eller godkännande av följande villkor innan anslutning:"
-#: ../../mod/group.php:54
-msgid "Collection updated."
-msgstr "Kretsen uppdaterad."
+#: ../../mod/connect.php:91
+msgid ""
+"Potential connections will then see the following text before proceeding:"
+msgstr "Potentiella kontakter kommer sedan att se följande text innan de går vidare:"
-#: ../../mod/group.php:86
-msgid "Create a collection of channels."
-msgstr "Skapa en krets av kanaler."
+#: ../../mod/connect.php:92 ../../mod/connect.php:113
+msgid ""
+"By continuing, I certify that I have complied with any instructions provided"
+" on this page."
+msgstr "Genom att fortsätta intygar jag att jag har följt alla instruktioner som ges på den här sidan."
-#: ../../mod/group.php:87 ../../mod/group.php:183
-msgid "Collection Name: "
-msgstr "Namn på krets: "
+#: ../../mod/connect.php:101
+msgid "(No specific instructions have been provided by the channel owner.)"
+msgstr "(Inga specifika instruktioner har givits av kanalägaren.)"
-#: ../../mod/group.php:89 ../../mod/group.php:186
-msgid "Members are visible to other channels"
-msgstr "Medlemmar kan ses av andra kanaler"
+#: ../../mod/connect.php:109
+msgid "Restricted or Premium Channel"
+msgstr "Begränsad kanal eller premiumkanal"
-#: ../../mod/group.php:107
-msgid "Collection removed."
-msgstr "Krets borttagen."
+#: ../../mod/filer.php:49
+msgid "- select -"
+msgstr "- välj -"
-#: ../../mod/group.php:109
-msgid "Unable to remove collection."
-msgstr "Kunde inte ta bort krets."
+#: ../../mod/locs.php:19 ../../mod/locs.php:46
+msgid "Location not found."
+msgstr "Platsen hittades inte."
-#: ../../mod/group.php:182
-msgid "Collection Editor"
-msgstr "Redigera krets"
+#: ../../mod/locs.php:50
+msgid "Primary location cannot be removed."
+msgstr "Huvudplatsen kan inte tas bort."
-#: ../../mod/group.php:196
-msgid "Members"
-msgstr "Medlemmar"
+#: ../../mod/locs.php:82
+msgid "No locations found."
+msgstr "Inga platser hittades."
-#: ../../mod/group.php:198
-msgid "All Connected Channels"
-msgstr "Alla anslutna kanaler"
+#: ../../mod/locs.php:95
+msgid "Manage Channel Locations"
+msgstr "Hantera kanalplatser"
-#: ../../mod/group.php:233
-msgid "Click on a channel to add or remove."
-msgstr "Klicka på en kanal för att lägga till eller ta bort."
+#: ../../mod/locs.php:96
+msgid "Location (address)"
+msgstr "Plats (adress)"
-#: ../../mod/home.php:48
-msgid "Red Matrix - &quot;The Network&quot;"
-msgstr "Red Matrix - &quot;Nätverket&quot;"
+#: ../../mod/locs.php:97
+msgid "Primary Location"
+msgstr "Huvudplats"
-#: ../../mod/home.php:101
-#, php-format
-msgid "Welcome to %s"
-msgstr "Välkommen till %s"
+#: ../../mod/locs.php:98
+msgid "Drop location"
+msgstr "Ta bort plats"
-#: ../../mod/suggest.php:35
-msgid ""
-"No suggestions available. If this is a new site, please try again in 24 "
-"hours."
-msgstr "Inga förslag tillgängliga. Om det här är en ny server, försök igen om 24 timmar."
+#: ../../mod/follow.php:25
+msgid "Channel added."
+msgstr "Kanal tillagd."
#: ../../mod/import.php:25
#, php-format
@@ -6580,32 +6557,36 @@ msgstr "Kunde inte ladda ner data från den gamla servern"
msgid "Imported file is empty."
msgstr "Den importerade filen är tom."
-#: ../../mod/import.php:105
+#: ../../mod/import.php:106
msgid ""
"Cannot create a duplicate channel identifier on this system. Import failed."
msgstr "Kan inte skapa ett dubblerat kanal-ID på det här systemet. Import misslyckades."
-#: ../../mod/import.php:123
+#: ../../mod/import.php:127
+msgid "Unable to create a unique channel address. Import failed."
+msgstr "Kan inte skapa en unik kanaladress. Import misslyckades."
+
+#: ../../mod/import.php:147
msgid "Channel clone failed. Import failed."
msgstr "Kloning av kanalen misslyckades. Import misslyckades."
-#: ../../mod/import.php:133
+#: ../../mod/import.php:157
msgid "Cloned channel not found. Import failed."
msgstr "Den klonade kanalen hittas inte. Import misslyckades."
-#: ../../mod/import.php:451
+#: ../../mod/import.php:475
msgid "Import completed."
msgstr "Import slutförd."
-#: ../../mod/import.php:463
+#: ../../mod/import.php:487
msgid "You must be logged in to use this feature."
msgstr "Du måste vara inloggad för att kunna använda den här funktionen."
-#: ../../mod/import.php:468
+#: ../../mod/import.php:492
msgid "Import Channel"
msgstr "Importera kanal"
-#: ../../mod/import.php:469
+#: ../../mod/import.php:493
msgid ""
"Use this form to import an existing channel from a different server/hub. You"
" may retrieve the channel identity from the old server/hub via the network "
@@ -6613,27 +6594,27 @@ msgid ""
"be imported. Importation of content is not yet available."
msgstr "Använd det här formuläret för att importera en befintlig kanal från en annan server/hubb. Du kan få kanal-ID:t från den gamla servern/hubben över nätverket eller tillhandahålla en exportfil. Endast identitet och kontakter/relationer kommer att importeras. Import av innehåll stöds ännu inte."
-#: ../../mod/import.php:470
+#: ../../mod/import.php:494
msgid "File to Upload"
msgstr "Fil att ladda upp"
-#: ../../mod/import.php:471
+#: ../../mod/import.php:495
msgid "Or provide the old server/hub details"
msgstr "Eller ge uppgifter om den gamla servern/hubben"
-#: ../../mod/import.php:472
+#: ../../mod/import.php:496
msgid "Your old identity address (xyz@example.com)"
msgstr "Din gamla identitetsadress (xyz@example.com)"
-#: ../../mod/import.php:473
+#: ../../mod/import.php:497
msgid "Your old login email address"
msgstr "Din gamla e-postadress för inloggning"
-#: ../../mod/import.php:474
+#: ../../mod/import.php:498
msgid "Your old login password"
msgstr "Ditt gamla inloggningslösenord"
-#: ../../mod/import.php:475
+#: ../../mod/import.php:499
msgid ""
"For either option, please choose whether to make this hub your new primary "
"address, or whether your old location should continue this role. You will be"
@@ -6641,19 +6622,316 @@ msgid ""
"primary location for files, photos, and media."
msgstr "Ange i bägge fallen om den här hubben ska vara din nya primära adress eller om den gamla platsen ska fortsätta att ha den rollen. Du kommer att kunna posta från båda platser, men bara en kan vara primärt utrymme för filer, foton och media."
-#: ../../mod/import.php:476
+#: ../../mod/import.php:500
msgid "Make this hub my primary location"
msgstr "Gör den här hubben till min primära plats"
-#: ../../mod/import.php:477
+#: ../../mod/import.php:501
msgid "Import existing posts if possible"
msgstr "Importera befintliga inlägg om möjligt"
+#: ../../mod/item.php:159
+msgid "Unable to locate original post."
+msgstr "Kunde inte hitta originalinlägget."
+
+#: ../../mod/item.php:418
+msgid "Empty post discarded."
+msgstr "Tomt inlägg förkastat."
+
+#: ../../mod/item.php:460
+msgid "Executable content type not permitted to this channel."
+msgstr "Körbart innehåll tillåts inte i den här kanalen."
+
+#: ../../mod/item.php:899
+msgid "System error. Post not saved."
+msgstr "Systemfel. Inlägget inte sparat."
+
+#: ../../mod/item.php:1117
+#, php-format
+msgid "You have reached your limit of %1$.0f top level posts."
+msgstr "Du har nått din gräns på %1$.0f toppnivåinlägg."
+
+#: ../../mod/item.php:1123
+#, php-format
+msgid "You have reached your limit of %1$.0f webpages."
+msgstr "Du har nått din gräns på %1$.0f webbsidor."
+
+#: ../../mod/suggest.php:35
+msgid ""
+"No suggestions available. If this is a new site, please try again in 24 "
+"hours."
+msgstr "Inga förslag tillgängliga. Om det här är en ny server, försök igen om 24 timmar."
+
+#: ../../mod/layouts.php:110
+msgid "Help with this feature"
+msgstr "Hjälp för den här funktionen"
+
+#: ../../mod/layouts.php:130
+msgid "Layout Name"
+msgstr "Layoutnamn"
+
#: ../../mod/tagger.php:98
#, php-format
msgid "%1$s tagged %2$s's %3$s with %4$s"
msgstr "%1$s taggade%2$ss %3$s med %4$s"
+#: ../../mod/profiles.php:18 ../../mod/profiles.php:165
+#: ../../mod/profiles.php:222 ../../mod/profiles.php:565
+msgid "Profile not found."
+msgstr "Profil hittades inte."
+
+#: ../../mod/profiles.php:38
+msgid "Profile deleted."
+msgstr "Profil borttagen."
+
+#: ../../mod/profiles.php:56 ../../mod/profiles.php:92
+msgid "Profile-"
+msgstr "Profil-"
+
+#: ../../mod/profiles.php:77 ../../mod/profiles.php:120
+msgid "New profile created."
+msgstr "Ny profil skapad."
+
+#: ../../mod/profiles.php:98
+msgid "Profile unavailable to clone."
+msgstr "Profil inte tillgänglig för kloning."
+
+#: ../../mod/profiles.php:136
+msgid "Profile unavailable to export."
+msgstr "Profil inte tillgänglig för export."
+
+#: ../../mod/profiles.php:232
+msgid "Profile Name is required."
+msgstr "Profilnamn krävs."
+
+#: ../../mod/profiles.php:378
+msgid "Marital Status"
+msgstr "Civilstånd"
+
+#: ../../mod/profiles.php:382
+msgid "Romantic Partner"
+msgstr "Romantisk partner"
+
+#: ../../mod/profiles.php:386
+msgid "Likes"
+msgstr "Gillar"
+
+#: ../../mod/profiles.php:390
+msgid "Dislikes"
+msgstr "Ogillar"
+
+#: ../../mod/profiles.php:394
+msgid "Work/Employment"
+msgstr "Arbete/sysselsättning"
+
+#: ../../mod/profiles.php:397
+msgid "Religion"
+msgstr "Religion"
+
+#: ../../mod/profiles.php:401
+msgid "Political Views"
+msgstr "Politisk åskådning"
+
+#: ../../mod/profiles.php:405
+msgid "Gender"
+msgstr "Kön"
+
+#: ../../mod/profiles.php:409
+msgid "Sexual Preference"
+msgstr "Sexuell preferens"
+
+#: ../../mod/profiles.php:413
+msgid "Homepage"
+msgstr "Hemsida"
+
+#: ../../mod/profiles.php:417
+msgid "Interests"
+msgstr "Intressen"
+
+#: ../../mod/profiles.php:421 ../../mod/admin.php:866
+msgid "Address"
+msgstr "Adress"
+
+#: ../../mod/profiles.php:511
+msgid "Profile updated."
+msgstr "Profil uppdaterad."
+
+#: ../../mod/profiles.php:590
+msgid "Hide your contact/friend list from viewers of this profile?"
+msgstr "Dölj din kontakt-/vänlista för de som ser den här profilen"
+
+#: ../../mod/profiles.php:632
+msgid "Edit Profile Details"
+msgstr "Redigera profildetaljer"
+
+#: ../../mod/profiles.php:634
+msgid "View this profile"
+msgstr "Visa den här profilen"
+
+#: ../../mod/profiles.php:636
+msgid "Change Profile Photo"
+msgstr "Byt profilfoto"
+
+#: ../../mod/profiles.php:637
+msgid "Create a new profile using these settings"
+msgstr "Skapa en ny profil utifrån de här inställningarna"
+
+#: ../../mod/profiles.php:638
+msgid "Clone this profile"
+msgstr "Klona den här profilen"
+
+#: ../../mod/profiles.php:639
+msgid "Delete this profile"
+msgstr "Ta bort den här profilen"
+
+#: ../../mod/profiles.php:641
+msgid "Import profile from file"
+msgstr "Importera profil från fil"
+
+#: ../../mod/profiles.php:642
+msgid "Export profile to file"
+msgstr "Exportera profil som fil"
+
+#: ../../mod/profiles.php:643
+msgid "Profile Name:"
+msgstr "Profilnamn:"
+
+#: ../../mod/profiles.php:644
+msgid "Your Full Name:"
+msgstr "Ditt fulllständiga namn:"
+
+#: ../../mod/profiles.php:645
+msgid "Title/Description:"
+msgstr "Titel/beskrivning:"
+
+#: ../../mod/profiles.php:646
+msgid "Your Gender:"
+msgstr "Ditt kön:"
+
+#: ../../mod/profiles.php:647
+msgid "Birthday :"
+msgstr "Födelsedag:"
+
+#: ../../mod/profiles.php:648
+msgid "Street Address:"
+msgstr "Gatuadress:"
+
+#: ../../mod/profiles.php:649
+msgid "Locality/City:"
+msgstr "Ort:"
+
+#: ../../mod/profiles.php:650
+msgid "Postal/Zip Code:"
+msgstr "Postnummer:"
+
+#: ../../mod/profiles.php:651
+msgid "Country:"
+msgstr "Land:"
+
+#: ../../mod/profiles.php:652
+msgid "Region/State:"
+msgstr "Region:"
+
+#: ../../mod/profiles.php:653
+msgid "<span class=\"heart\">&hearts;</span> Marital Status:"
+msgstr "<span class=\"heart\">&hearts;</span> Civilstånd:"
+
+#: ../../mod/profiles.php:654
+msgid "Who: (if applicable)"
+msgstr "Vem: (om tillämpligt)"
+
+#: ../../mod/profiles.php:655
+msgid "Examples: cathy123, Cathy Williams, cathy@example.com"
+msgstr "Exempel: cathy123, Cathy Williams, cathy@example.com"
+
+#: ../../mod/profiles.php:656
+msgid "Since [date]:"
+msgstr "Sedan [datum]"
+
+#: ../../mod/profiles.php:658
+msgid "Homepage URL:"
+msgstr "Hemsideadress:"
+
+#: ../../mod/profiles.php:661
+msgid "Religious Views:"
+msgstr "Religion/livsåskådning:"
+
+#: ../../mod/profiles.php:662
+msgid "Keywords:"
+msgstr "Nyckelord:"
+
+#: ../../mod/profiles.php:665
+msgid "Example: fishing photography software"
+msgstr "Exempel: fiske fotografering mjukvara"
+
+#: ../../mod/profiles.php:666
+msgid "Used in directory listings"
+msgstr "Används i kataloglistningar"
+
+#: ../../mod/profiles.php:667
+msgid "Tell us about yourself..."
+msgstr "Beskriv dig själv..."
+
+#: ../../mod/profiles.php:668
+msgid "Hobbies/Interests"
+msgstr "Fritidssysselsättning/intressen"
+
+#: ../../mod/profiles.php:669
+msgid "Contact information and Social Networks"
+msgstr "Kontaktinformation och sociala nätverk"
+
+#: ../../mod/profiles.php:670
+msgid "My other channels"
+msgstr "Mina andra kanaler"
+
+#: ../../mod/profiles.php:671
+msgid "Musical interests"
+msgstr "Musikintressen"
+
+#: ../../mod/profiles.php:672
+msgid "Books, literature"
+msgstr "Böcker, litteratur"
+
+#: ../../mod/profiles.php:673
+msgid "Television"
+msgstr "Tv"
+
+#: ../../mod/profiles.php:674
+msgid "Film/dance/culture/entertainment"
+msgstr "Film/dans/kultur/underhållning"
+
+#: ../../mod/profiles.php:675
+msgid "Love/romance"
+msgstr "Kärlek/romantik"
+
+#: ../../mod/profiles.php:676
+msgid "Work/employment"
+msgstr "Arbete/sysselsättning"
+
+#: ../../mod/profiles.php:677
+msgid "School/education"
+msgstr "Skola/utbildning"
+
+#: ../../mod/profiles.php:683
+msgid "This is your default profile."
+msgstr "Det här är din standardprofil."
+
+#: ../../mod/profiles.php:694 ../../mod/directory.php:188
+msgid "Age: "
+msgstr "Ålder:"
+
+#: ../../mod/profiles.php:737
+msgid "Edit/Manage Profiles"
+msgstr "Redigera/hantera profiler"
+
+#: ../../mod/profiles.php:738
+msgid "Add profile things"
+msgstr "Lägg till profilsaker"
+
+#: ../../mod/profiles.php:739
+msgid "Include desirable objects in your profile"
+msgstr "Inkludera fina prylar i din profil"
+
#: ../../mod/tagrm.php:44 ../../mod/tagrm.php:94
msgid "Tag removed"
msgstr "Tagg borttagen"
@@ -6749,10 +7027,6 @@ msgstr "Aktiva tillägg"
msgid "Site settings updated."
msgstr "Serverinställningar uppdaterade."
-#: ../../mod/admin.php:363
-msgid "mobile"
-msgstr "mobilt"
-
#: ../../mod/admin.php:365
msgid "experimental"
msgstr "experimentellt"
@@ -7310,111 +7584,118 @@ msgstr "Fältdefinition hittades inte"
msgid "Edit Profile Field"
msgstr "Redigera profilfält"
-#: ../../mod/locs.php:19 ../../mod/locs.php:46
-msgid "Location not found."
-msgstr "Platsen hittades inte."
+#: ../../mod/manage.php:136
+#, php-format
+msgid "You have created %1$.0f of %2$.0f allowed channels."
+msgstr "Du har skapat %1$.0f av %2$.0f tillåtna kanaler."
-#: ../../mod/locs.php:50
-msgid "Primary location cannot be removed."
-msgstr "Huvudplatsen kan inte tas bort."
+#: ../../mod/manage.php:144
+msgid "Create a new channel"
+msgstr "Skapa en ny kanal"
-#: ../../mod/locs.php:82
-msgid "No locations found."
-msgstr "Inga platser hittades."
+#: ../../mod/manage.php:149
+msgid "Current Channel"
+msgstr "Nuvarande kanal"
-#: ../../mod/locs.php:95
-msgid "Manage Channel Locations"
-msgstr "Hantera kanalplatser"
+#: ../../mod/manage.php:151
+msgid "Attach to one of your channels by selecting it."
+msgstr "Anslut till en av dina kanaler genom att välja den."
-#: ../../mod/locs.php:96
-msgid "Location (address)"
-msgstr "Plats (adress)"
+#: ../../mod/manage.php:152
+msgid "Default Channel"
+msgstr "Standardkanal"
-#: ../../mod/locs.php:97
-msgid "Primary Location"
-msgstr "Huvudplats"
+#: ../../mod/manage.php:153
+msgid "Make Default"
+msgstr "Gör till standard"
-#: ../../mod/locs.php:98
-msgid "Drop location"
-msgstr "Ta bort plats"
+#: ../../mod/menu.php:31
+msgid "Menu updated."
+msgstr "Meny uppdaterad."
-#: ../../mod/mail.php:33
-msgid "Unable to lookup recipient."
-msgstr "Kunde inte hitta mottagare."
+#: ../../mod/menu.php:35
+msgid "Unable to update menu."
+msgstr "Kunde inte uppdatera meny."
-#: ../../mod/mail.php:41
-msgid "Unable to communicate with requested channel."
-msgstr "Kunde inte kommunicera med den begärda kanalen."
+#: ../../mod/menu.php:40
+msgid "Menu created."
+msgstr "Meny skapad."
-#: ../../mod/mail.php:48
-msgid "Cannot verify requested channel."
-msgstr "Kan inte bekräfta den begärda kanalen."
+#: ../../mod/menu.php:44
+msgid "Unable to create menu."
+msgstr "Kunde inte skapa meny."
-#: ../../mod/mail.php:74
-msgid "Selected channel has private message restrictions. Send failed."
-msgstr "Den valda kanalen har restriktioner för privata meddelanden. Misslyckades att skicka."
+#: ../../mod/menu.php:76
+msgid "Manage Menus"
+msgstr "Hantera menyer"
-#: ../../mod/mail.php:136
-msgid "Message deleted."
-msgstr "Meddelande borttaget."
+#: ../../mod/menu.php:79
+msgid "Drop"
+msgstr "Ta bort"
-#: ../../mod/mail.php:153
-msgid "Message recalled."
-msgstr "Meddelande återkallat."
+#: ../../mod/menu.php:81
+msgid "Bookmarks allowed"
+msgstr "Bokmärken tillåtna"
-#: ../../mod/mail.php:222
-msgid "Send Private Message"
-msgstr "Skicka privat meddelande."
+#: ../../mod/menu.php:82
+msgid "Create a new menu"
+msgstr "Skapa en ny meny"
-#: ../../mod/mail.php:223 ../../mod/mail.php:340
-msgid "To:"
-msgstr "Till:"
+#: ../../mod/menu.php:83
+msgid "Delete this menu"
+msgstr "Ta bort den här menyn"
-#: ../../mod/mail.php:228 ../../mod/mail.php:342
-msgid "Subject:"
-msgstr "Ämne:"
+#: ../../mod/menu.php:84 ../../mod/menu.php:125
+msgid "Edit menu contents"
+msgstr "Redigera menyinnehåll"
-#: ../../mod/mail.php:232 ../../mod/mail.php:345 ../../mod/invite.php:131
-msgid "Your message:"
-msgstr "Ditt meddelande:"
+#: ../../mod/menu.php:85
+msgid "Edit this menu"
+msgstr "Redigera den här menyn"
-#: ../../mod/mail.php:239
-msgid "Send"
-msgstr "Skicka"
+#: ../../mod/menu.php:96
+msgid "New Menu"
+msgstr "Ny meny"
-#: ../../mod/mail.php:266
-msgid "Message not found."
-msgstr "Meddelandet hittades inte."
+#: ../../mod/menu.php:97 ../../mod/menu.php:126
+msgid "Menu name"
+msgstr "Menynamn"
-#: ../../mod/mail.php:309
-msgid "Delete message"
-msgstr "Ta bort meddelande"
+#: ../../mod/menu.php:97 ../../mod/menu.php:126
+msgid "Must be unique, only seen by you"
+msgstr "Måste vara unikt, ses endast av dig"
-#: ../../mod/mail.php:310
-msgid "Recall message"
-msgstr "Återkalla meddelande"
+#: ../../mod/menu.php:98 ../../mod/menu.php:127
+msgid "Menu title"
+msgstr "Menytitel"
-#: ../../mod/mail.php:312
-msgid "Message has been recalled."
-msgstr "Meddelandet har återkallats."
+#: ../../mod/menu.php:98 ../../mod/menu.php:127
+msgid "Menu title as seen by others"
+msgstr "Menytitel som andra ser den"
-#: ../../mod/mail.php:329
-msgid "Private Conversation"
-msgstr "Privat konversation"
+#: ../../mod/menu.php:99 ../../mod/menu.php:128
+msgid "Allow bookmarks"
+msgstr "Tillåt bokmärken"
-#: ../../mod/mail.php:333 ../../mod/message.php:72
-msgid "Delete conversation"
-msgstr "Ta bort konversation"
+#: ../../mod/menu.php:99 ../../mod/menu.php:128
+msgid "Menu may be used to store saved bookmarks"
+msgstr "Menyn kan användas för att spara bokmärken"
-#: ../../mod/mail.php:335
-msgid ""
-"No secure communications available. You <strong>may</strong> be able to "
-"respond from the sender's profile page."
-msgstr "Ingen säker kommunikationskanal tillgänglig. Du kan <strong>möjligtvis</strong> svara från avsändarens profilsida."
+#: ../../mod/menu.php:114
+msgid "Menu deleted."
+msgstr "Meny borttagen."
-#: ../../mod/mail.php:339
-msgid "Send Reply"
-msgstr "Skicka svar"
+#: ../../mod/menu.php:116
+msgid "Menu could not be deleted."
+msgstr "Menyn kunde inte tas bort."
+
+#: ../../mod/menu.php:122
+msgid "Edit Menu"
+msgstr "Redigera meny"
+
+#: ../../mod/menu.php:124
+msgid "Add or remove entries to this menu"
+msgstr "Lägg till eller ta bort menyval"
#: ../../mod/invite.php:25
msgid "Total invitation limit exceeded."
@@ -7481,30 +7762,45 @@ msgstr "eller besök "
msgid "3. Click [Connect]"
msgstr "3. Klicka [Ta kontakt]"
-#: ../../mod/manage.php:136
-#, php-format
-msgid "You have created %1$.0f of %2$.0f allowed channels."
-msgstr "Du har skapat %1$.0f av %2$.0f tillåtna kanaler."
+#: ../../mod/network.php:84
+msgid "No such group"
+msgstr "Ingen sådan grupp"
-#: ../../mod/manage.php:144
-msgid "Create a new channel"
-msgstr "Skapa en ny kanal"
+#: ../../mod/network.php:122
+msgid "Search Results For:"
+msgstr "Sökresultat för:"
-#: ../../mod/manage.php:149
-msgid "Current Channel"
-msgstr "Nuvarande kanal"
+#: ../../mod/network.php:176
+msgid "Collection is empty"
+msgstr "Kretsen är tom"
-#: ../../mod/manage.php:151
-msgid "Attach to one of your channels by selecting it."
-msgstr "Anslut till en av dina kanaler genom att välja den."
+#: ../../mod/network.php:184
+msgid "Collection: "
+msgstr "Krets: "
-#: ../../mod/manage.php:152
-msgid "Default Channel"
-msgstr "Standardkanal"
+#: ../../mod/network.php:197
+msgid "Connection: "
+msgstr "Kontakt:"
-#: ../../mod/manage.php:153
-msgid "Make Default"
-msgstr "Gör till standard"
+#: ../../mod/network.php:200
+msgid "Invalid connection."
+msgstr "Ogiltig kontakt."
+
+#: ../../mod/notifications.php:26
+msgid "Invalid request identifier."
+msgstr "Ogiltigt ID på förfrågan."
+
+#: ../../mod/notifications.php:35
+msgid "Discard"
+msgstr "Förkasta"
+
+#: ../../mod/notifications.php:94 ../../mod/notify.php:53
+msgid "No more system notifications."
+msgstr "Inga fler systemnotifieringar."
+
+#: ../../mod/notifications.php:98 ../../mod/notify.php:57
+msgid "System Notifications"
+msgstr "Systemnotifieringar"
#: ../../mod/update_channel.php:43 ../../mod/update_display.php:25
#: ../../mod/update_network.php:23 ../../mod/update_search.php:46
@@ -7512,14 +7808,6 @@ msgstr "Gör till standard"
msgid "[Embedded content - reload page to view]"
msgstr "[Inbäddat innehåll - ladda om sidan för att visa]"
-#: ../../mod/layouts.php:110
-msgid "Help with this feature"
-msgstr "Hjälp för den här funktionen"
-
-#: ../../mod/layouts.php:130
-msgid "Layout Name"
-msgstr "Layoutnamn"
-
#: ../../mod/lockview.php:31
msgid "Remote privacy information not available."
msgstr "Icke-lokal integritetsinformation är inte tillgänglig"
@@ -7553,29 +7841,14 @@ msgstr "Totalt antal röster"
msgid "Average Rating"
msgstr "Genomsnittsbetyg"
-#: ../../mod/network.php:81
-msgid "No such group"
-msgstr "Ingen sådan grupp"
-
-#: ../../mod/network.php:119
-msgid "Search Results For:"
-msgstr "Sökresultat för:"
-
-#: ../../mod/network.php:173
-msgid "Collection is empty"
-msgstr "Kretsen är tom"
-
-#: ../../mod/network.php:181
-msgid "Collection: "
-msgstr "Krets: "
-
-#: ../../mod/network.php:194
-msgid "Connection: "
-msgstr "Kontakt:"
+#: ../../mod/openid.php:26
+msgid "OpenID protocol error. No ID returned."
+msgstr "Protokollfel för OpenID. Inget ID returnerades."
-#: ../../mod/network.php:197
-msgid "Invalid connection."
-msgstr "Ogiltig kontakt."
+#: ../../mod/openid.php:72 ../../mod/openid.php:180 ../../mod/post.php:261
+#, php-format
+msgid "Welcome %s. Remote authentication successful."
+msgstr "Välkommen %s. Fjärrinloggning lyckades."
#: ../../mod/wall_upload.php:35
msgid "Wall Photos"
@@ -7597,94 +7870,6 @@ msgstr "är intresserad av:"
msgid "No matches"
msgstr "Inga träffar"
-#: ../../mod/menu.php:31
-msgid "Menu updated."
-msgstr "Meny uppdaterad."
-
-#: ../../mod/menu.php:35
-msgid "Unable to update menu."
-msgstr "Kunde inte uppdatera meny."
-
-#: ../../mod/menu.php:40
-msgid "Menu created."
-msgstr "Meny skapad."
-
-#: ../../mod/menu.php:44
-msgid "Unable to create menu."
-msgstr "Kunde inte skapa meny."
-
-#: ../../mod/menu.php:76
-msgid "Manage Menus"
-msgstr "Hantera menyer"
-
-#: ../../mod/menu.php:79
-msgid "Drop"
-msgstr "Ta bort"
-
-#: ../../mod/menu.php:81
-msgid "Bookmarks allowed"
-msgstr "Bokmärken tillåtna"
-
-#: ../../mod/menu.php:82
-msgid "Create a new menu"
-msgstr "Skapa en ny meny"
-
-#: ../../mod/menu.php:83
-msgid "Delete this menu"
-msgstr "Ta bort den här menyn"
-
-#: ../../mod/menu.php:84 ../../mod/menu.php:125
-msgid "Edit menu contents"
-msgstr "Redigera menyinnehåll"
-
-#: ../../mod/menu.php:85
-msgid "Edit this menu"
-msgstr "Redigera den här menyn"
-
-#: ../../mod/menu.php:96
-msgid "New Menu"
-msgstr "Ny meny"
-
-#: ../../mod/menu.php:97 ../../mod/menu.php:126
-msgid "Menu name"
-msgstr "Menynamn"
-
-#: ../../mod/menu.php:97 ../../mod/menu.php:126
-msgid "Must be unique, only seen by you"
-msgstr "Måste vara unikt, ses endast av dig"
-
-#: ../../mod/menu.php:98 ../../mod/menu.php:127
-msgid "Menu title"
-msgstr "Menytitel"
-
-#: ../../mod/menu.php:98 ../../mod/menu.php:127
-msgid "Menu title as seen by others"
-msgstr "Menytitel som andra ser den"
-
-#: ../../mod/menu.php:99 ../../mod/menu.php:128
-msgid "Allow bookmarks"
-msgstr "Tillåt bokmärken"
-
-#: ../../mod/menu.php:99 ../../mod/menu.php:128
-msgid "Menu may be used to store saved bookmarks"
-msgstr "Menyn kan användas för att spara bokmärken"
-
-#: ../../mod/menu.php:114
-msgid "Menu deleted."
-msgstr "Meny borttagen."
-
-#: ../../mod/menu.php:116
-msgid "Menu could not be deleted."
-msgstr "Menyn kunde inte tas bort."
-
-#: ../../mod/menu.php:122
-msgid "Edit Menu"
-msgstr "Redigera meny"
-
-#: ../../mod/menu.php:124
-msgid "Add or remove entries to this menu"
-msgstr "Lägg till eller ta bort menyval"
-
#: ../../mod/message.php:41
msgid "Conversation removed."
msgstr "Konversation borttagen."
@@ -7732,27 +7917,19 @@ msgid "Channel Type"
msgstr "Kanaltyp"
#: ../../mod/new_channel.php:119
+msgid "?"
+msgstr "?"
+
+#: ../../mod/new_channel.php:120
+msgid "What is this?"
+msgstr "Vad är detta?"
+
+#: ../../mod/new_channel.php:121
msgid ""
"Please choose a channel type (such as social networking or community forum) "
"and privacy requirements so we can select the best permissions for you"
msgstr "Välj en kanaltyp (som till exempel socialt nätverkande eller gemenskapsforum) och integritetskrav, så kan vi välja de bästa behörigheterna åt dig"
-#: ../../mod/notifications.php:26
-msgid "Invalid request identifier."
-msgstr "Ogiltigt ID på förfrågan."
-
-#: ../../mod/notifications.php:35
-msgid "Discard"
-msgstr "Förkasta"
-
-#: ../../mod/notifications.php:94 ../../mod/notify.php:53
-msgid "No more system notifications."
-msgstr "Inga fler systemnotifieringar."
-
-#: ../../mod/notifications.php:98 ../../mod/notify.php:57
-msgid "System Notifications"
-msgstr "Systemnotifieringar"
-
#: ../../mod/xchan.php:6
msgid "Xchan Lookup"
msgstr "Xchan-sökning"
@@ -7773,196 +7950,55 @@ msgstr "Kunde inte hitta din hubb."
msgid "Post successful."
msgstr "Sändning lyckades."
-#: ../../mod/directory.php:172
+#: ../../mod/directory.php:201
msgid "Gender: "
msgstr "Kön:"
-#: ../../mod/directory.php:174
+#: ../../mod/directory.php:203
msgid "Status: "
msgstr "Status: "
-#: ../../mod/directory.php:176
+#: ../../mod/directory.php:205
msgid "Homepage: "
msgstr "Hemsida: "
-#: ../../mod/directory.php:179
+#: ../../mod/directory.php:208
msgid "Hometown: "
msgstr "Hemort: "
-#: ../../mod/directory.php:181
+#: ../../mod/directory.php:210
msgid "About: "
msgstr "Om: "
-#: ../../mod/directory.php:236
+#: ../../mod/directory.php:265
msgid "Public Forum:"
msgstr "Offentligt forum:"
-#: ../../mod/directory.php:239
+#: ../../mod/directory.php:268
msgid "Keywords: "
msgstr "Nyckelord: "
-#: ../../mod/directory.php:279
+#: ../../mod/directory.php:318
msgid "Finding:"
msgstr "Sökning efter:"
-#: ../../mod/directory.php:284
+#: ../../mod/directory.php:323
msgid "next page"
msgstr "nästa sida"
-#: ../../mod/directory.php:284
+#: ../../mod/directory.php:323
msgid "previous page"
msgstr "föregående sida"
-#: ../../mod/directory.php:301
+#: ../../mod/directory.php:340
msgid "No entries (some entries may be hidden)."
msgstr "Inga resultat (vissa resultat kan vara dolda)."
-#: ../../mod/photos.php:77
-msgid "Page owner information could not be retrieved."
-msgstr "Information om sidans ägare kunde inte hittas."
-
-#: ../../mod/photos.php:97
-msgid "Album not found."
-msgstr "Albumet hittades inte."
-
-#: ../../mod/photos.php:119 ../../mod/photos.php:672
-msgid "Delete Album"
-msgstr "Ta bort album"
-
-#: ../../mod/photos.php:159 ../../mod/photos.php:958
-msgid "Delete Photo"
-msgstr "Ta bort foto"
-
-#: ../../mod/photos.php:469
-msgid "No photos selected"
-msgstr "Inga foton valda"
-
-#: ../../mod/photos.php:513
-msgid "Access to this item is restricted."
-msgstr "Åtkomst till den här posten är begränsat."
-
-#: ../../mod/photos.php:552
-#, php-format
-msgid "%1$.2f MB of %2$.2f MB photo storage used."
-msgstr "%1$.2f MB av %2$.2f MB fotolagring använt."
-
-#: ../../mod/photos.php:555
-#, php-format
-msgid "%1$.2f MB photo storage used."
-msgstr "%1$.2f MB fotolagring använt."
-
-#: ../../mod/photos.php:579
-msgid "Upload Photos"
-msgstr "Ladda upp foton"
-
-#: ../../mod/photos.php:583 ../../mod/photos.php:665 ../../mod/photos.php:943
-msgid "Enter a new album name"
-msgstr "Ange ett nytt albumnamn"
-
-#: ../../mod/photos.php:584 ../../mod/photos.php:666 ../../mod/photos.php:944
-msgid "or select an existing one (doubleclick)"
-msgstr "eller välj ett befintligt (dubbelklicka)"
-
-#: ../../mod/photos.php:585
-msgid "Do not show a status post for this upload"
-msgstr "Visa inte en statusuppdatering för den här uppladdningen"
-
-#: ../../mod/photos.php:613
-msgid "Album name could not be decoded"
-msgstr "Albumnamn kunde inte tolkas"
-
-#: ../../mod/photos.php:654 ../../mod/photos.php:1167
-#: ../../mod/photos.php:1183
-msgid "Contact Photos"
-msgstr "Kontaktfoton"
-
-#: ../../mod/photos.php:678
-msgid "Show Newest First"
-msgstr "Visa nyast först"
-
-#: ../../mod/photos.php:680
-msgid "Show Oldest First"
-msgstr "Visa äldst först"
-
-#: ../../mod/photos.php:707 ../../mod/photos.php:1215
-msgid "View Photo"
-msgstr "Visa foto"
-
-#: ../../mod/photos.php:736
-msgid "Edit Album"
-msgstr "Redigera album"
-
-#: ../../mod/photos.php:781
-msgid "Permission denied. Access to this item may be restricted."
-msgstr "Behörighet saknas. Åtkomst till den här posten kan vara begränsat."
-
-#: ../../mod/photos.php:783
-msgid "Photo not available"
-msgstr "Foto inte tillgängligt"
-
-#: ../../mod/photos.php:841
-msgid "Use as profile photo"
-msgstr "Använd som profilfoto"
-
-#: ../../mod/photos.php:848
-msgid "Private Photo"
-msgstr "Privat foto"
-
-#: ../../mod/photos.php:863
-msgid "View Full Size"
-msgstr "Visa fullstorlek"
-
-#: ../../mod/photos.php:937
-msgid "Edit photo"
-msgstr "Redigera foto"
-
-#: ../../mod/photos.php:939
-msgid "Rotate CW (right)"
-msgstr "Rotera medurs (höger)"
-
-#: ../../mod/photos.php:940
-msgid "Rotate CCW (left)"
-msgstr "Rotera moturs (vänster)"
-
-#: ../../mod/photos.php:947
-msgid "Caption"
-msgstr "Bildtext"
-
-#: ../../mod/photos.php:949
-msgid "Add a Tag"
-msgstr "Lägg till en tagg"
-
-#: ../../mod/photos.php:953
-msgid "Example: @bob, @Barbara_Jensen, @jim@example.com"
-msgstr "Exempel: @bob, @Barbara_Jensen, @jim@example.com"
-
-#: ../../mod/photos.php:956
-msgid "Flag as adult in album view"
-msgstr "Flagga som olämpligt för barn i albumvyn"
-
-#: ../../mod/photos.php:1133
-msgid "In This Photo:"
-msgstr "På fotot:"
-
-#: ../../mod/photos.php:1221
-msgid "View Album"
-msgstr "Visa album"
-
-#: ../../mod/photos.php:1244
-msgid "Recent Photos"
-msgstr "Nya foton"
-
-#: ../../mod/ping.php:265
-msgid "sent you a private message"
-msgstr "skickade ett privat meddelande till dig"
-
-#: ../../mod/ping.php:316
-msgid "added your channel"
-msgstr "lade till din kanal"
-
-#: ../../mod/ping.php:357
-msgid "posted an event"
-msgstr "skapade en händelse"
+#: ../../mod/post.php:229
+msgid ""
+"Remote authentication blocked. You are logged into this site locally. Please"
+" logout and retry."
+msgstr "Fjärrinloggning blockerades. Du är inloggad på den här servern lokalt. Logga ut och försök igen."
#: ../../mod/appman.php:28 ../../mod/appman.php:44
msgid "App installed."
@@ -8320,41 +8356,41 @@ msgstr "Oordnade fotoalbum"
msgid "Are you a clean desk or a messy desk person?"
msgstr "Föredrar du ett tomt eller stökigt skrivbord?"
-#: ../../boot.php:1293
+#: ../../boot.php:1345
#, php-format
msgid "Update %s failed. See error logs."
msgstr "Uppdatering %s misslyckades. Se felloggar."
-#: ../../boot.php:1296
+#: ../../boot.php:1348
#, php-format
msgid "Update Error at %s"
msgstr "Uppdateringsfel på %s"
-#: ../../boot.php:1463
+#: ../../boot.php:1515
msgid ""
"Create an account to access services and applications within the Red Matrix"
msgstr "Skapa ett konto för att komma åt tjänster och applikationer inom Red Matrix"
-#: ../../boot.php:1489
+#: ../../boot.php:1543
msgid "Password"
msgstr "Lösenord"
-#: ../../boot.php:1490
+#: ../../boot.php:1544
msgid "Remember me"
msgstr "Kom ihåg mig"
-#: ../../boot.php:1493
+#: ../../boot.php:1547
msgid "Forgot your password?"
msgstr "Glömt lösenordet?"
-#: ../../boot.php:1567
+#: ../../boot.php:1628
msgid "permission denied"
msgstr "behörighet saknas"
-#: ../../boot.php:1568
+#: ../../boot.php:1629
msgid "Got Zot?"
msgstr "Got Zot?"
-#: ../../boot.php:2030
+#: ../../boot.php:2112
msgid "toggle mobile"
msgstr "växla mobil"
diff --git a/view/sv/strings.php b/view/sv/strings.php
index 3217a520e..7cfc355ea 100644
--- a/view/sv/strings.php
+++ b/view/sv/strings.php
@@ -7,461 +7,109 @@ function string_plural_select_sv($n){
;
$a->strings["Cannot locate DNS info for database server '%s'"] = "Kan inte hitta DNS-information för databasserver '%s'";
$a->strings["Profile Photos"] = "Profilfoton";
-$a->strings["photo"] = "foto";
-$a->strings["event"] = "händelse";
-$a->strings["channel"] = "kanal";
-$a->strings["status"] = "status";
-$a->strings["comment"] = "kommentar";
-$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s gillar %2\$ss %3\$s";
-$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s gillar inte %2\$ss %3\$s";
-$a->strings["%1\$s is now connected with %2\$s"] = "%1\$s har nu kontakt med %2\$s";
-$a->strings["%1\$s poked %2\$s"] = "%1\$s puffade %2\$s";
-$a->strings["poked"] = "puffade";
-$a->strings["__ctx:mood__ %1\$s is %2\$s"] = "%1\$s är %2\$s";
-$a->strings["Select"] = "Välj";
-$a->strings["Delete"] = "Ta bort";
-$a->strings["Private Message"] = "Privat meddelande";
-$a->strings["Message signature validated"] = "Meddelandesignatur bekräftad";
-$a->strings["Message signature incorrect"] = "Meddelandesignatur felaktig";
-$a->strings["View %s's profile @ %s"] = "Visa %ss profil på %s";
-$a->strings["Categories:"] = "Kategorier:";
-$a->strings["Filed under:"] = "Postat under:";
-$a->strings[" from %s"] = "från %s";
-$a->strings["last edited: %s"] = "senast redigerat: %s";
-$a->strings["Expires: %s"] = "Upphör: %s";
-$a->strings["View in context"] = "Visa sammanhang";
-$a->strings["Please wait"] = "Vänta";
-$a->strings["remove"] = "ta bort";
-$a->strings["Loading..."] = "Laddar...";
-$a->strings["Delete Selected Items"] = "Ta bort valda poster";
-$a->strings["View Source"] = "Visa källa";
-$a->strings["Follow Thread"] = "Följ tråd";
-$a->strings["View Status"] = "Visa status";
-$a->strings["View Profile"] = "Visa profil";
-$a->strings["View Photos"] = "Visa foton";
-$a->strings["Matrix Activity"] = "Matrisaktivitet";
-$a->strings["Connect"] = "Ta kontakt";
-$a->strings["Edit Contact"] = "Redigera kontakt";
-$a->strings["Send PM"] = "Skicka meddelande";
-$a->strings["Poke"] = "Puffa";
-$a->strings["Unknown"] = "Okända";
-$a->strings["%s likes this."] = "%s gillar det här.";
-$a->strings["%s doesn't like this."] = "%s gillar inte det här.";
-$a->strings["<span %1\$s>%2\$d people</span> like this."] = array(
- 0 => "<span %1\$s>%2\$d person</span> gillar det här.",
- 1 => "<span %1\$s>%2\$d personer</span> gillar det här.",
-);
-$a->strings["<span %1\$s>%2\$d people</span> don't like this."] = array(
- 0 => "<span %1\$s>%2\$d person</span> gillar inte det här.",
- 1 => "<span %1\$s>%2\$d personer</span> gillar inte det här.",
-);
-$a->strings["and"] = "och";
-$a->strings[", and %d other people"] = array(
- 0 => ", och %d annan person",
- 1 => ", och %d andra personer",
-);
-$a->strings["%s like this."] = "%s gillar det här.";
-$a->strings["%s don't like this."] = "%s gillar inte det här.";
-$a->strings["Visible to <strong>everybody</strong>"] = "Kan ses av <strong>alla</strong>";
-$a->strings["Please enter a link URL:"] = "Ange en länkadress:";
-$a->strings["Please enter a video link/URL:"] = "Ange en videolänkadress:";
-$a->strings["Please enter an audio link/URL:"] = "Ange en ljudlänkadress";
-$a->strings["Tag term:"] = "Tagguttryck";
-$a->strings["Save to Folder:"] = "Spara i mapp:";
-$a->strings["Where are you right now?"] = "Var är du just nu?";
-$a->strings["Expires YYYY-MM-DD HH:MM"] = "Upphör YYYY-MM-DD HH:MM";
-$a->strings["Preview"] = "Förhandsgranska";
-$a->strings["Share"] = "Dela";
-$a->strings["Page link title"] = "Titel på sidlänk";
-$a->strings["Post as"] = "Posta som";
-$a->strings["Upload photo"] = "Ladda upp foto";
-$a->strings["upload photo"] = "ladda upp foto";
-$a->strings["Attach file"] = "Bifoga fil";
-$a->strings["attach file"] = "bifoga fil";
-$a->strings["Insert web link"] = "Infoga webblänk";
-$a->strings["web link"] = "webblänk";
-$a->strings["Insert video link"] = "Infoga videolänk";
-$a->strings["video link"] = "videolänk";
-$a->strings["Insert audio link"] = "Infoga ljudlänk";
-$a->strings["audio link"] = "ljudlänk";
-$a->strings["Set your location"] = "Ange din plats";
-$a->strings["set location"] = "ange plats";
-$a->strings["Clear browser location"] = "Rensa webbläsarplats";
-$a->strings["clear location"] = "rensa plats";
-$a->strings["Set title"] = "Ange titel";
-$a->strings["Categories (comma-separated list)"] = "Kategorier (kommaseparerad lista)";
-$a->strings["Permission settings"] = "Behörighetsinställningar";
-$a->strings["permissions"] = "behörighet";
-$a->strings["Public post"] = "Offentligt inlägg";
-$a->strings["Example: bob@example.com, mary@example.com"] = "Exempel: bob@example.com, mary@example.com";
-$a->strings["Set expiration date"] = "Ange utgångsdatum";
-$a->strings["Encrypt text"] = "Kryptera text";
-$a->strings["OK"] = "OK";
-$a->strings["Cancel"] = "Avbryt";
-$a->strings["Discover"] = "Upptäck";
-$a->strings["Imported public streams"] = "Importerade offentliga strömmar";
-$a->strings["Commented Order"] = "Kommentarsordning";
-$a->strings["Sort by Comment Date"] = "Ordna efter kommentarsdatum";
-$a->strings["Posted Order"] = "Inläggsordning";
-$a->strings["Sort by Post Date"] = "Ordna efter när inlägget skrevs";
-$a->strings["Personal"] = "Personligt";
-$a->strings["Posts that mention or involve you"] = "Inlägg som nämner eller berör dig";
-$a->strings["New"] = "Nytt";
-$a->strings["Activity Stream - by date"] = "Aktivitetsström - efter datum";
-$a->strings["Starred"] = "Märkt";
-$a->strings["Favourite Posts"] = "Favoritinlägg";
-$a->strings["Spam"] = "Skräp";
-$a->strings["Posts flagged as SPAM"] = "Inlägg markerade som SKRÄP";
-$a->strings["Channel"] = "Kanal";
-$a->strings["Status Messages and Posts"] = "Statusmeddelanden och inlägg";
-$a->strings["About"] = "Om";
-$a->strings["Profile Details"] = "Profildetaljer";
-$a->strings["Photos"] = "Foton";
-$a->strings["Photo Albums"] = "Fotoalbum";
-$a->strings["Files"] = "Filer";
-$a->strings["Files and Storage"] = "Filer och lagring";
-$a->strings["Chatrooms"] = "Chattrum";
-$a->strings["Bookmarks"] = "Bokmärken";
-$a->strings["Saved Bookmarks"] = "Sparade bokmärken";
-$a->strings["Webpages"] = "Webbsidor";
-$a->strings["Manage Webpages"] = "Hantera webbsidor";
-$a->strings["Channel is blocked on this site."] = "Kanalen är blockerad på den här servern.";
-$a->strings["Channel location missing."] = "Kanalplats saknas.";
-$a->strings["Response from remote channel was incomplete."] = "Svar från den andra kanalen var ofullständigt.";
-$a->strings["Channel was deleted and no longer exists."] = "Kanalen har tagits bort och finns inte längre.";
-$a->strings["Protocol disabled."] = "Protokoll inaktiverat.";
-$a->strings["Channel discovery failed."] = "Kanalsökning misslyckades.";
-$a->strings["local account not found."] = "hittade inte lokalt konto.";
-$a->strings["Cannot connect to yourself."] = "Du kan inte kontakta dig själv.";
+$a->strings["Permission denied"] = "Behörighet saknas";
+$a->strings["(Unknown)"] = "(Okänt)";
+$a->strings["Visible to anybody on the internet."] = "Kan ses av vem som helst på Internet.";
+$a->strings["Visible to you only."] = "Kan bara ses av dig.";
+$a->strings["Visible to anybody in this network."] = "Kan ses av alla på det här nätverket.";
+$a->strings["Visible to anybody authenticated."] = "Kan ses av alla inloggade.";
+$a->strings["Visible to anybody on %s."] = "Kan ses av alla på %s.";
+$a->strings["Visible to all connections."] = "Kan ses av alla kontakter.";
+$a->strings["Visible to approved connections."] = "Kan ses av godkända kontakter.";
+$a->strings["Visible to specific connections."] = "Kan ses av valda kontakter.";
+$a->strings["Item not found."] = "Posten hittades inte.";
+$a->strings["Permission denied."] = "Behörighet saknas.";
+$a->strings["Collection not found."] = "Kretsen hittades inte.";
+$a->strings["Collection is empty."] = "Kretsen är tom.";
+$a->strings["Collection: %s"] = "Krets: %s";
+$a->strings["Connection: %s"] = "Kontakt: %s";
+$a->strings["Connection not found."] = "Kontakten hittades inte.";
+$a->strings["Edit"] = "Redigera";
+$a->strings["No recipient provided."] = "Ingen mottagare angiven.";
+$a->strings["[no subject]"] = "[inget ämne]";
+$a->strings["Unable to determine sender."] = "Kunde inte avgöra vem som är avsändare.";
+$a->strings["Stored post could not be verified."] = "Den sparade posten kunde inte verifieras.";
+$a->strings["view full size"] = "visa full storlek";
+$a->strings["Can view my normal stream and posts"] = "Kan se mina normala strömmar och inlägg";
+$a->strings["Can view my default channel profile"] = "Kan se min standardkanalprofil";
+$a->strings["Can view my photo albums"] = "Kan se mina fotoalbum";
+$a->strings["Can view my connections"] = "Kan se mina kontakter";
+$a->strings["Can view my file storage"] = "Kan se mitt filutrymme";
+$a->strings["Can view my webpages"] = "Kan se mina webbsidor";
+$a->strings["Can send me their channel stream and posts"] = "Kan skicka sina kanalströmmar och inlägg till mig";
+$a->strings["Can post on my channel page (\"wall\")"] = "Kan posta inlägg på min kanalsida (\"vägg\")";
+$a->strings["Can comment on or like my posts"] = "Kan kommentera eller gilla mina inlägg";
+$a->strings["Can send me private mail messages"] = "Kan skicka privata meddelanden till mig";
+$a->strings["Can post photos to my photo albums"] = "Kan lägga till foton i mitt fotoalbum";
+$a->strings["Can like/dislike stuff"] = "Kan gilla/ogilla saker";
+$a->strings["Profiles and things other than posts/comments"] = "Profiler och annat än inlägg/kommentarer";
+$a->strings["Can forward to all my channel contacts via post @mentions"] = "Kan vidarebefordra till alla mina kanalkontakter genom @omnämnanden";
+$a->strings["Advanced - useful for creating group forum channels"] = "Avancerat - användbart för att skapa kanaler för gruppforum";
+$a->strings["Can chat with me (when available)"] = "Kan chatta med mig (när tillgänglig)";
+$a->strings["Can write to my file storage"] = "Har skrivrättigheter i mitt filutrymme";
+$a->strings["Can edit my webpages"] = "Kan redigera mina webbsidor";
+$a->strings["Can source my public posts in derived channels"] = "Kan använda mina offentliga inlägg i kanaler nedströms";
+$a->strings["Somewhat advanced - very useful in open communities"] = "Ganska avancerat - väldigt användbart i öppna gemenskaper";
+$a->strings["Can administer my channel resources"] = "Kan administrera mina kanalresurser";
+$a->strings["Extremely advanced. Leave this alone unless you know what you are doing"] = "Extremt avancerat. Låt detta vara om du inte vet vad du gör";
+$a->strings["Social Networking"] = "Socialt nätverkande";
+$a->strings["Mostly Public"] = "Mestadels offentligt";
+$a->strings["Restricted"] = "Begränsat";
+$a->strings["Private"] = "Privat";
+$a->strings["Community Forum"] = "Gemenskapsforum";
+$a->strings["Feed Republish"] = "Vidarepublicering av flöde";
+$a->strings["Special Purpose"] = "Särskilt syfte";
+$a->strings["Celebrity/Soapbox"] = "Kändis/talarstol";
+$a->strings["Group Repository"] = "Gruppförråd";
+$a->strings["Other"] = "Annat";
+$a->strings["Custom/Expert Mode"] = "Anpassat/expertläge";
$a->strings["created a new post"] = "skapade ett nytt inlägg";
$a->strings["commented on %s's post"] = "kommenterade %ss inlägg";
+$a->strings["Tags"] = "Taggar";
+$a->strings["Categories"] = "Kategorier";
+$a->strings["Keywords"] = "Nyckelord";
+$a->strings["have"] = "har";
+$a->strings["has"] = "har";
+$a->strings["want"] = "vill ha";
+$a->strings["wants"] = "vill ha";
+$a->strings["like"] = "gilla";
+$a->strings["likes"] = "gillar";
+$a->strings["dislike"] = "ogilla";
+$a->strings["dislikes"] = "ogillar";
+$a->strings["__ctx:noun__ Like"] = array(
+ 0 => "gillar detta",
+ 1 => "gillar detta",
+);
$a->strings["New Page"] = "Ny sida";
-$a->strings["Edit"] = "Redigera";
$a->strings["View"] = "Visa";
+$a->strings["Preview"] = "Förhandsgranska";
$a->strings["Actions"] = "Åtgärder";
$a->strings["Page Link"] = "Länk";
$a->strings["Title"] = "Titel";
$a->strings["Created"] = "Skapad";
$a->strings["Edited"] = "Ändrad";
-$a->strings["%d invitation available"] = array(
- 0 => "%d inbjudan tillgänglig",
- 1 => "%d inbjudningar tillgängliga",
-);
-$a->strings["Advanced"] = "Avancerat";
-$a->strings["Find Channels"] = "Hitta kanaler";
-$a->strings["Enter name or interest"] = "Ange namn eller intresse";
-$a->strings["Connect/Follow"] = "Ta kontakt/följ";
-$a->strings["Examples: Robert Morgenstein, Fishing"] = "Exempel: Robert Morgenstein, Fiske";
-$a->strings["Find"] = "Sök";
-$a->strings["Channel Suggestions"] = "Kanalförslag";
-$a->strings["Random Profile"] = "Slumpvald profil";
-$a->strings["Invite Friends"] = "Bjud in vänner";
-$a->strings["Advanced example: name=fred and country=iceland"] = "Avancerat exempel: name=fred and country=iceland";
-$a->strings["Saved Folders"] = "Sparade mappar";
-$a->strings["Everything"] = "Allt";
-$a->strings["Categories"] = "Kategorier";
-$a->strings["%d connection in common"] = array(
- 0 => "%d gemensam kontakt",
- 1 => "%d gemensamma kontakter",
-);
-$a->strings["show more"] = "visa fler";
$a->strings["Embedded content"] = "Inbäddat innehåll";
$a->strings["Embedding disabled"] = "Inbäddning inaktiverat";
-$a->strings["No recipient provided."] = "Ingen mottagare angiven.";
-$a->strings["[no subject]"] = "[inget ämne]";
-$a->strings["Unable to determine sender."] = "Kunde inte avgöra vem som är avsändare.";
-$a->strings["Stored post could not be verified."] = "Den sparade posten kunde inte verifieras.";
+$a->strings["Logged out."] = "Utloggad.";
+$a->strings["Failed authentication"] = "Inloggning misslyckades";
+$a->strings["Login failed."] = "Inloggning misslyckades.";
+$a->strings["Image exceeds website size limit of %lu bytes"] = "Bild överskrider webbplatsens storleksbegränsning på %lu byte";
+$a->strings["Image file is empty."] = "Bildfil är tom.";
+$a->strings["Unable to process image"] = "Kunde inte bearbeta bild";
+$a->strings["Photo storage failed."] = "Fotolagring misslyckades.";
+$a->strings["Photo Albums"] = "Fotoalbum";
+$a->strings["Upload New Photos"] = "Ladda upp nya foton";
$a->strings[" and "] = " och ";
$a->strings["public profile"] = "offentlig profil";
$a->strings["%1\$s changed %2\$s to &ldquo;%3\$s&rdquo;"] = "%1\$s ändrade %2\$s till &quot;%3\$s&quot;";
$a->strings["Visit %1\$s's %2\$s"] = "Besök %1\$ss %2\$s";
$a->strings["%1\$s has an updated %2\$s, changing %3\$s."] = "%1\$s har en uppdaterad %2\$s (har ändrat %3\$s).";
-$a->strings["Visible to your default audience"] = "Kan ses av förinställda mottagare";
-$a->strings["Show"] = "Visa";
-$a->strings["Don't show"] = "Visa inte";
-$a->strings["Permissions"] = "Behörighet";
-$a->strings["Close"] = "Stäng";
$a->strings["Attachments:"] = "Bilagor:";
$a->strings["l F d, Y \\@ g:i A"] = "l j F Y \\k\\l. H.i";
$a->strings["Redmatrix event notification:"] = "Händelsenotifiering från Redmatrix:";
$a->strings["Starts:"] = "Börjar:";
$a->strings["Finishes:"] = "Slutar:";
$a->strings["Location:"] = "Plats:";
-$a->strings["Permission denied."] = "Behörighet saknas.";
-$a->strings["Item was not found."] = "Posten hittades inte.";
-$a->strings["No source file."] = "Ingen källfil.";
-$a->strings["Cannot locate file to replace"] = "Kan inte hitta fil att ersätta";
-$a->strings["Cannot locate file to revise/update"] = "Kan inte hitta fil att revidera/uppdatera";
-$a->strings["File exceeds size limit of %d"] = "Filen överskrider storleksbegränsningen %d";
-$a->strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = "Du har nått begränsningen %1$.0f megabyte utrymme för bilagor.";
-$a->strings["File upload failed. Possible system limit or action terminated."] = "Filuppladdning misslyckades. Möjlig systembegränsning eller avbruten åtgärd.";
-$a->strings["Stored file could not be verified. Upload failed."] = "Den lagrade filen kunde inte verifieras. Uppladdning misslyckad.";
-$a->strings["Path not available."] = "Sökväg inte tillgänglig.";
-$a->strings["Empty pathname"] = "Tom sökväg";
-$a->strings["duplicate filename or path"] = "filnamn eller sökväg finns redan";
-$a->strings["Path not found."] = "Sökväg hittas inte.";
-$a->strings["mkdir failed."] = "mkdir misslyckades.";
-$a->strings["database storage failed."] = "databaslagring misslyckades.";
-$a->strings["parent"] = "en nivå upp";
-$a->strings["Collection"] = "Samling";
-$a->strings["Principal"] = "Bas";
-$a->strings["Addressbook"] = "Adressbok";
-$a->strings["Calendar"] = "Kalender";
-$a->strings["Schedule Inbox"] = "Schemainkorg";
-$a->strings["Schedule Outbox"] = "Schemautkorg";
-$a->strings["%1\$s used"] = "%1\$s använt";
-$a->strings["%1\$s used of %2\$s (%3\$s&#37;)"] = "%1\$s använt av %2\$s (%3\$s&#37;)";
-$a->strings["Name"] = "Namn";
-$a->strings["Type"] = "Typ";
-$a->strings["Size"] = "Storlek";
-$a->strings["Last Modified"] = "Senast ändrad";
-$a->strings["Total"] = "Totalt";
-$a->strings["Create new folder"] = "Skapa ny mapp";
-$a->strings["Create"] = "Skapa";
-$a->strings["Upload file"] = "Ladda upp fil";
-$a->strings["Upload"] = "Ladda upp";
-$a->strings["%1\$s's bookmarks"] = "%1\$ss bokmärken";
-$a->strings["Logout"] = "Logga ut";
-$a->strings["End this session"] = "Avsluta sessionen";
-$a->strings["Home"] = "Hem";
-$a->strings["Your posts and conversations"] = "Dina inlägg och konversationer";
-$a->strings["Your profile page"] = "Din profilsida";
-$a->strings["Edit Profiles"] = "Redigera profiler";
-$a->strings["Manage/Edit profiles"] = "Hantera/redigera profiler";
-$a->strings["Edit Profile"] = "Redigera profil";
-$a->strings["Edit your profile"] = "Redigera din profil";
-$a->strings["Your photos"] = "Dina foton";
-$a->strings["Your files"] = "Dina filer";
-$a->strings["Chat"] = "Chatt";
-$a->strings["Your chatrooms"] = "Dina chattrum";
-$a->strings["Your bookmarks"] = "Dina bokmärken";
-$a->strings["Your webpages"] = "Dina webbsidor";
-$a->strings["Login"] = "Logga in";
-$a->strings["Sign in"] = "Logga in";
-$a->strings["%s - click to logout"] = "%s - klicka för att logga ut";
-$a->strings["Remote authentication"] = "Fjärrinloggning";
-$a->strings["Click to authenticate to your home hub"] = "Klicka för att autentisera mot din hemmahubb";
-$a->strings["Home Page"] = "Hemsida";
-$a->strings["Register"] = "Skapa konto";
-$a->strings["Create an account"] = "Skapa ett konto";
-$a->strings["Help"] = "Hjälp";
-$a->strings["Help and documentation"] = "Hjälp och dokumentation";
-$a->strings["Apps"] = "Appar";
-$a->strings["Applications, utilities, links, games"] = "Applikationer, verktyg, länkar, spel";
-$a->strings["Search"] = "Sök";
-$a->strings["Search site content"] = "Sök innehåll";
-$a->strings["Directory"] = "Katalog";
-$a->strings["Channel Directory"] = "Kanalkatalog";
-$a->strings["Matrix"] = "Matris";
-$a->strings["Your matrix"] = "Din matris";
-$a->strings["Mark all matrix notifications seen"] = "Märk alla matrisnotifieringar som lästa";
-$a->strings["Channel Home"] = "Kanalhem";
-$a->strings["Channel home"] = "Kanalhem";
-$a->strings["Mark all channel notifications seen"] = "Märk alla kanalnotifieringar som lästa";
-$a->strings["Connections"] = "Kontakter";
-$a->strings["Notices"] = "Meddelanden";
-$a->strings["Notifications"] = "Notifieringar";
-$a->strings["See all notifications"] = "Se alla notifieringar";
-$a->strings["Mark all system notifications seen"] = "Märk alla systemnotifieringar som lästa";
-$a->strings["Mail"] = "Privat meddelande";
-$a->strings["Private mail"] = "Privat meddelande";
-$a->strings["See all private messages"] = "Se alla privata meddelanden";
-$a->strings["Mark all private messages seen"] = "Märk alla privata meddelanden som lästa";
-$a->strings["Inbox"] = "Inkorg";
-$a->strings["Outbox"] = "Utkorg";
-$a->strings["New Message"] = "Nytt meddelande";
-$a->strings["Events"] = "Händelser";
-$a->strings["Event Calendar"] = "Kalender";
-$a->strings["See all events"] = "Se alla händelser";
-$a->strings["Mark all events seen"] = "Märk alla händelser som lästa";
-$a->strings["Channel Manager"] = "Kanalhanterare";
-$a->strings["Manage Your Channels"] = "Hantera dina kanaler";
-$a->strings["Settings"] = "Inställningar";
-$a->strings["Account/Channel Settings"] = "Konto-/kanalinställningar";
-$a->strings["Admin"] = "Administration";
-$a->strings["Site Setup and Configuration"] = "Serverinställning och -konfiguration";
-$a->strings["Please wait..."] = "Vänta...";
-$a->strings["view full size"] = "visa full storlek";
-$a->strings["Default"] = "Standard";
-$a->strings["Frequently"] = "Ofta";
-$a->strings["Hourly"] = "Varje timme";
-$a->strings["Twice daily"] = "Två gånger dagligen";
-$a->strings["Daily"] = "Dagligen";
-$a->strings["Weekly"] = "Varje vecka";
-$a->strings["Monthly"] = "Varje månad";
-$a->strings["Friendica"] = "Friendica";
-$a->strings["OStatus"] = "OStatus";
-$a->strings["RSS/Atom"] = "RSS/Atom";
-$a->strings["Email"] = "E-post";
-$a->strings["Diaspora"] = "Diaspora";
-$a->strings["Facebook"] = "Facebook";
-$a->strings["Zot!"] = "Zot!";
-$a->strings["LinkedIn"] = "LinkedIn";
-$a->strings["XMPP/IM"] = "XMPP/IM";
-$a->strings["MySpace"] = "MySpace";
-$a->strings["Unable to obtain identity information from database"] = "Kunde inte hämta från databasen";
-$a->strings["Empty name"] = "Tomt namn";
-$a->strings["Name too long"] = "För långt namn";
-$a->strings["No account identifier"] = "Ingen kontoidentifierare";
-$a->strings["Nickname is required."] = "Smeknamn måste anges.";
-$a->strings["Reserved nickname. Please choose another."] = "Reserverat smeknamn. Välj ett annat.";
-$a->strings["Nickname has unsupported characters or is already being used on this site."] = "Smeknamnet innehåller otillåtna tecken eller är redan upptaget på den här servern.";
-$a->strings["Unable to retrieve created identity"] = "Kunde inte hämta den skapade identiteten";
-$a->strings["Default Profile"] = "Standardprofil";
-$a->strings["Friends"] = "Vänner";
-$a->strings["Requested channel is not available."] = "Den begärda kanalen är inte tillgänglig";
-$a->strings["Requested profile is not available."] = "Begärd profil är inte tillgänglig.";
-$a->strings["Change profile photo"] = "Bytprofilfoto";
-$a->strings["Profiles"] = "Profiler";
-$a->strings["Manage/edit profiles"] = "Hantera/redigera profiler";
-$a->strings["Create New Profile"] = "Skapa ny profil";
-$a->strings["Profile Image"] = "Profilbild";
-$a->strings["visible to everybody"] = "synlig för alla";
-$a->strings["Edit visibility"] = "Redigera synlighet";
-$a->strings["Gender:"] = "Kön:";
-$a->strings["Status:"] = "Status:";
-$a->strings["Homepage:"] = "Hemsida:";
-$a->strings["Online Now"] = "Online nu";
-$a->strings["g A l F d"] = "l j F \\k\\l G";
-$a->strings["F d"] = "j F";
-$a->strings["[today]"] = "[i dag]";
-$a->strings["Birthday Reminders"] = "Födelsedagspåminnelser";
-$a->strings["Birthdays this week:"] = "Födelsedagar den här veckan:";
-$a->strings["[No description]"] = "[Ingen beskrivning]";
-$a->strings["Event Reminders"] = "Händelsepåminnelser";
-$a->strings["Events this week:"] = "Händelser den här veckan:";
-$a->strings["Profile"] = "Profil";
-$a->strings["Full Name:"] = "Fullständigt namn:";
-$a->strings["Like this channel"] = "Gilla den här kanalen";
-$a->strings["__ctx:noun__ Like"] = array(
- 0 => "gillar detta",
- 1 => "gillar detta",
-);
-$a->strings["j F, Y"] = "j F Y";
-$a->strings["j F"] = "j F";
-$a->strings["Birthday:"] = "Födelsedag:";
-$a->strings["Age:"] = "Ålder:";
-$a->strings["for %1\$d %2\$s"] = "i %1\$d %2\$s";
-$a->strings["Sexual Preference:"] = "Sexuell preferens:";
-$a->strings["Hometown:"] = "Hemort:";
-$a->strings["Tags:"] = "Taggar:";
-$a->strings["Political Views:"] = "Politisk åskådning:";
-$a->strings["Religion:"] = "Religion:";
-$a->strings["About:"] = "Om:";
-$a->strings["Hobbies/Interests:"] = "Fritidssysselsättning/intressen:";
-$a->strings["Likes:"] = "Gillar:";
-$a->strings["Dislikes:"] = "Ogillar:";
-$a->strings["Contact information and Social Networks:"] = "Kontaktinformation och sociala nätverk:";
-$a->strings["My other channels:"] = "Mina andra kanaler:";
-$a->strings["Musical interests:"] = "Musikintressen:";
-$a->strings["Books, literature:"] = "Böcker, litteratur:";
-$a->strings["Television:"] = "Tv:";
-$a->strings["Film/dance/culture/entertainment:"] = "Film/dans/kultur/underhållning:";
-$a->strings["Love/Romance:"] = "Kärlek/romantik:";
-$a->strings["Work/employment:"] = "Arbete/sysselsättning:";
-$a->strings["School/education:"] = "Skola/utbildning:";
-$a->strings["Like this thing"] = "Gilla den här saken";
-$a->strings["Image/photo"] = "Bild/foto";
-$a->strings["Encrypted content"] = "Krypterat innehåll";
-$a->strings["Install design element: "] = "Installera designelement: ";
-$a->strings["QR code"] = "QR-kod";
-$a->strings["%1\$s wrote the following %2\$s %3\$s"] = "%1\$s skrev följande %2\$s %3\$s";
-$a->strings["post"] = "post";
-$a->strings["$1 spoiler"] = "$1 spoiler";
-$a->strings["$1 wrote:"] = "$1 skrev:";
-$a->strings["Miscellaneous"] = "Övrigt";
-$a->strings["YYYY-MM-DD or MM-DD"] = "ÅÅÅÅ-MM-DD eller MM-DD";
-$a->strings["never"] = "aldrig";
-$a->strings["less than a second ago"] = "mindre än en sekund sedan";
-$a->strings["year"] = "år";
-$a->strings["years"] = "år";
-$a->strings["month"] = "månad";
-$a->strings["months"] = "månader";
-$a->strings["week"] = "vecka";
-$a->strings["weeks"] = "veckor";
-$a->strings["day"] = "dag";
-$a->strings["days"] = "dagar";
-$a->strings["hour"] = "timme";
-$a->strings["hours"] = "timmar";
-$a->strings["minute"] = "minut";
-$a->strings["minutes"] = "minuter";
-$a->strings["second"] = "sekund";
-$a->strings["seconds"] = "sekunder";
-$a->strings["%1\$d %2\$s ago"] = "%1\$d %2\$s sedan";
-$a->strings["%1\$s's birthday"] = "%1\$ss födelsedag";
-$a->strings["Happy Birthday %1\$s"] = "Grattis på födelsedagen %1\$s";
-$a->strings["Invalid data packet"] = "Ogiltigt datapaket";
-$a->strings["Unable to verify channel signature"] = "Kunde inte bekräfta kanalsignatur";
-$a->strings["Unable to verify site signature for %s"] = "Kunde inte bekräfta signatur för servern %s";
-$a->strings["Tags"] = "Taggar";
-$a->strings["Keywords"] = "Nyckelord";
-$a->strings["have"] = "har";
-$a->strings["has"] = "har";
-$a->strings["want"] = "vill ha";
-$a->strings["wants"] = "vill ha";
-$a->strings["like"] = "gilla";
-$a->strings["likes"] = "gillar";
-$a->strings["dislike"] = "ogilla";
-$a->strings["dislikes"] = "ogillar";
-$a->strings["Public Timeline"] = "Offentlig tidslinje";
-$a->strings["Directory Options"] = "Katalogalternativ";
-$a->strings["Alphabetic"] = "Alfabetisk";
-$a->strings["Reverse Alphabetic"] = "Omvänd alfabetisk";
-$a->strings["Newest to Oldest"] = "Nyast till äldst";
-$a->strings["Public Forums Only"] = "Endast offentliga forum";
-$a->strings["Enable Safe Search"] = "Aktivera säker sökning";
-$a->strings["Disable Safe Search"] = "Avaktivera säker sökning";
-$a->strings["Safe Mode"] = "Säkert läge";
-$a->strings["Red Matrix Notification"] = "Red Matrix-meddelande";
-$a->strings["redmatrix"] = "redmatrix";
-$a->strings["Thank You,"] = "Tack,";
-$a->strings["%s Administrator"] = "Administratören för %s";
-$a->strings["%s <!item_type!>"] = "%s <!item_type!>";
-$a->strings["[Red:Notify] New mail received at %s"] = "[Red:Meddelande] Nytt meddelande på %s";
-$a->strings["%1\$s, %2\$s sent you a new private message at %3\$s."] = "%1\$s, %2\$s skickade ett nytt privat meddelande till dig på %3\$s.";
-$a->strings["%1\$s sent you %2\$s."] = "%1\$s skickade %2\$s till dig.";
-$a->strings["a private message"] = "ett privat meddelande";
-$a->strings["Please visit %s to view and/or reply to your private messages."] = "Besök %s för att visa och/eller svara på dina privata meddelanden.";
-$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]a %4\$s[/zrl]"] = "%1\$s, %2\$s kommenterade [zrl=%3\$s]ett %4\$s[/zrl]";
-$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = "%1\$s, %2\$s kommenterade [zrl=%3\$s]%4\$ss %5\$s[/zrl]";
-$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]your %4\$s[/zrl]"] = "%1\$s, %2\$s kommenterade [zrl=%3\$s]ditt %4\$s[/zrl]";
-$a->strings["[Red:Notify] Comment to conversation #%1\$d by %2\$s"] = "[Red:Meddelande] Kommentar till konversation #%1\$d av %2\$s";
-$a->strings["%1\$s, %2\$s commented on an item/conversation you have been following."] = "%1\$s, %2\$s kommenterade en sak/konversation du har följt.";
-$a->strings["Please visit %s to view and/or reply to the conversation."] = "Besök %s för att visa och/eller svara på konversationen.";
-$a->strings["[Red:Notify] %s posted to your profile wall"] = "[Red:Meddelande] %s postade till din profilvägg";
-$a->strings["%1\$s, %2\$s posted to your profile wall at %3\$s"] = "%1\$s, %2\$s postade till din profilvägg på %3\$s";
-$a->strings["%1\$s, %2\$s posted to [zrl=%3\$s]your wall[/zrl]"] = "%1\$s, %2\$s postade till [zrl=%3\$s]din vägg[/zrl]";
-$a->strings["[Red:Notify] %s tagged you"] = "[Red:Meddelande] %s taggade dig";
-$a->strings["%1\$s, %2\$s tagged you at %3\$s"] = "%1\$s, %2\$s taggade dig på %3\$s";
-$a->strings["%1\$s, %2\$s [zrl=%3\$s]tagged you[/zrl]."] = "%1\$s, %2\$s [zrl=%3\$s]taggade dig[/zrl].";
-$a->strings["[Red:Notify] %1\$s poked you"] = "[Red:Meddelande] %1\$s puffade dig";
-$a->strings["%1\$s, %2\$s poked you at %3\$s"] = "%1\$s, %2\$s puffade dig på %3\$s";
-$a->strings["%1\$s, %2\$s [zrl=%2\$s]poked you[/zrl]."] = "%1\$s, %2\$s [zrl=%2\$s]puffade dig[/zrl].";
-$a->strings["[Red:Notify] %s tagged your post"] = "[Red:Meddelande] %s taggade ditt inlägg";
-$a->strings["%1\$s, %2\$s tagged your post at %3\$s"] = "%1\$s, %2\$s taggade ditt inlägg på %3\$s";
-$a->strings["%1\$s, %2\$s tagged [zrl=%3\$s]your post[/zrl]"] = "%1\$s, %2\$s taggade [zrl=%3\$s]ditt inlägg[/zrl]";
-$a->strings["[Red:Notify] Introduction received"] = "[Red:Meddelande] Presentation mottagen";
-$a->strings["%1\$s, you've received an new connection request from '%2\$s' at %3\$s"] = "%1\$s, du har fått en ny kontaktförfrågan från '%2\$s' på %3\$s";
-$a->strings["%1\$s, you've received [zrl=%2\$s]a new connection request[/zrl] from %3\$s."] = "%1\$s, du har fått [zrl=%2\$s]en ny kontaktförfrågan[/zrl] från %3\$s.";
-$a->strings["You may visit their profile at %s"] = "Du kan besöka deras profil på %s";
-$a->strings["Please visit %s to approve or reject the connection request."] = "Besök %s för att bevilja eller avslå kontaktförfrågan.";
-$a->strings["[Red:Notify] Friend suggestion received"] = "[Red:Meddelande] Vänförslag mottaget";
-$a->strings["%1\$s, you've received a friend suggestion from '%2\$s' at %3\$s"] = "%1\$s, du har fått ett vänförslag från '%2\$s' på %3\$s";
-$a->strings["%1\$s, you've received [zrl=%2\$s]a friend suggestion[/zrl] for %3\$s from %4\$s."] = "%1\$s, du har fått [zrl=%2\$s]ett vänförslag[/zrl] angående %3\$s från %4\$s.";
-$a->strings["Name:"] = "Namn:";
-$a->strings["Photo:"] = "Foto:";
-$a->strings["Please visit %s to approve or reject the suggestion."] = "Besök %s för att bevilja eller avslå förslaget.";
-$a->strings["[Red:Notify]"] = "[Red:Notifiering]";
-$a->strings["This event has been added to your calendar."] = "Händelsen har lagts till i din kalender.";
-$a->strings["A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = "En borttagen grupp med det här namnet återskapades. Befintliga rättigheter till saker <strong>kan</strong> gälla för den här gruppen och alla framtida medlemmar. Om det här inte är vad du avsåg, skapa i stället en annan grupp med ett annat namn.";
-$a->strings["Default privacy group for new contacts"] = "Förvald integritetsgrupp för nya kontakter";
-$a->strings["All Channels"] = "Alla kanaler";
-$a->strings["edit"] = "redigera";
-$a->strings["Collections"] = "Kretsar";
-$a->strings["Edit collection"] = "Redigera krets";
-$a->strings["Create a new collection"] = "Skapa en ny krets";
-$a->strings["Channels not in any collection"] = "Kanaler inte i någon krets";
-$a->strings["add"] = "lägg till";
$a->strings["General Features"] = "Allmänna funktioner";
$a->strings["Content Expiration"] = "Tidsbegränsat innehåll";
$a->strings["Remove posts/comments and/or private messages at a future time"] = "Ta bort inlägg/kommentarer och/eller privata meddelanden efter en tid";
@@ -486,8 +134,6 @@ $a->strings["Allows you to set restrictions and terms on those that connect with
$a->strings["Post Composition Features"] = "Skrivfunktioner";
$a->strings["Use Markdown"] = "Använd Markdown";
$a->strings["Allow use of \"Markdown\" to format posts"] = "Tillåt att \"Markdown\" används för att formatera inlägg";
-$a->strings["Post Preview"] = "Förhandsgranskning";
-$a->strings["Allow previewing posts and comments before publishing them"] = "Tillåt förhandsgranskning av inlägg och kommentarer innan de publiceras";
$a->strings["Channel Sources"] = "Kanalkällor";
$a->strings["Automatically import channel content from other channels or feeds"] = "Importera kanalinnehåll från andra kanaler eller flöden automatiskt";
$a->strings["Even More Encryption"] = "Ytterligare kryptering";
@@ -510,12 +156,11 @@ $a->strings["Filter stream activity by depth of relationships"] = "Filtrera str
$a->strings["Suggest Channels"] = "Föreslå kanaler";
$a->strings["Show channel suggestions"] = "Visa förslag på kanaler";
$a->strings["Post/Comment Tools"] = "Inläggs-/kommentarsverktyg";
-$a->strings["Edit Sent Posts"] = "Redigera sända inlägg";
-$a->strings["Edit and correct posts and comments after sending"] = "Redigera och korrigera inlägg och kommentarer efter att de skickats";
$a->strings["Tagging"] = "Taggning";
$a->strings["Ability to tag existing posts"] = "Möjlighet att tagga befintliga inlägg";
$a->strings["Post Categories"] = "Inläggskategorier";
$a->strings["Add categories to your posts"] = "Lägg till kategorier till dina inlägg";
+$a->strings["Saved Folders"] = "Sparade mappar";
$a->strings["Ability to file posts under folders"] = "Möjlighet att lägga inlägg i mappar";
$a->strings["Dislike Posts"] = "Ogilla inlägg";
$a->strings["Ability to dislike posts/comments"] = "Möjlighet att ogilla inlägg/kommentarer";
@@ -523,6 +168,60 @@ $a->strings["Star Posts"] = "Märk inlägg";
$a->strings["Ability to mark special posts with a star indicator"] = "Möjlighet att märka speciella inlägg med en stjärna";
$a->strings["Tag Cloud"] = "Taggmoln";
$a->strings["Provide a personal tag cloud on your channel page"] = "Tillhandahåll ett personligt taggmoln på din kanalsida";
+$a->strings["parent"] = "en nivå upp";
+$a->strings["Collection"] = "Samling";
+$a->strings["Principal"] = "Bas";
+$a->strings["Addressbook"] = "Adressbok";
+$a->strings["Calendar"] = "Kalender";
+$a->strings["Schedule Inbox"] = "Schemainkorg";
+$a->strings["Schedule Outbox"] = "Schemautkorg";
+$a->strings["Unknown"] = "Okända";
+$a->strings["%1\$s used"] = "%1\$s använt";
+$a->strings["%1\$s used of %2\$s (%3\$s&#37;)"] = "%1\$s använt av %2\$s (%3\$s&#37;)";
+$a->strings["Files"] = "Filer";
+$a->strings["Total"] = "Totalt";
+$a->strings["Name"] = "Namn";
+$a->strings["Type"] = "Typ";
+$a->strings["Size"] = "Storlek";
+$a->strings["Last Modified"] = "Senast ändrad";
+$a->strings["Delete"] = "Ta bort";
+$a->strings["Create new folder"] = "Skapa ny mapp";
+$a->strings["Create"] = "Skapa";
+$a->strings["Upload file"] = "Ladda upp fil";
+$a->strings["Upload"] = "Ladda upp";
+$a->strings["%1\$s's bookmarks"] = "%1\$ss bokmärken";
+$a->strings["Directory Options"] = "Katalogalternativ";
+$a->strings["Alphabetic"] = "Alfabetisk";
+$a->strings["Reverse Alphabetic"] = "Omvänd alfabetisk";
+$a->strings["Newest to Oldest"] = "Nyast till äldst";
+$a->strings["Oldest to Newest"] = "Äldst till nyast";
+$a->strings["Public Forums Only"] = "Endast offentliga forum";
+$a->strings["Sort"] = "Ordning";
+$a->strings["Enable Safe Search"] = "Aktivera säker sökning";
+$a->strings["Disable Safe Search"] = "Avaktivera säker sökning";
+$a->strings["Safe Mode"] = "Säkert läge";
+$a->strings["Default"] = "Standard";
+$a->strings["Frequently"] = "Ofta";
+$a->strings["Hourly"] = "Varje timme";
+$a->strings["Twice daily"] = "Två gånger dagligen";
+$a->strings["Daily"] = "Dagligen";
+$a->strings["Weekly"] = "Varje vecka";
+$a->strings["Monthly"] = "Varje månad";
+$a->strings["Friendica"] = "Friendica";
+$a->strings["OStatus"] = "OStatus";
+$a->strings["RSS/Atom"] = "RSS/Atom";
+$a->strings["Email"] = "E-post";
+$a->strings["Diaspora"] = "Diaspora";
+$a->strings["Facebook"] = "Facebook";
+$a->strings["Zot!"] = "Zot!";
+$a->strings["LinkedIn"] = "LinkedIn";
+$a->strings["XMPP/IM"] = "XMPP/IM";
+$a->strings["MySpace"] = "MySpace";
+$a->strings["Visible to your default audience"] = "Kan ses av förinställda mottagare";
+$a->strings["Show"] = "Visa";
+$a->strings["Don't show"] = "Visa inte";
+$a->strings["Permissions"] = "Behörighet";
+$a->strings["Close"] = "Stäng";
$a->strings["prev"] = "föregående";
$a->strings["first"] = "första";
$a->strings["last"] = "sista";
@@ -535,8 +234,10 @@ $a->strings["%d Connection"] = array(
1 => "%d kontakter",
);
$a->strings["View Connections"] = "Visa kontakter";
+$a->strings["Search"] = "Sök";
$a->strings["Save"] = "Spara";
$a->strings["poke"] = "puffa";
+$a->strings["poked"] = "puffade";
$a->strings["ping"] = "pinga";
$a->strings["pinged"] = "pingade";
$a->strings["prod"] = "stöt till";
@@ -597,12 +298,146 @@ $a->strings["Select a page layout: "] = "Välj en sidlayout: ";
$a->strings["default"] = "standard";
$a->strings["Page content type: "] = "Typ av sidinnehåll: ";
$a->strings["Select an alternate language"] = "Välj ett alternativt språk";
+$a->strings["photo"] = "foto";
+$a->strings["event"] = "händelse";
+$a->strings["status"] = "status";
+$a->strings["comment"] = "kommentar";
$a->strings["activity"] = "aktivitet";
$a->strings["Design"] = "Design";
$a->strings["Blocks"] = "Block";
$a->strings["Menus"] = "Menyer";
$a->strings["Layouts"] = "Layouter";
$a->strings["Pages"] = "Sidor";
+$a->strings["%d invitation available"] = array(
+ 0 => "%d inbjudan tillgänglig",
+ 1 => "%d inbjudningar tillgängliga",
+);
+$a->strings["Advanced"] = "Avancerat";
+$a->strings["Find Channels"] = "Hitta kanaler";
+$a->strings["Enter name or interest"] = "Ange namn eller intresse";
+$a->strings["Connect/Follow"] = "Ta kontakt/följ";
+$a->strings["Examples: Robert Morgenstein, Fishing"] = "Exempel: Robert Morgenstein, Fiske";
+$a->strings["Find"] = "Sök";
+$a->strings["Channel Suggestions"] = "Kanalförslag";
+$a->strings["Random Profile"] = "Slumpvald profil";
+$a->strings["Invite Friends"] = "Bjud in vänner";
+$a->strings["Advanced example: name=fred and country=iceland"] = "Avancerat exempel: name=fred and country=iceland";
+$a->strings["Everything"] = "Allt";
+$a->strings["%d connection in common"] = array(
+ 0 => "%d gemensam kontakt",
+ 1 => "%d gemensamma kontakter",
+);
+$a->strings["show more"] = "visa fler";
+$a->strings["Red Matrix Notification"] = "Red Matrix-meddelande";
+$a->strings["redmatrix"] = "redmatrix";
+$a->strings["Thank You,"] = "Tack,";
+$a->strings["%s Administrator"] = "Administratören för %s";
+$a->strings["%s <!item_type!>"] = "%s <!item_type!>";
+$a->strings["[Red:Notify] New mail received at %s"] = "[Red:Meddelande] Nytt meddelande på %s";
+$a->strings["%1\$s, %2\$s sent you a new private message at %3\$s."] = "%1\$s, %2\$s skickade ett nytt privat meddelande till dig på %3\$s.";
+$a->strings["%1\$s sent you %2\$s."] = "%1\$s skickade %2\$s till dig.";
+$a->strings["a private message"] = "ett privat meddelande";
+$a->strings["Please visit %s to view and/or reply to your private messages."] = "Besök %s för att visa och/eller svara på dina privata meddelanden.";
+$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]a %4\$s[/zrl]"] = "%1\$s, %2\$s kommenterade [zrl=%3\$s]ett %4\$s[/zrl]";
+$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = "%1\$s, %2\$s kommenterade [zrl=%3\$s]%4\$ss %5\$s[/zrl]";
+$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]your %4\$s[/zrl]"] = "%1\$s, %2\$s kommenterade [zrl=%3\$s]ditt %4\$s[/zrl]";
+$a->strings["[Red:Notify] Comment to conversation #%1\$d by %2\$s"] = "[Red:Meddelande] Kommentar till konversation #%1\$d av %2\$s";
+$a->strings["%1\$s, %2\$s commented on an item/conversation you have been following."] = "%1\$s, %2\$s kommenterade en sak/konversation du har följt.";
+$a->strings["Please visit %s to view and/or reply to the conversation."] = "Besök %s för att visa och/eller svara på konversationen.";
+$a->strings["[Red:Notify] %s posted to your profile wall"] = "[Red:Meddelande] %s postade till din profilvägg";
+$a->strings["%1\$s, %2\$s posted to your profile wall at %3\$s"] = "%1\$s, %2\$s postade till din profilvägg på %3\$s";
+$a->strings["%1\$s, %2\$s posted to [zrl=%3\$s]your wall[/zrl]"] = "%1\$s, %2\$s postade till [zrl=%3\$s]din vägg[/zrl]";
+$a->strings["[Red:Notify] %s tagged you"] = "[Red:Meddelande] %s taggade dig";
+$a->strings["%1\$s, %2\$s tagged you at %3\$s"] = "%1\$s, %2\$s taggade dig på %3\$s";
+$a->strings["%1\$s, %2\$s [zrl=%3\$s]tagged you[/zrl]."] = "%1\$s, %2\$s [zrl=%3\$s]taggade dig[/zrl].";
+$a->strings["[Red:Notify] %1\$s poked you"] = "[Red:Meddelande] %1\$s puffade dig";
+$a->strings["%1\$s, %2\$s poked you at %3\$s"] = "%1\$s, %2\$s puffade dig på %3\$s";
+$a->strings["%1\$s, %2\$s [zrl=%2\$s]poked you[/zrl]."] = "%1\$s, %2\$s [zrl=%2\$s]puffade dig[/zrl].";
+$a->strings["[Red:Notify] %s tagged your post"] = "[Red:Meddelande] %s taggade ditt inlägg";
+$a->strings["%1\$s, %2\$s tagged your post at %3\$s"] = "%1\$s, %2\$s taggade ditt inlägg på %3\$s";
+$a->strings["%1\$s, %2\$s tagged [zrl=%3\$s]your post[/zrl]"] = "%1\$s, %2\$s taggade [zrl=%3\$s]ditt inlägg[/zrl]";
+$a->strings["[Red:Notify] Introduction received"] = "[Red:Meddelande] Presentation mottagen";
+$a->strings["%1\$s, you've received an new connection request from '%2\$s' at %3\$s"] = "%1\$s, du har fått en ny kontaktförfrågan från '%2\$s' på %3\$s";
+$a->strings["%1\$s, you've received [zrl=%2\$s]a new connection request[/zrl] from %3\$s."] = "%1\$s, du har fått [zrl=%2\$s]en ny kontaktförfrågan[/zrl] från %3\$s.";
+$a->strings["You may visit their profile at %s"] = "Du kan besöka deras profil på %s";
+$a->strings["Please visit %s to approve or reject the connection request."] = "Besök %s för att bevilja eller avslå kontaktförfrågan.";
+$a->strings["[Red:Notify] Friend suggestion received"] = "[Red:Meddelande] Vänförslag mottaget";
+$a->strings["%1\$s, you've received a friend suggestion from '%2\$s' at %3\$s"] = "%1\$s, du har fått ett vänförslag från '%2\$s' på %3\$s";
+$a->strings["%1\$s, you've received [zrl=%2\$s]a friend suggestion[/zrl] for %3\$s from %4\$s."] = "%1\$s, du har fått [zrl=%2\$s]ett vänförslag[/zrl] angående %3\$s från %4\$s.";
+$a->strings["Name:"] = "Namn:";
+$a->strings["Photo:"] = "Foto:";
+$a->strings["Please visit %s to approve or reject the suggestion."] = "Besök %s för att bevilja eller avslå förslaget.";
+$a->strings["[Red:Notify]"] = "[Red:Notifiering]";
+$a->strings["This event has been added to your calendar."] = "Händelsen har lagts till i din kalender.";
+$a->strings["A deleted group with this name was revived. Existing item permissions <strong>may</strong> apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = "En borttagen grupp med det här namnet återskapades. Befintliga rättigheter till saker <strong>kan</strong> gälla för den här gruppen och alla framtida medlemmar. Om det här inte är vad du avsåg, skapa i stället en annan grupp med ett annat namn.";
+$a->strings["Default privacy group for new contacts"] = "Förvald integritetsgrupp för nya kontakter";
+$a->strings["All Channels"] = "Alla kanaler";
+$a->strings["edit"] = "redigera";
+$a->strings["Collections"] = "Kretsar";
+$a->strings["Edit collection"] = "Redigera krets";
+$a->strings["Create a new collection"] = "Skapa en ny krets";
+$a->strings["Channels not in any collection"] = "Kanaler inte i någon krets";
+$a->strings["add"] = "lägg till";
+$a->strings["Unable to obtain identity information from database"] = "Kunde inte hämta från databasen";
+$a->strings["Empty name"] = "Tomt namn";
+$a->strings["Name too long"] = "För långt namn";
+$a->strings["No account identifier"] = "Ingen kontoidentifierare";
+$a->strings["Nickname is required."] = "Smeknamn måste anges.";
+$a->strings["Reserved nickname. Please choose another."] = "Reserverat smeknamn. Välj ett annat.";
+$a->strings["Nickname has unsupported characters or is already being used on this site."] = "Smeknamnet innehåller otillåtna tecken eller är redan upptaget på den här servern.";
+$a->strings["Unable to retrieve created identity"] = "Kunde inte hämta den skapade identiteten";
+$a->strings["Default Profile"] = "Standardprofil";
+$a->strings["Friends"] = "Vänner";
+$a->strings["Requested channel is not available."] = "Den begärda kanalen är inte tillgänglig";
+$a->strings["Requested profile is not available."] = "Begärd profil är inte tillgänglig.";
+$a->strings["Connect"] = "Ta kontakt";
+$a->strings["Change profile photo"] = "Bytprofilfoto";
+$a->strings["Profiles"] = "Profiler";
+$a->strings["Manage/edit profiles"] = "Hantera/redigera profiler";
+$a->strings["Create New Profile"] = "Skapa ny profil";
+$a->strings["Edit Profile"] = "Redigera profil";
+$a->strings["Profile Image"] = "Profilbild";
+$a->strings["visible to everybody"] = "synlig för alla";
+$a->strings["Edit visibility"] = "Redigera synlighet";
+$a->strings["Gender:"] = "Kön:";
+$a->strings["Status:"] = "Status:";
+$a->strings["Homepage:"] = "Hemsida:";
+$a->strings["Online Now"] = "Online nu";
+$a->strings["g A l F d"] = "l j F \\k\\l G";
+$a->strings["F d"] = "j F";
+$a->strings["[today]"] = "[i dag]";
+$a->strings["Birthday Reminders"] = "Födelsedagspåminnelser";
+$a->strings["Birthdays this week:"] = "Födelsedagar den här veckan:";
+$a->strings["[No description]"] = "[Ingen beskrivning]";
+$a->strings["Event Reminders"] = "Händelsepåminnelser";
+$a->strings["Events this week:"] = "Händelser den här veckan:";
+$a->strings["Profile"] = "Profil";
+$a->strings["Full Name:"] = "Fullständigt namn:";
+$a->strings["Like this channel"] = "Gilla den här kanalen";
+$a->strings["j F, Y"] = "j F Y";
+$a->strings["j F"] = "j F";
+$a->strings["Birthday:"] = "Födelsedag:";
+$a->strings["Age:"] = "Ålder:";
+$a->strings["for %1\$d %2\$s"] = "i %1\$d %2\$s";
+$a->strings["Sexual Preference:"] = "Sexuell preferens:";
+$a->strings["Hometown:"] = "Hemort:";
+$a->strings["Tags:"] = "Taggar:";
+$a->strings["Political Views:"] = "Politisk åskådning:";
+$a->strings["Religion:"] = "Religion:";
+$a->strings["About:"] = "Om:";
+$a->strings["Hobbies/Interests:"] = "Fritidssysselsättning/intressen:";
+$a->strings["Likes:"] = "Gillar:";
+$a->strings["Dislikes:"] = "Ogillar:";
+$a->strings["Contact information and Social Networks:"] = "Kontaktinformation och sociala nätverk:";
+$a->strings["My other channels:"] = "Mina andra kanaler:";
+$a->strings["Musical interests:"] = "Musikintressen:";
+$a->strings["Books, literature:"] = "Böcker, litteratur:";
+$a->strings["Television:"] = "Tv:";
+$a->strings["Film/dance/culture/entertainment:"] = "Film/dans/kultur/underhållning:";
+$a->strings["Love/Romance:"] = "Kärlek/romantik:";
+$a->strings["Work/employment:"] = "Arbete/sysselsättning:";
+$a->strings["School/education:"] = "Skola/utbildning:";
+$a->strings["Like this thing"] = "Gilla den här saken";
$a->strings["Not a valid email address"] = "Inte en giltig e-postadress";
$a->strings["Your email domain is not among those allowed on this site"] = "Din e-postdomän är inte bland de som tillåts på den här servern";
$a->strings["Your email address is already registered at this site."] = "Din e-postadress är redan registrerad på den här servern.";
@@ -621,61 +456,150 @@ $a->strings["Account verified. Please login."] = "Konto bekräftat. Du kan nu lo
$a->strings["Click here to upgrade."] = "Klicka här för att uppgradera.";
$a->strings["This action exceeds the limits set by your subscription plan."] = "Den här funktionen går utanför vad som anges i ditt avtal.";
$a->strings["This action is not available under your subscription plan."] = "Den här funktionen är inte tillgänglig med ditt avtal.";
-$a->strings["Can view my normal stream and posts"] = "Kan se mina normala strömmar och inlägg";
-$a->strings["Can view my default channel profile"] = "Kan se min standardkanalprofil";
-$a->strings["Can view my photo albums"] = "Kan se mina fotoalbum";
-$a->strings["Can view my connections"] = "Kan se mina kontakter";
-$a->strings["Can view my file storage"] = "Kan se mitt filutrymme";
-$a->strings["Can view my webpages"] = "Kan se mina webbsidor";
-$a->strings["Can send me their channel stream and posts"] = "Kan skicka sina kanalströmmar och inlägg till mig";
-$a->strings["Can post on my channel page (\"wall\")"] = "Kan posta inlägg på min kanalsida (\"vägg\")";
-$a->strings["Can comment on or like my posts"] = "Kan kommentera eller gilla mina inlägg";
-$a->strings["Can send me private mail messages"] = "Kan skicka privata meddelanden till mig";
-$a->strings["Can post photos to my photo albums"] = "Kan lägga till foton i mitt fotoalbum";
-$a->strings["Can like/dislike stuff"] = "Kan gilla/ogilla saker";
-$a->strings["Profiles and things other than posts/comments"] = "Profiler och annat än inlägg/kommentarer";
-$a->strings["Can forward to all my channel contacts via post @mentions"] = "Kan vidarebefordra till alla mina kanalkontakter genom @omnämnanden";
-$a->strings["Advanced - useful for creating group forum channels"] = "Avancerat - användbart för att skapa kanaler för gruppforum";
-$a->strings["Can chat with me (when available)"] = "Kan chatta med mig (när tillgänglig)";
-$a->strings["Can write to my file storage"] = "Har skrivrättigheter i mitt filutrymme";
-$a->strings["Can edit my webpages"] = "Kan redigera mina webbsidor";
-$a->strings["Can source my public posts in derived channels"] = "Kan använda mina offentliga inlägg i kanaler nedströms";
-$a->strings["Somewhat advanced - very useful in open communities"] = "Ganska avancerat - väldigt användbart i öppna gemenskaper";
-$a->strings["Can administer my channel resources"] = "Kan administrera mina kanalresurser";
-$a->strings["Extremely advanced. Leave this alone unless you know what you are doing"] = "Extremt avancerat. Låt detta vara om du inte vet vad du gör";
-$a->strings["Social Networking"] = "Socialt nätverkande";
-$a->strings["Mostly Public"] = "Mestadels offentligt";
-$a->strings["Restricted"] = "Begränsat";
-$a->strings["Private"] = "Privat";
-$a->strings["Community Forum"] = "Gemenskapsforum";
-$a->strings["Feed Republish"] = "Vidarepublicering av flöde";
-$a->strings["Special Purpose"] = "Särskilt syfte";
-$a->strings["Celebrity/Soapbox"] = "Kändis/talarstol";
-$a->strings["Group Repository"] = "Gruppförråd";
-$a->strings["Other"] = "Annat";
-$a->strings["Custom/Expert Mode"] = "Anpassat/expertläge";
-$a->strings["Image exceeds website size limit of %lu bytes"] = "Bild överskrider webbplatsens storleksbegränsning på %lu byte";
-$a->strings["Image file is empty."] = "Bildfil är tom.";
-$a->strings["Unable to process image"] = "Kunde inte bearbeta bild";
-$a->strings["Photo storage failed."] = "Fotolagring misslyckades.";
-$a->strings["Upload New Photos"] = "Ladda upp nya foton";
-$a->strings["Permission denied"] = "Behörighet saknas";
-$a->strings["(Unknown)"] = "(Okänt)";
-$a->strings["Visible to anybody on the internet."] = "Kan ses av vem som helst på Internet.";
-$a->strings["Visible to you only."] = "Kan bara ses av dig.";
-$a->strings["Visible to anybody in this network."] = "Kan ses av alla på det här nätverket.";
-$a->strings["Visible to anybody authenticated."] = "Kan ses av alla inloggade.";
-$a->strings["Visible to anybody on %s."] = "Kan ses av alla på %s.";
-$a->strings["Visible to all connections."] = "Kan ses av alla kontakter.";
-$a->strings["Visible to approved connections."] = "Kan ses av godkända kontakter.";
-$a->strings["Visible to specific connections."] = "Kan ses av valda kontakter.";
-$a->strings["Item not found."] = "Posten hittades inte.";
-$a->strings["Collection not found."] = "Kretsen hittades inte.";
-$a->strings["Collection is empty."] = "Kretsen är tom.";
-$a->strings["Collection: %s"] = "Krets: %s";
-$a->strings["Connection: %s"] = "Kontakt: %s";
-$a->strings["Connection not found."] = "Kontakten hittades inte.";
-$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "Formulärets kontrollkod var inte korrekt. Antagligen beror det på att formuläret har varit öppet för länge (> 3 timmar) innan det skickades.";
+$a->strings["Channel is blocked on this site."] = "Kanalen är blockerad på den här servern.";
+$a->strings["Channel location missing."] = "Kanalplats saknas.";
+$a->strings["Response from remote channel was incomplete."] = "Svar från den andra kanalen var ofullständigt.";
+$a->strings["Channel was deleted and no longer exists."] = "Kanalen har tagits bort och finns inte längre.";
+$a->strings["Protocol disabled."] = "Protokoll inaktiverat.";
+$a->strings["Channel discovery failed."] = "Kanalsökning misslyckades.";
+$a->strings["local account not found."] = "hittade inte lokalt konto.";
+$a->strings["Cannot connect to yourself."] = "Du kan inte kontakta dig själv.";
+$a->strings["Public Timeline"] = "Offentlig tidslinje";
+$a->strings["Item was not found."] = "Posten hittades inte.";
+$a->strings["No source file."] = "Ingen källfil.";
+$a->strings["Cannot locate file to replace"] = "Kan inte hitta fil att ersätta";
+$a->strings["Cannot locate file to revise/update"] = "Kan inte hitta fil att revidera/uppdatera";
+$a->strings["File exceeds size limit of %d"] = "Filen överskrider storleksbegränsningen %d";
+$a->strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = "Du har nått begränsningen %1$.0f megabyte utrymme för bilagor.";
+$a->strings["File upload failed. Possible system limit or action terminated."] = "Filuppladdning misslyckades. Möjlig systembegränsning eller avbruten åtgärd.";
+$a->strings["Stored file could not be verified. Upload failed."] = "Den lagrade filen kunde inte verifieras. Uppladdning misslyckad.";
+$a->strings["Path not available."] = "Sökväg inte tillgänglig.";
+$a->strings["Empty pathname"] = "Tom sökväg";
+$a->strings["duplicate filename or path"] = "filnamn eller sökväg finns redan";
+$a->strings["Path not found."] = "Sökväg hittas inte.";
+$a->strings["mkdir failed."] = "mkdir misslyckades.";
+$a->strings["database storage failed."] = "databaslagring misslyckades.";
+$a->strings["Missing room name"] = "Rumsnamn saknas";
+$a->strings["Duplicate room name"] = "Rumsnamnet finns redan";
+$a->strings["Invalid room specifier."] = "Ogiltig rumsbeskrivning.";
+$a->strings["Room not found."] = "Rummet hittades inte.";
+$a->strings["Room is full"] = "Rummet är fullt";
+$a->strings["Image/photo"] = "Bild/foto";
+$a->strings["Encrypted content"] = "Krypterat innehåll";
+$a->strings["Install design element: "] = "Installera designelement: ";
+$a->strings["QR code"] = "QR-kod";
+$a->strings["%1\$s wrote the following %2\$s %3\$s"] = "%1\$s skrev följande %2\$s %3\$s";
+$a->strings["post"] = "post";
+$a->strings["$1 spoiler"] = "$1 spoiler";
+$a->strings["$1 wrote:"] = "$1 skrev:";
+$a->strings["channel"] = "kanal";
+$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s gillar %2\$ss %3\$s";
+$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s gillar inte %2\$ss %3\$s";
+$a->strings["%1\$s is now connected with %2\$s"] = "%1\$s har nu kontakt med %2\$s";
+$a->strings["%1\$s poked %2\$s"] = "%1\$s puffade %2\$s";
+$a->strings["__ctx:mood__ %1\$s is %2\$s"] = "%1\$s är %2\$s";
+$a->strings["Select"] = "Välj";
+$a->strings["Private Message"] = "Privat meddelande";
+$a->strings["Message signature validated"] = "Meddelandesignatur bekräftad";
+$a->strings["Message signature incorrect"] = "Meddelandesignatur felaktig";
+$a->strings["View %s's profile @ %s"] = "Visa %ss profil på %s";
+$a->strings["Categories:"] = "Kategorier:";
+$a->strings["Filed under:"] = "Postat under:";
+$a->strings[" from %s"] = "från %s";
+$a->strings["last edited: %s"] = "senast redigerat: %s";
+$a->strings["Expires: %s"] = "Upphör: %s";
+$a->strings["View in context"] = "Visa sammanhang";
+$a->strings["Please wait"] = "Vänta";
+$a->strings["remove"] = "ta bort";
+$a->strings["Loading..."] = "Laddar...";
+$a->strings["Delete Selected Items"] = "Ta bort valda poster";
+$a->strings["View Source"] = "Visa källa";
+$a->strings["Follow Thread"] = "Följ tråd";
+$a->strings["View Status"] = "Visa status";
+$a->strings["View Profile"] = "Visa profil";
+$a->strings["View Photos"] = "Visa foton";
+$a->strings["Matrix Activity"] = "Matrisaktivitet";
+$a->strings["Edit Contact"] = "Redigera kontakt";
+$a->strings["Send PM"] = "Skicka meddelande";
+$a->strings["Poke"] = "Puffa";
+$a->strings["%s likes this."] = "%s gillar det här.";
+$a->strings["%s doesn't like this."] = "%s gillar inte det här.";
+$a->strings["<span %1\$s>%2\$d people</span> like this."] = array(
+ 0 => "<span %1\$s>%2\$d person</span> gillar det här.",
+ 1 => "<span %1\$s>%2\$d personer</span> gillar det här.",
+);
+$a->strings["<span %1\$s>%2\$d people</span> don't like this."] = array(
+ 0 => "<span %1\$s>%2\$d person</span> gillar inte det här.",
+ 1 => "<span %1\$s>%2\$d personer</span> gillar inte det här.",
+);
+$a->strings["and"] = "och";
+$a->strings[", and %d other people"] = array(
+ 0 => ", och %d annan person",
+ 1 => ", och %d andra personer",
+);
+$a->strings["%s like this."] = "%s gillar det här.";
+$a->strings["%s don't like this."] = "%s gillar inte det här.";
+$a->strings["Visible to <strong>everybody</strong>"] = "Kan ses av <strong>alla</strong>";
+$a->strings["Please enter a link URL:"] = "Ange en länkadress:";
+$a->strings["Please enter a video link/URL:"] = "Ange en videolänkadress:";
+$a->strings["Please enter an audio link/URL:"] = "Ange en ljudlänkadress";
+$a->strings["Tag term:"] = "Tagguttryck";
+$a->strings["Save to Folder:"] = "Spara i mapp:";
+$a->strings["Where are you right now?"] = "Var är du just nu?";
+$a->strings["Expires YYYY-MM-DD HH:MM"] = "Upphör YYYY-MM-DD HH:MM";
+$a->strings["Share"] = "Dela";
+$a->strings["Page link title"] = "Titel på sidlänk";
+$a->strings["Post as"] = "Posta som";
+$a->strings["Upload photo"] = "Ladda upp foto";
+$a->strings["upload photo"] = "ladda upp foto";
+$a->strings["Attach file"] = "Bifoga fil";
+$a->strings["attach file"] = "bifoga fil";
+$a->strings["Insert web link"] = "Infoga webblänk";
+$a->strings["web link"] = "webblänk";
+$a->strings["Insert video link"] = "Infoga videolänk";
+$a->strings["video link"] = "videolänk";
+$a->strings["Insert audio link"] = "Infoga ljudlänk";
+$a->strings["audio link"] = "ljudlänk";
+$a->strings["Set your location"] = "Ange din plats";
+$a->strings["set location"] = "ange plats";
+$a->strings["Clear browser location"] = "Rensa webbläsarplats";
+$a->strings["clear location"] = "rensa plats";
+$a->strings["Title (optional)"] = "Titel (frivilligt)";
+$a->strings["Categories (optional, comma-separated list)"] = "Kategorier (frivilligt, kommaseparerad lista)";
+$a->strings["Permission settings"] = "Behörighetsinställningar";
+$a->strings["permissions"] = "behörighet";
+$a->strings["Public post"] = "Offentligt inlägg";
+$a->strings["Example: bob@example.com, mary@example.com"] = "Exempel: bob@example.com, mary@example.com";
+$a->strings["Set expiration date"] = "Ange utgångsdatum";
+$a->strings["Encrypt text"] = "Kryptera text";
+$a->strings["OK"] = "OK";
+$a->strings["Cancel"] = "Avbryt";
+$a->strings["Discover"] = "Upptäck";
+$a->strings["Imported public streams"] = "Importerade offentliga strömmar";
+$a->strings["Commented Order"] = "Kommentarsordning";
+$a->strings["Sort by Comment Date"] = "Ordna efter kommentarsdatum";
+$a->strings["Posted Order"] = "Inläggsordning";
+$a->strings["Sort by Post Date"] = "Ordna efter när inlägget skrevs";
+$a->strings["Personal"] = "Personligt";
+$a->strings["Posts that mention or involve you"] = "Inlägg som nämner eller berör dig";
+$a->strings["New"] = "Nytt";
+$a->strings["Activity Stream - by date"] = "Aktivitetsström - efter datum";
+$a->strings["Starred"] = "Märkt";
+$a->strings["Favourite Posts"] = "Favoritinlägg";
+$a->strings["Spam"] = "Skräp";
+$a->strings["Posts flagged as SPAM"] = "Inlägg markerade som SKRÄP";
+$a->strings["Channel"] = "Kanal";
+$a->strings["Status Messages and Posts"] = "Statusmeddelanden och inlägg";
+$a->strings["About"] = "Om";
+$a->strings["Profile Details"] = "Profildetaljer";
+$a->strings["Photos"] = "Foton";
+$a->strings["Files and Storage"] = "Filer och lagring";
+$a->strings["Chatrooms"] = "Chattrum";
+$a->strings["Bookmarks"] = "Bokmärken";
+$a->strings["Saved Bookmarks"] = "Sparade bokmärken";
+$a->strings["Webpages"] = "Webbsidor";
+$a->strings["Manage Webpages"] = "Hantera webbsidor";
+$a->strings["Apps"] = "Appar";
$a->strings["System"] = "System";
$a->strings["Create Personal App"] = "Skapa personlig app";
$a->strings["Edit Personal App"] = "Redigera personlig app";
@@ -703,21 +627,108 @@ $a->strings["Feature settings"] = "Funktionsinställningar";
$a->strings["Display settings"] = "Utseende";
$a->strings["Connected apps"] = "Anslutna appar";
$a->strings["Export channel"] = "Exportera kanal";
-$a->strings["Export content"] = "Exportera innehåll";
$a->strings["Connection Default Permissions"] = "Standardbehörighet för kontakt";
$a->strings["Premium Channel Settings"] = "Inställningar för premiumkanal";
+$a->strings["Settings"] = "Inställningar";
$a->strings["Messages"] = "Meddelanden";
$a->strings["Check Mail"] = "Hämta meddelanden";
+$a->strings["New Message"] = "Nytt meddelande";
$a->strings["Chat Rooms"] = "Chattrum";
$a->strings["Bookmarked Chatrooms"] = "Bokmärkta chattrum";
$a->strings["Suggested Chatrooms"] = "Föreslagna chattrum";
$a->strings["photo/image"] = "foto/bild";
+$a->strings["Invalid data packet"] = "Ogiltigt datapaket";
+$a->strings["Unable to verify channel signature"] = "Kunde inte bekräfta kanalsignatur";
+$a->strings["Unable to verify site signature for %s"] = "Kunde inte bekräfta signatur för servern %s";
+$a->strings["Save to Folder"] = "Spara i mapp";
+$a->strings["View all"] = "Visa alla";
+$a->strings["__ctx:noun__ Dislike"] = array(
+ 0 => "ogillar detta",
+ 1 => "ogillar detta",
+);
+$a->strings["Add Star"] = "Märk";
+$a->strings["Remove Star"] = "Ta bort märkning";
+$a->strings["Toggle Star Status"] = "Växla märkning";
+$a->strings["starred"] = "märkt";
+$a->strings["Add Tag"] = "Lägg till en tagg";
+$a->strings["I like this (toggle)"] = "Jag gillar det här (växla)";
+$a->strings["I don't like this (toggle)"] = "Jag gillar inte det här (växla)";
+$a->strings["Share This"] = "Dela det här";
+$a->strings["share"] = "dela";
+$a->strings["%d comment"] = array(
+ 0 => "%d kommentar",
+ 1 => "%d kommentarer",
+);
+$a->strings["View %s's profile - %s"] = "Visa %ss profil - %s";
+$a->strings["to"] = "till";
+$a->strings["via"] = "via";
+$a->strings["Wall-to-Wall"] = "Vägg-till-vägg";
+$a->strings["via Wall-To-Wall:"] = "via vägg-till-vägg";
+$a->strings["Save Bookmarks"] = "Spara bokmärken";
+$a->strings["Add to Calendar"] = "Lägg till kalendern";
+$a->strings["Mark all seen"] = "Märk alla som lästa";
+$a->strings["__ctx:noun__ Likes"] = "gillar detta";
+$a->strings["__ctx:noun__ Dislikes"] = "ogillar detta";
+$a->strings["[+] show all"] = "[+] visa alla";
+$a->strings["This is you"] = "Det här är du";
+$a->strings["Comment"] = "Kommentera";
+$a->strings["Submit"] = "Skicka";
+$a->strings["Bold"] = "Fet";
+$a->strings["Italic"] = "Kursiv";
+$a->strings["Underline"] = "Understruken";
+$a->strings["Quote"] = "Citat";
+$a->strings["Code"] = "Kod";
+$a->strings["Image"] = "Bild";
+$a->strings["Link"] = "Länk";
+$a->strings["Video"] = "Video";
+$a->strings["Miscellaneous"] = "Övrigt";
+$a->strings["YYYY-MM-DD or MM-DD"] = "ÅÅÅÅ-MM-DD eller MM-DD";
+$a->strings["never"] = "aldrig";
+$a->strings["less than a second ago"] = "mindre än en sekund sedan";
+$a->strings["year"] = "år";
+$a->strings["years"] = "år";
+$a->strings["month"] = "månad";
+$a->strings["months"] = "månader";
+$a->strings["week"] = "vecka";
+$a->strings["weeks"] = "veckor";
+$a->strings["day"] = "dag";
+$a->strings["days"] = "dagar";
+$a->strings["hour"] = "timme";
+$a->strings["hours"] = "timmar";
+$a->strings["minute"] = "minut";
+$a->strings["minutes"] = "minuter";
+$a->strings["second"] = "sekund";
+$a->strings["seconds"] = "sekunder";
+$a->strings["%1\$d %2\$s ago"] = "%1\$d %2\$s sedan";
+$a->strings["%1\$s's birthday"] = "%1\$ss födelsedag";
+$a->strings["Happy Birthday %1\$s"] = "Grattis på födelsedagen %1\$s";
+$a->strings["Site Admin"] = "Serveradministrator";
+$a->strings["Address Book"] = "Adressbok";
+$a->strings["Login"] = "Logga in";
+$a->strings["Channel Manager"] = "Kanalhanterare";
+$a->strings["Matrix"] = "Matris";
+$a->strings["Channel Home"] = "Kanalhem";
+$a->strings["Events"] = "Händelser";
+$a->strings["Directory"] = "Katalog";
+$a->strings["Help"] = "Hjälp";
+$a->strings["Mail"] = "Privat meddelande";
+$a->strings["Mood"] = "Sinnesstämning";
+$a->strings["Chat"] = "Chatt";
+$a->strings["Probe"] = "Sond";
+$a->strings["Suggest"] = "Föreslå";
+$a->strings["Random Channel"] = "Slumpvald kanal";
+$a->strings["Invite"] = "Bjud in";
+$a->strings["Features"] = "Funktioner";
+$a->strings["Language"] = "Språk";
+$a->strings["Post"] = "Inlägg";
+$a->strings["Profile Photo"] = "Profilfoto";
+$a->strings["Update"] = "Uppdatera";
+$a->strings["Install"] = "Installera";
+$a->strings["Purchase"] = "Köp";
$a->strings["New window"] = "Nytt fönster";
$a->strings["Open the selected location in a different window or browser tab"] = "Öppna den valda platsen i ett annat fönster eller en annan webbläsarflik";
$a->strings["User '%s' deleted"] = "Användare '%s' borttagen";
$a->strings["Delete this item?"] = "Ta bort den här posten?";
-$a->strings["Comment"] = "Kommentar";
-$a->strings["[+] show all"] = "[+] visa alla";
$a->strings["[-] show less"] = "[-] visa färre";
$a->strings["[+] expand"] = "[+] fäll ut";
$a->strings["[-] collapse"] = "[-] fäll ihop";
@@ -802,68 +813,73 @@ $a->strings["Uncertain"] = "Osäkert";
$a->strings["It's complicated"] = "Det är komplicerat";
$a->strings["Don't care"] = "Bryr mig inte";
$a->strings["Ask me"] = "Fråga mig";
-$a->strings["Site Admin"] = "Serveradministrator";
-$a->strings["Address Book"] = "Adressbok";
-$a->strings["Mood"] = "Sinnesstämning";
-$a->strings["Probe"] = "Sond";
-$a->strings["Suggest"] = "Föreslå";
-$a->strings["Random Channel"] = "Slumpvald kanal";
-$a->strings["Invite"] = "Bjud in";
-$a->strings["Features"] = "Funktioner";
-$a->strings["Language"] = "Språk";
-$a->strings["Post"] = "Inlägg";
-$a->strings["Profile Photo"] = "Profilfoto";
-$a->strings["Update"] = "Uppdatera";
-$a->strings["Install"] = "Installera";
-$a->strings["Purchase"] = "Köp";
-$a->strings["Logged out."] = "Utloggad.";
-$a->strings["Failed authentication"] = "Inloggning misslyckades";
-$a->strings["Login failed."] = "Inloggning misslyckades.";
-$a->strings["Save to Folder"] = "Spara i mapp";
-$a->strings["View all"] = "Visa alla";
-$a->strings["__ctx:noun__ Dislike"] = array(
- 0 => "ogillar detta",
- 1 => "ogillar detta",
-);
-$a->strings["Add Star"] = "Märk";
-$a->strings["Remove Star"] = "Ta bort märkning";
-$a->strings["Toggle Star Status"] = "Växla märkning";
-$a->strings["starred"] = "märkt";
-$a->strings["Add Tag"] = "Lägg till en tagg";
-$a->strings["I like this (toggle)"] = "Jag gillar det här (växla)";
-$a->strings["I don't like this (toggle)"] = "Jag gillar inte det här (växla)";
-$a->strings["Share This"] = "Dela det här";
-$a->strings["share"] = "dela";
-$a->strings["%d comment"] = array(
- 0 => "%d kommentar",
- 1 => "%d kommentarer",
-);
-$a->strings["View %s's profile - %s"] = "Visa %ss profil - %s";
-$a->strings["to"] = "till";
-$a->strings["via"] = "via";
-$a->strings["Wall-to-Wall"] = "Vägg-till-vägg";
-$a->strings["via Wall-To-Wall:"] = "via vägg-till-vägg";
-$a->strings["Save Bookmarks"] = "Spara bokmärken";
-$a->strings["Add to Calendar"] = "Lägg till kalendern";
-$a->strings["Mark all seen"] = "Märk alla som lästa";
-$a->strings["__ctx:noun__ Likes"] = "gillar detta";
-$a->strings["__ctx:noun__ Dislikes"] = "ogillar detta";
-$a->strings["This is you"] = "Det här är du";
-$a->strings["Submit"] = "Skicka";
-$a->strings["Bold"] = "Fet";
-$a->strings["Italic"] = "Kursiv";
-$a->strings["Underline"] = "Understruken";
-$a->strings["Quote"] = "Citat";
-$a->strings["Code"] = "Kod";
-$a->strings["Image"] = "Bild";
-$a->strings["Link"] = "Länk";
-$a->strings["Video"] = "Video";
-$a->strings["Missing room name"] = "Rumsnamn saknas";
-$a->strings["Duplicate room name"] = "Rumsnamnet finns redan";
-$a->strings["Invalid room specifier."] = "Ogiltig rumsbeskrivning.";
-$a->strings["Room not found."] = "Rummet hittades inte.";
-$a->strings["Room is full"] = "Rummet är fullt";
+$a->strings["Logout"] = "Logga ut";
+$a->strings["End this session"] = "Avsluta sessionen";
+$a->strings["Home"] = "Hem";
+$a->strings["Your posts and conversations"] = "Dina inlägg och konversationer";
+$a->strings["Your profile page"] = "Din profilsida";
+$a->strings["Edit Profiles"] = "Redigera profiler";
+$a->strings["Manage/Edit profiles"] = "Hantera/redigera profiler";
+$a->strings["Edit your profile"] = "Redigera din profil";
+$a->strings["Your photos"] = "Dina foton";
+$a->strings["Your files"] = "Dina filer";
+$a->strings["Your chatrooms"] = "Dina chattrum";
+$a->strings["Your bookmarks"] = "Dina bokmärken";
+$a->strings["Your webpages"] = "Dina webbsidor";
+$a->strings["Sign in"] = "Logga in";
+$a->strings["%s - click to logout"] = "%s - klicka för att logga ut";
+$a->strings["Remote authentication"] = "Fjärrinloggning";
+$a->strings["Click to authenticate to your home hub"] = "Klicka för att autentisera mot din hemmahubb";
+$a->strings["Home Page"] = "Hemsida";
+$a->strings["Register"] = "Skapa konto";
+$a->strings["Create an account"] = "Skapa ett konto";
+$a->strings["Help and documentation"] = "Hjälp och dokumentation";
+$a->strings["Applications, utilities, links, games"] = "Applikationer, verktyg, länkar, spel";
+$a->strings["Search site content"] = "Sök innehåll";
+$a->strings["Channel Directory"] = "Kanalkatalog";
+$a->strings["Your matrix"] = "Din matris";
+$a->strings["Mark all matrix notifications seen"] = "Märk alla matrisnotifieringar som lästa";
+$a->strings["Channel home"] = "Kanalhem";
+$a->strings["Mark all channel notifications seen"] = "Märk alla kanalnotifieringar som lästa";
+$a->strings["Connections"] = "Kontakter";
+$a->strings["Notices"] = "Meddelanden";
+$a->strings["Notifications"] = "Notifieringar";
+$a->strings["See all notifications"] = "Se alla notifieringar";
+$a->strings["Mark all system notifications seen"] = "Märk alla systemnotifieringar som lästa";
+$a->strings["Private mail"] = "Privat meddelande";
+$a->strings["See all private messages"] = "Se alla privata meddelanden";
+$a->strings["Mark all private messages seen"] = "Märk alla privata meddelanden som lästa";
+$a->strings["Inbox"] = "Inkorg";
+$a->strings["Outbox"] = "Utkorg";
+$a->strings["Event Calendar"] = "Kalender";
+$a->strings["See all events"] = "Se alla händelser";
+$a->strings["Mark all events seen"] = "Märk alla händelser som lästa";
+$a->strings["Manage Your Channels"] = "Hantera dina kanaler";
+$a->strings["Account/Channel Settings"] = "Konto-/kanalinställningar";
+$a->strings["Admin"] = "Administration";
+$a->strings["Site Setup and Configuration"] = "Serverinställning och -konfiguration";
+$a->strings["@name, #tag, content"] = "@namn, #tagg, innehåll";
+$a->strings["Please wait..."] = "Vänta...";
+$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "Formulärets kontrollkod var inte korrekt. Antagligen beror det på att formuläret har varit öppet för länge (> 3 timmar) innan det skickades.";
$a->strings["Set your current mood and tell your friends"] = "Ange din nuvarande sinnesstämning och visa för dina vänner";
+$a->strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = "Maximalt antal dagliga serverregistreringar överskridet. Försök igen i morgon.";
+$a->strings["Please indicate acceptance of the Terms of Service. Registration failed."] = "Välj huruvida du accepterar användarvillkoren. Registrering misslyckades.";
+$a->strings["Passwords do not match."] = "Lösenorden stämmer inte överens.";
+$a->strings["Registration successful. Please check your email for validation instructions."] = "Registrering lyckades. Kontrollera din e-post för valideringsinstruktioner.";
+$a->strings["Your registration is pending approval by the site owner."] = "Din registrering väntar på att bli godkänd av serverägaren.";
+$a->strings["Your registration can not be processed."] = "Din registrering kan inte behandlas.";
+$a->strings["Registration on this site/hub is by approval only."] = "Registrering på den här servern/hubben måste godkännas.";
+$a->strings["<a href=\"pubsites\">Register at another affiliated site/hub</a>"] = "<a href=\"pubsites\">Skapa konto på en annan ansluten server/hubb</a>";
+$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = "Antal dagliga registreringar som tillåts på den här servern har överskridits. Försök igen i morgon.";
+$a->strings["Terms of Service"] = "användarvillkor";
+$a->strings["I accept the %s for this website"] = "Jag accepterar den här webbplatsens %s";
+$a->strings["I am over 13 years of age and accept the %s for this website"] = "Jag är över 13 år och accepterar den här webbplatsens %s";
+$a->strings["Registration"] = "Registrering";
+$a->strings["Membership on this site is by invitation only."] = "Medlemskap på den här servern kan endast fås genom inbjudan.";
+$a->strings["Please enter your invitation code"] = "Ange din inbjudningskod";
+$a->strings["Your email address"] = "Din e-postadress";
+$a->strings["Choose a password"] = "Välj ett lösenord";
+$a->strings["Please re-enter your password"] = "Ange lösenordet igen";
$a->strings["Menu not found."] = "Menyn hittades inte.";
$a->strings["Menu element updated."] = "Menyval uppdaterat.";
$a->strings["Unable to update menu element."] = "Kunde inte uppdatera menyval.";
@@ -894,144 +910,6 @@ $a->strings["Menu item could not be deleted."] = "Menyval kunde inte tas bort.";
$a->strings["Edit Menu Element"] = "Redigera menyval";
$a->strings["Modify"] = "Ändra";
$a->strings["Some blurb about what to do when you're new here"] = "Lite text om vad man kan göra som ny här";
-$a->strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = "Maximalt antal dagliga serverregistreringar överskridet. Försök igen i morgon.";
-$a->strings["Please indicate acceptance of the Terms of Service. Registration failed."] = "Välj huruvida du accepterar användarvillkoren. Registrering misslyckades.";
-$a->strings["Passwords do not match."] = "Lösenorden stämmer inte överens.";
-$a->strings["Registration successful. Please check your email for validation instructions."] = "Registrering lyckades. Kontrollera din e-post för valideringsinstruktioner.";
-$a->strings["Your registration is pending approval by the site owner."] = "Din registrering väntar på att bli godkänd av serverägaren.";
-$a->strings["Your registration can not be processed."] = "Din registrering kan inte behandlas.";
-$a->strings["Registration on this site/hub is by approval only."] = "Registrering på den här servern/hubben måste godkännas.";
-$a->strings["<a href=\"pubsites\">Register at another affiliated site/hub</a>"] = "<a href=\"pubsites\">Skapa konto på en annan ansluten server/hubb</a>";
-$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = "Antal dagliga registreringar som tillåts på den här servern har överskridits. Försök igen i morgon.";
-$a->strings["Terms of Service"] = "användarvillkor";
-$a->strings["I accept the %s for this website"] = "Jag accepterar den här webbplatsens %s";
-$a->strings["I am over 13 years of age and accept the %s for this website"] = "Jag är över 13 år och accepterar den här webbplatsens %s";
-$a->strings["Registration"] = "Registrering";
-$a->strings["Membership on this site is by invitation only."] = "Medlemskap på den här servern kan endast fås genom inbjudan.";
-$a->strings["Please enter your invitation code"] = "Ange din inbjudningskod";
-$a->strings["Your email address"] = "Din e-postadress";
-$a->strings["Choose a password"] = "Välj ett lösenord";
-$a->strings["Please re-enter your password"] = "Ange lösenordet igen";
-$a->strings["- select -"] = "- välj -";
-$a->strings["Invalid profile identifier."] = "Ogiltigt profil-ID.";
-$a->strings["Profile Visibility Editor"] = "Redigera profilsynlighet";
-$a->strings["Click on a contact to add or remove."] = "Klicka på en kontakt för att lägga till eller ta bort.";
-$a->strings["Visible To"] = "Kan ses av";
-$a->strings["All Connections"] = "Alla kontakter";
-$a->strings["Failed to create source. No channel selected."] = "Misslyckades att skapa källa. Ingen kanal vald.";
-$a->strings["Source created."] = "Källa skapad.";
-$a->strings["Source updated."] = "Källa uppdaterad.";
-$a->strings["*"] = "*";
-$a->strings["Manage remote sources of content for your channel."] = "Hantera fjärrkällor med innehåll för din kanal.";
-$a->strings["New Source"] = "Ny källa";
-$a->strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = "Importera allt eller valt innehåll från följande kanal till den här kanalen och distribuera det enligt dina kanalinställningar.";
-$a->strings["Only import content with these words (one per line)"] = "Importera endast innehåll med de här orden (ett per rad)";
-$a->strings["Leave blank to import all public content"] = "Lämna blankt för att importera allt offentligt innehåll";
-$a->strings["Channel Name"] = "Kanalnamn";
-$a->strings["Source not found."] = "Källa hittades inte.";
-$a->strings["Edit Source"] = "Redigera källa";
-$a->strings["Delete Source"] = "Ta bort källa";
-$a->strings["Source removed"] = "Källa borttagen";
-$a->strings["Unable to remove source."] = "Kunde inte ta bort källa.";
-$a->strings["Poke/Prod"] = "Puffa/stöt till";
-$a->strings["poke, prod or do other things to somebody"] = "puffa, stöt till eller gör andra saker mot någon";
-$a->strings["Recipient"] = "Mottagare";
-$a->strings["Choose what you wish to do to recipient"] = "Välj vad du önskar göra med mottagaren";
-$a->strings["Make this post private"] = "Gör det här inlägget privat";
-$a->strings["Authorize application connection"] = "Tillåt anslutning av applikation";
-$a->strings["Return to your app and insert this Securty Code:"] = "Återgå till din applikation och ange den här säkerhetskoden:";
-$a->strings["Please login to continue."] = "Logga in för att fortsätta.";
-$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "Vill du låta den här applikationen få tillgång till dina inlägg och kontakter, och/eller skapa nya inlägg åt dig?";
-$a->strings["Yes"] = "Ja";
-$a->strings["No"] = "Nej";
-$a->strings["Public access denied."] = "Offentlig behörighet saknas.";
-$a->strings["Item not available."] = "Post inte tillgänglig.";
-$a->strings["Fetching URL returns error: %1\$s"] = "Hämtning av URL returnerade fel: %1\$s";
-$a->strings["Invalid item."] = "Ogiltig post.";
-$a->strings["Channel not found."] = "Kanalen hittas inte.";
-$a->strings["Page not found."] = "Sidan hittas inte.";
-$a->strings["%1\$s is following %2\$s's %3\$s"] = "%1\$s följer %2\$ss %3\$s";
-$a->strings["Block Name"] = "Blocknamn";
-$a->strings["Red Matrix Server - Setup"] = "Red Matrix-server - inställningar";
-$a->strings["Could not connect to database."] = "Kunde inte ansluta till databasen.";
-$a->strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = "Kunde inte ansluta till den angivna server-URL:en. Möjligt problem med SSL-certifikat eller DNS.";
-$a->strings["Could not create table."] = "Kunde inte skapa tabell.";
-$a->strings["Your site database has been installed."] = "Din serverdatabas har installerats.";
-$a->strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = "Du kan behöva importera filen \"install/schema_xxx.sql\" manuellt med en databasklient.";
-$a->strings["Please see the file \"install/INSTALL.txt\"."] = "Se filen \"install/INSTALL.txt\".";
-$a->strings["System check"] = "Systemkontroll";
-$a->strings["Next"] = "Nästa";
-$a->strings["Check again"] = "Kontrollera igen";
-$a->strings["Database connection"] = "Databasanslutning";
-$a->strings["In order to install Red Matrix we need to know how to connect to your database."] = "För att kunna installera Red Matrix behöver vi veta hur databasen ska anslutas.";
-$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Kontakta din servervärd eller administratör om du har frågor om de här inställningarna.";
-$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "Databasen du anger nedan måste finnas. Om den inte gör det, skapa den innan du fortsätter.";
-$a->strings["Database Server Name"] = "Databasserver";
-$a->strings["Default is localhost"] = "Standard är localhost";
-$a->strings["Database Port"] = "Databasport";
-$a->strings["Communication port number - use 0 for default"] = "Kommunikationsportnummer - använd 0 för standardinställning";
-$a->strings["Database Login Name"] = "Loginnamn till databas";
-$a->strings["Database Login Password"] = "Lösenord till databas";
-$a->strings["Database Name"] = "Databasnamn";
-$a->strings["Database Type"] = "Databastyp";
-$a->strings["Site administrator email address"] = "Serveradministratörens e-postadress";
-$a->strings["Your account email address must match this in order to use the web admin panel."] = "Ditt kontos e-postadress måste stämma med den här för att webbgränssnittet för administration ska kunna användas.";
-$a->strings["Website URL"] = "Webbplatsens URL";
-$a->strings["Please use SSL (https) URL if available."] = "Ange en URL med SSL (https) om tillgängligt";
-$a->strings["Please select a default timezone for your website"] = "Välj en standardtidszon för din webbplats";
-$a->strings["Site settings"] = "Serverinställningar";
-$a->strings["Could not find a command line version of PHP in the web server PATH."] = "Kunde inte hitta en kommandoradsversion av PHP i webbserverns PATH.";
-$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron."] = "Om du inte har en kommandoradsversion av PHP installerad på servern kommer du inte att kunna köra bakgrundshämtning via cron.";
-$a->strings["PHP executable path"] = "Sökväg till PHP-programmet";
-$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = "Ange hela sökvägen till php-programfilen. Du kan lämna det här blankt för att fortsätta installationen.";
-$a->strings["Command line PHP"] = "Kommandorads-PHP";
-$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "Kommandoradsversionen av PHP på ditt system har inte \"register_argc_argv\" aktiverat.";
-$a->strings["This is required for message delivery to work."] = "Det här behövs för att meddelandeleverans ska fungera.";
-$a->strings["PHP register_argc_argv"] = "PHP register_argc_argv";
-$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Fel: \"openssl_pkey_new\"-funktionen på det här systemet kan inte generera kryptonycklar";
-$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "Om systemet kör Windows, se \"http://www.php.net/manual/en/openssl.installation.php\".";
-$a->strings["Generate encryption keys"] = "Generera kryptonycklar";
-$a->strings["libCurl PHP module"] = "PHP-modulen libCurl";
-$a->strings["GD graphics PHP module"] = "PHP-modulen GD graphics";
-$a->strings["OpenSSL PHP module"] = "PHP-modulen OpenSSL";
-$a->strings["mysqli or postgres PHP module"] = "PHP-modulen mysqli eller postgres";
-$a->strings["mb_string PHP module"] = "PHP-modulen mb_string";
-$a->strings["mcrypt PHP module"] = "PHP-modulen mcrypt";
-$a->strings["Apache mod_rewrite module"] = "Apache-modulen mod_rewrite";
-$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Fel: Apache-webbserverns mod-rewrite-modul krävs men är inte installerad.";
-$a->strings["proc_open"] = "proc_open";
-$a->strings["Error: proc_open is required but is either not installed or has been disabled in php.ini"] = "Fel: proc_open krävs men är antingen inte installerad eller har inaktiverats i php.ini";
-$a->strings["Error: libCURL PHP module required but not installed."] = "Fel: PHP-modulen libCURL krävs men är inte installerad.";
-$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Fel: PHP-modulen GD graphics med JPEG-stöd krävs men är inte installerad.";
-$a->strings["Error: openssl PHP module required but not installed."] = "Fel: PHP-modulen openssl krävs men är inte installerad.";
-$a->strings["Error: mysqli or postgres PHP module required but neither are installed."] = "Fel: en av PHP-modulerna mysqli eller postgres krävs men är inte installerad.";
-$a->strings["Error: mb_string PHP module required but not installed."] = "Fel: PHP-modulen mb_string krävs men är inte installerad.";
-$a->strings["Error: mcrypt PHP module required but not installed."] = "Fel: PHP-modulen mcrypt krävs men är inte installerad.";
-$a->strings["The web installer needs to be able to create a file called \".htconfig.php\ in the top folder of your web server and it is unable to do so."] = "Webbinstallationen måste kunna skapa filen \".htconfig.php\" i toppkatalogen på din webbserver men kan inte göra det.";
-$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "Det är ofta en behörighetsinställning som gör att webbservern inte kan skriva filer i din katalog - även om du kan.";
-$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder."] = "Efter den här proceduren kommer vi att ge dig en text att spara i filen .htconfig.php i Reds toppkatalog.";
-$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"install/INSTALL.txt\" for instructions."] = "Alternativt kan du hoppa över den här proceduren och göra en manuell installation. För instruktioner, se filen \"install/INSTALL.txt\".";
-$a->strings[".htconfig.php is writable"] = ".htconfig.php är skrivbar";
-$a->strings["Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = "Red använder mallmotorn Smarty3 för att rendera webbvyerna. Smarty3 kompilerar mallar till PHP för att snabba upp renderingen.";
-$a->strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder."] = "För att spara de här kompilerade mallarna behöver webbservern ha skrivrättigheter till katalogen %s under Reds toppkatalog.";
-$a->strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = "Försäkra dig om att användaren som din webbserver kör som (t.ex. www-data) har skrivrättigheter till den här katalogen.";
-$a->strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = "Observera: som en säkerhetsåtgärd bör du ge webbservern skrivrättighet endast för %s - inte för mallfilerna (.tpl) som finns där.";
-$a->strings["%s is writable"] = "%s är skrivbar";
-$a->strings["Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder"] = "Red använder katalogen store för att spara uppladdade filer. Webbservern behöver ha skrivrättigheter till katalogen store under Reds toppkatalog.";
-$a->strings["store is writable"] = "store är skrivbar";
-$a->strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = "SSL-certifikatet kan inte valideras. Fixa certifikatet eller inaktivera https-åtkomst till den här servern.";
-$a->strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = "Om du har https-åtkomst till din webbplats eller tillåter anslutningar till TCP-port 443 (https-porten) MÅSTE du använda ett certifikat som kan verifieras av webbläsare. Du FÅR INTE använda självsignerade certifikat!";
-$a->strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = "Restriktionen finns eftersom offentliga inlägg från dig kan innehålla till exempel referenser till bilder på din egen hubb.";
-$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = "Om ditt certifikat inte känns igen kommer medlemmar på andra webbplatser (som själv kan ha giltiga certifikat) att få en varning på sin egen webbplats om säkerhetsproblem.";
-$a->strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = "Detta kan orsaka problem med användbarheten (inte bara på din egen server) så vi måste trycka på det här kravet.";
-$a->strings["Providers are available that issue free certificates which are browser-valid."] = "Det finns leverantörer som utfärdar gratis certifikat som känns igen av webbläsare.";
-$a->strings["SSL certificate validation"] = "SSL-certifikatvalidering";
-$a->strings["Url rewrite in .htaccess is not working. Check your server configuration.Test: "] = "Url rewrite i .htaccess fungerar inte. Kolla din serverkonfiguration. Test: ";
-$a->strings["Url rewrite is working"] = "URL rewrite fungerar";
-$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "Databaskonfigurationsfilen \".htconfig.php\" kunde inte skrivas. Använd den bifogade texten för att skapa en konfigurationsfil i din webbservers rot.";
-$a->strings["Errors encountered creating database tables."] = "Fel inträffade när databastabeller skulle skapas.";
-$a->strings["<h1>What next</h1>"] = "<h1>Nästa steg</h1>";
-$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "VIKTIGT: Du behöver ställa in en schemalagd för hämtningsrutinen [manuellt]";
$a->strings["Name is required"] = "Namn är obligatoriskt";
$a->strings["Key and Secret are required"] = "Nyckel och kod är obligatoriska";
$a->strings["Passwords do not match. Password unchanged."] = "Lösenorden stämmer inte överens. Lösenordet har inte ändrats.";
@@ -1073,6 +951,7 @@ $a->strings["Additional Features"] = "Ytterligare funktioner";
$a->strings["Connector Settings"] = "Anslutningsinställningar";
$a->strings["No special theme for mobile devices"] = "Inget särskilt tema för mobila enheter";
$a->strings["%s - (Experimental)"] = "%s - (experimentellt)";
+$a->strings["mobile"] = "mobilt";
$a->strings["Display Settings"] = "Utseende";
$a->strings["Display Theme:"] = "Tema för utseende:";
$a->strings["Mobile Theme:"] = "Mobilt tema:";
@@ -1099,6 +978,8 @@ $a->strings["Anybody in this network"] = "Vem som helst i det här nätverket";
$a->strings["Anybody authenticated"] = "Vem som helst som har autentiserat sig";
$a->strings["Anybody on the internet"] = "Vem som helst på Internet";
$a->strings["Publish your default profile in the network directory"] = "Publicera din standardprofil i nätverkskatalogen";
+$a->strings["No"] = "Nej";
+$a->strings["Yes"] = "Ja";
$a->strings["Allow us to suggest you as a potential friend to new members?"] = "Tillåt oss att föreslå dig som möjlig vän för nya medlemmar";
$a->strings["or"] = "eller";
$a->strings["Your channel address is"] = "Din kanaladress är";
@@ -1166,6 +1047,159 @@ $a->strings["Please enable expert mode (in <a href=\"settings/features\">Setting
$a->strings["Miscellaneous Settings"] = "Diverse inställningar";
$a->strings["Personal menu to display in your channel pages"] = "Personlig meny att visa i dina kanalsidor";
$a->strings["Remove this channel"] = "Ta bort den här kanalen";
+$a->strings["Collection created."] = "Krets skapad.";
+$a->strings["Could not create collection."] = "Kunde inte skapa krets.";
+$a->strings["Collection updated."] = "Kretsen uppdaterad.";
+$a->strings["Create a collection of channels."] = "Skapa en krets av kanaler.";
+$a->strings["Collection Name: "] = "Namn på krets: ";
+$a->strings["Members are visible to other channels"] = "Medlemmar kan ses av andra kanaler";
+$a->strings["Collection removed."] = "Krets borttagen.";
+$a->strings["Unable to remove collection."] = "Kunde inte ta bort krets.";
+$a->strings["Collection Editor"] = "Redigera krets";
+$a->strings["Members"] = "Medlemmar";
+$a->strings["All Connected Channels"] = "Alla anslutna kanaler";
+$a->strings["Click on a channel to add or remove."] = "Klicka på en kanal för att lägga till eller ta bort.";
+$a->strings["Public access denied."] = "Offentlig behörighet saknas.";
+$a->strings["%1\$s is following %2\$s's %3\$s"] = "%1\$s följer %2\$ss %3\$s";
+$a->strings["Poke/Prod"] = "Puffa/stöt till";
+$a->strings["poke, prod or do other things to somebody"] = "puffa, stöt till eller gör andra saker mot någon";
+$a->strings["Recipient"] = "Mottagare";
+$a->strings["Choose what you wish to do to recipient"] = "Välj vad du önskar göra med mottagaren";
+$a->strings["Make this post private"] = "Gör det här inlägget privat";
+$a->strings["Authorize application connection"] = "Tillåt anslutning av applikation";
+$a->strings["Return to your app and insert this Securty Code:"] = "Återgå till din applikation och ange den här säkerhetskoden:";
+$a->strings["Please login to continue."] = "Logga in för att fortsätta.";
+$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "Vill du låta den här applikationen få tillgång till dina inlägg och kontakter, och/eller skapa nya inlägg åt dig?";
+$a->strings["Red Matrix Server - Setup"] = "Red Matrix-server - inställningar";
+$a->strings["Could not connect to database."] = "Kunde inte ansluta till databasen.";
+$a->strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = "Kunde inte ansluta till den angivna server-URL:en. Möjligt problem med SSL-certifikat eller DNS.";
+$a->strings["Could not create table."] = "Kunde inte skapa tabell.";
+$a->strings["Your site database has been installed."] = "Din serverdatabas har installerats.";
+$a->strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = "Du kan behöva importera filen \"install/schema_xxx.sql\" manuellt med en databasklient.";
+$a->strings["Please see the file \"install/INSTALL.txt\"."] = "Se filen \"install/INSTALL.txt\".";
+$a->strings["System check"] = "Systemkontroll";
+$a->strings["Next"] = "Nästa";
+$a->strings["Check again"] = "Kontrollera igen";
+$a->strings["Database connection"] = "Databasanslutning";
+$a->strings["In order to install Red Matrix we need to know how to connect to your database."] = "För att kunna installera Red Matrix behöver vi veta hur databasen ska anslutas.";
+$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Kontakta din servervärd eller administratör om du har frågor om de här inställningarna.";
+$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "Databasen du anger nedan måste finnas. Om den inte gör det, skapa den innan du fortsätter.";
+$a->strings["Database Server Name"] = "Databasserver";
+$a->strings["Default is localhost"] = "Standard är localhost";
+$a->strings["Database Port"] = "Databasport";
+$a->strings["Communication port number - use 0 for default"] = "Kommunikationsportnummer - använd 0 för standardinställning";
+$a->strings["Database Login Name"] = "Loginnamn till databas";
+$a->strings["Database Login Password"] = "Lösenord till databas";
+$a->strings["Database Name"] = "Databasnamn";
+$a->strings["Database Type"] = "Databastyp";
+$a->strings["Site administrator email address"] = "Serveradministratörens e-postadress";
+$a->strings["Your account email address must match this in order to use the web admin panel."] = "Ditt kontos e-postadress måste stämma med den här för att webbgränssnittet för administration ska kunna användas.";
+$a->strings["Website URL"] = "Webbplatsens URL";
+$a->strings["Please use SSL (https) URL if available."] = "Ange en URL med SSL (https) om tillgängligt";
+$a->strings["Please select a default timezone for your website"] = "Välj en standardtidszon för din webbplats";
+$a->strings["Site settings"] = "Serverinställningar";
+$a->strings["Could not find a command line version of PHP in the web server PATH."] = "Kunde inte hitta en kommandoradsversion av PHP i webbserverns PATH.";
+$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron."] = "Om du inte har en kommandoradsversion av PHP installerad på servern kommer du inte att kunna köra bakgrundshämtning via cron.";
+$a->strings["PHP executable path"] = "Sökväg till PHP-programmet";
+$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = "Ange hela sökvägen till php-programfilen. Du kan lämna det här blankt för att fortsätta installationen.";
+$a->strings["Command line PHP"] = "Kommandorads-PHP";
+$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "Kommandoradsversionen av PHP på ditt system har inte \"register_argc_argv\" aktiverat.";
+$a->strings["This is required for message delivery to work."] = "Det här behövs för att meddelandeleverans ska fungera.";
+$a->strings["PHP register_argc_argv"] = "PHP register_argc_argv";
+$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Fel: \"openssl_pkey_new\"-funktionen på det här systemet kan inte generera kryptonycklar";
+$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "Om systemet kör Windows, se \"http://www.php.net/manual/en/openssl.installation.php\".";
+$a->strings["Generate encryption keys"] = "Generera kryptonycklar";
+$a->strings["libCurl PHP module"] = "PHP-modulen libCurl";
+$a->strings["GD graphics PHP module"] = "PHP-modulen GD graphics";
+$a->strings["OpenSSL PHP module"] = "PHP-modulen OpenSSL";
+$a->strings["mysqli or postgres PHP module"] = "PHP-modulen mysqli eller postgres";
+$a->strings["mb_string PHP module"] = "PHP-modulen mb_string";
+$a->strings["mcrypt PHP module"] = "PHP-modulen mcrypt";
+$a->strings["Apache mod_rewrite module"] = "Apache-modulen mod_rewrite";
+$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Fel: Apache-webbserverns mod-rewrite-modul krävs men är inte installerad.";
+$a->strings["proc_open"] = "proc_open";
+$a->strings["Error: proc_open is required but is either not installed or has been disabled in php.ini"] = "Fel: proc_open krävs men är antingen inte installerad eller har inaktiverats i php.ini";
+$a->strings["Error: libCURL PHP module required but not installed."] = "Fel: PHP-modulen libCURL krävs men är inte installerad.";
+$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Fel: PHP-modulen GD graphics med JPEG-stöd krävs men är inte installerad.";
+$a->strings["Error: openssl PHP module required but not installed."] = "Fel: PHP-modulen openssl krävs men är inte installerad.";
+$a->strings["Error: mysqli or postgres PHP module required but neither are installed."] = "Fel: en av PHP-modulerna mysqli eller postgres krävs men är inte installerad.";
+$a->strings["Error: mb_string PHP module required but not installed."] = "Fel: PHP-modulen mb_string krävs men är inte installerad.";
+$a->strings["Error: mcrypt PHP module required but not installed."] = "Fel: PHP-modulen mcrypt krävs men är inte installerad.";
+$a->strings["The web installer needs to be able to create a file called \".htconfig.php\" in the top folder of your web server and it is unable to do so."] = "Webbinstallationen måste kunna skapa filen \".htconfig.php\" i toppkatalogen på din webbserver men kan inte göra det.";
+$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "Det är ofta en behörighetsinställning som gör att webbservern inte kan skriva filer i din katalog - även om du kan.";
+$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder."] = "Efter den här proceduren kommer vi att ge dig en text att spara i filen .htconfig.php i Reds toppkatalog.";
+$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"install/INSTALL.txt\" for instructions."] = "Alternativt kan du hoppa över den här proceduren och göra en manuell installation. För instruktioner, se filen \"install/INSTALL.txt\".";
+$a->strings[".htconfig.php is writable"] = ".htconfig.php är skrivbar";
+$a->strings["Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = "Red använder mallmotorn Smarty3 för att rendera webbvyerna. Smarty3 kompilerar mallar till PHP för att snabba upp renderingen.";
+$a->strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder."] = "För att spara de här kompilerade mallarna behöver webbservern ha skrivrättigheter till katalogen %s under Reds toppkatalog.";
+$a->strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = "Försäkra dig om att användaren som din webbserver kör som (t.ex. www-data) har skrivrättigheter till den här katalogen.";
+$a->strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = "Observera: som en säkerhetsåtgärd bör du ge webbservern skrivrättighet endast för %s - inte för mallfilerna (.tpl) som finns där.";
+$a->strings["%s is writable"] = "%s är skrivbar";
+$a->strings["Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder"] = "Red använder katalogen store för att spara uppladdade filer. Webbservern behöver ha skrivrättigheter till katalogen store under Reds toppkatalog.";
+$a->strings["store is writable"] = "store är skrivbar";
+$a->strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = "SSL-certifikatet kan inte valideras. Fixa certifikatet eller inaktivera https-åtkomst till den här servern.";
+$a->strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = "Om du har https-åtkomst till din webbplats eller tillåter anslutningar till TCP-port 443 (https-porten) MÅSTE du använda ett certifikat som kan verifieras av webbläsare. Du FÅR INTE använda självsignerade certifikat!";
+$a->strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = "Restriktionen finns eftersom offentliga inlägg från dig kan innehålla till exempel referenser till bilder på din egen hubb.";
+$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = "Om ditt certifikat inte känns igen kommer medlemmar på andra webbplatser (som själv kan ha giltiga certifikat) att få en varning på sin egen webbplats om säkerhetsproblem.";
+$a->strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = "Detta kan orsaka problem med användbarheten (inte bara på din egen server) så vi måste trycka på det här kravet.";
+$a->strings["Providers are available that issue free certificates which are browser-valid."] = "Det finns leverantörer som utfärdar gratis certifikat som känns igen av webbläsare.";
+$a->strings["SSL certificate validation"] = "SSL-certifikatvalidering";
+$a->strings["Url rewrite in .htaccess is not working. Check your server configuration.Test: "] = "Url rewrite i .htaccess fungerar inte. Kolla din serverkonfiguration. Test: ";
+$a->strings["Url rewrite is working"] = "URL rewrite fungerar";
+$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "Databaskonfigurationsfilen \".htconfig.php\" kunde inte skrivas. Använd den bifogade texten för att skapa en konfigurationsfil i din webbservers rot.";
+$a->strings["Errors encountered creating database tables."] = "Fel inträffade när databastabeller skulle skapas.";
+$a->strings["<h1>What next</h1>"] = "<h1>Nästa steg</h1>";
+$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "VIKTIGT: Du behöver ställa in en schemalagd för hämtningsrutinen [manuellt]";
+$a->strings["Item not available."] = "Post inte tillgänglig.";
+$a->strings["Fetching URL returns error: %1\$s"] = "Hämtning av URL returnerade fel: %1\$s";
+$a->strings["Invalid item."] = "Ogiltig post.";
+$a->strings["Channel not found."] = "Kanalen hittas inte.";
+$a->strings["Page not found."] = "Sidan hittas inte.";
+$a->strings["Export Channel"] = "Exportera kanal";
+$a->strings["Export your basic channel information to a small file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new hub, but\tdoes not contain your content."] = "Exportera kanalens basinformation till en liten fil. Denna fungerar som en säkerhetskopia av dina anslutningar, behörigheter, profil, och grundläggande data, och kan användas för att importera dina data till en ny hubb, men tar inte med ditt innehåll.";
+$a->strings["Export Content"] = "Exportera innehåll";
+$a->strings["Export your channel information and all the content to a JSON backup. This backs up all of your connections, permissions, profile data and all of your content, but is generally not suitable for importing a channel to a new hub as this file may be VERY large. Please be patient - it may take several minutes for this download to begin."] = "Exportera din kanalinformation och allt innehåll till en säkerhetskopia i JSON-format. Detta kopierar alla dina anslutningar, behörigheter, profildata och allt ditt innehåll, men är generellt inte lämpligt för att importera en kanal till en ny hubb, eftersom filen kan vara VÄLDIGT stor. Ha tålamod - det kan ta flera minuter innan nedladdningen börjar.";
+$a->strings["No potential page delegates located."] = "Inga potentiella sid-ombud funna.";
+$a->strings["Delegate Page Management"] = "Delegera sidhantering";
+$a->strings["Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely."] = "Ombud kan hantera alla aspekter av det här kontot/den här sidan förutom grundläggande kontoinställningar. Delegera inte ditt personliga konto till någon som du inte litar fullständigt på.";
+$a->strings["Existing Page Managers"] = "Befintliga sid-ansvariga";
+$a->strings["Existing Page Delegates"] = "Befintliga sid-ombud";
+$a->strings["Potential Delegates"] = "Potentiella ombud";
+$a->strings["Remove"] = "Ta bort";
+$a->strings["Add"] = "Lägg till";
+$a->strings["No entries."] = "Inga poster.";
+$a->strings["Version %s"] = "Version %s";
+$a->strings["Installed plugins/addons/apps:"] = "Installerade tillägg/moduler/appar:";
+$a->strings["No installed plugins/addons/apps"] = "Inga installerade tillägg/moduler/appar";
+$a->strings["Red"] = "Red";
+$a->strings["This is a hub of the Red Matrix - a global cooperative network of decentralized privacy enhanced websites."] = "Det här är en hubb som ingår i Red Matrix - ett globalt samverkande nätverk av decentraliserade webbplatser med bättre integritetskydd.";
+$a->strings["Tag: "] = "Tagg: ";
+$a->strings["Last background fetch: "] = "Senaste bakgrundshämtning: ";
+$a->strings["Running at web location"] = "Kör på webbutrymmet";
+$a->strings["Please visit <a href=\"https://redmatrix.me\">RedMatrix.me</a> to learn more about the Red Matrix."] = "Besök <a href=\"https://redmatrix.me\">RedMatrix.me</a> för att lära dig mer om Red Matrix.";
+$a->strings["Bug reports and issues: please visit"] = "Buggrapporter och problem: besök";
+$a->strings["Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot com"] = "Förslag, uppskattning, etc. - maila \"redmatrix\" at librelist - dot com";
+$a->strings["Site Administrators"] = "Serveradministratörer";
+$a->strings["Failed to create source. No channel selected."] = "Misslyckades att skapa källa. Ingen kanal vald.";
+$a->strings["Source created."] = "Källa skapad.";
+$a->strings["Source updated."] = "Källa uppdaterad.";
+$a->strings["*"] = "*";
+$a->strings["Manage remote sources of content for your channel."] = "Hantera fjärrkällor med innehåll för din kanal.";
+$a->strings["New Source"] = "Ny källa";
+$a->strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = "Importera allt eller valt innehåll från följande kanal till den här kanalen och distribuera det enligt dina kanalinställningar.";
+$a->strings["Only import content with these words (one per line)"] = "Importera endast innehåll med de här orden (ett per rad)";
+$a->strings["Leave blank to import all public content"] = "Lämna blankt för att importera allt offentligt innehåll";
+$a->strings["Channel Name"] = "Kanalnamn";
+$a->strings["Source not found."] = "Källa hittades inte.";
+$a->strings["Edit Source"] = "Redigera källa";
+$a->strings["Delete Source"] = "Ta bort källa";
+$a->strings["Source removed"] = "Källa borttagen";
+$a->strings["Unable to remove source."] = "Kunde inte ta bort källa.";
+$a->strings["Invalid profile identifier."] = "Ogiltigt profil-ID.";
+$a->strings["Profile Visibility Editor"] = "Redigera profilsynlighet";
+$a->strings["Click on a contact to add or remove."] = "Klicka på en kontakt för att lägga till eller ta bort.";
+$a->strings["Visible To"] = "Kan ses av";
+$a->strings["All Connections"] = "Alla kontakter";
$a->strings["Event can not end before it has started."] = "Händelser kan inte sluta innan de börjat.";
$a->strings["Event title and start time are required."] = "Händelsen behöver titel och starttid.";
$a->strings["Event not found."] = "Händelsen hittades inte.";
@@ -1176,6 +1210,7 @@ $a->strings["Previous"] = "Föregående";
$a->strings["Export"] = "Exportera";
$a->strings["Event details"] = "Detaljer för händelse";
$a->strings["Starting date and Title are required."] = "Startdatum och titel är obligatoriska.";
+$a->strings["Categories (comma-separated list)"] = "Kategorier (kommaseparerad lista)";
$a->strings["Event Starts:"] = "Händelsen börjar:";
$a->strings["Required"] = "Behövs";
$a->strings["Finish date/time is not known or not relevant"] = "Slutdatum/tid är okänt eller inte relevant";
@@ -1206,28 +1241,16 @@ $a->strings["Bookmark this room"] = "Bokmärk det här rummet";
$a->strings["New Chatroom"] = "Nytt chattrum";
$a->strings["Chatroom Name"] = "Namn på chattrum";
$a->strings["%1\$s's Chatrooms"] = "%1\$ss chattrum";
-$a->strings["Version %s"] = "Version %s";
-$a->strings["Installed plugins/addons/apps:"] = "Installerade tillägg/moduler/appar:";
-$a->strings["No installed plugins/addons/apps"] = "Inga installerade tillägg/moduler/appar";
-$a->strings["Red"] = "Red";
-$a->strings["This is a hub of the Red Matrix - a global cooperative network of decentralized privacy enhanced websites."] = "Det här är en hubb som ingår i Red Matrix - ett globalt samverkande nätverk av decentraliserade webbplatser med bättre integritetskydd.";
-$a->strings["Running at web location"] = "Kör på webbutrymmet";
-$a->strings["Please visit <a href=\"http://getzot.com\">GetZot.com</a> to learn more about the Red Matrix."] = "Besök <a href=\"http://getzot.com\">GetZot.com</a> lära dig mer om Red Matrix.";
-$a->strings["Bug reports and issues: please visit"] = "Buggrapporter och problem: besök";
-$a->strings["Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot com"] = "Förslag, uppskattning, etc. - maila \"redmatrix\" at librelist - dot com";
-$a->strings["Site Administrators"] = "Serveradministratörer";
$a->strings["Away"] = "Borta";
$a->strings["Online"] = "Online";
$a->strings["Please login."] = "Logga in.";
-$a->strings["Continue"] = "Fortsätt";
-$a->strings["Premium Channel Setup"] = "Inställning av premiumkanal";
-$a->strings["Enable premium channel connection restrictions"] = "Aktivera kontaktrestriktioner för premiumkanal";
-$a->strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = "Ange dina restriktioner och villkor, som Paypal-kvitto, användarriktlinjer, etc.";
-$a->strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = "Den här kanalen kan kräva ytterligare steg eller godkännande av följande villkor innan anslutning:";
-$a->strings["Potential connections will then see the following text before proceeding:"] = "Potentiella kontakter kommer sedan att se följande text innan de går vidare:";
-$a->strings["By continuing, I certify that I have complied with any instructions provided on this page."] = "Genom att fortsätta intygar jag att jag har följt alla instruktioner som ges på den här sidan.";
-$a->strings["(No specific instructions have been provided by the channel owner.)"] = "(Inga specifika instruktioner har givits av kanalägaren.)";
-$a->strings["Restricted or Premium Channel"] = "Begränsad kanal eller premiumkanal";
+$a->strings["Item not found"] = "Posten hittas inte";
+$a->strings["Item is not editable"] = "Posten går ej att redigera";
+$a->strings["Edit post"] = "Redigera inlägg";
+$a->strings["Delete item?"] = "Ta bort posten?";
+$a->strings["Insert YouTube video"] = "Infoga Youtube-video";
+$a->strings["Insert Vorbis [.ogg] video"] = "Infoga Vorbis [.ogg]-video";
+$a->strings["Insert Vorbis [.ogg] audio"] = "Infoga Vorbis [.ogg]-ljud";
$a->strings["Channel removals are not allowed within 48 hours of changing the account password."] = "Borttagning av kanal tillåts inte inom 48 timmar efter att kontolösenordet har ändrats.";
$a->strings["Remove This Channel"] = "Ta bort den här kanalen";
$a->strings["This will completely remove this channel from the network. Once this has been done it is not recoverable."] = "Det här kommer att ta bort den här kanalen helt från nätverket. När det är gjort går det inte att återställa den.";
@@ -1244,17 +1267,22 @@ $a->strings["Authentication failed."] = "Inloggning misslyckades.";
$a->strings["Remote Authentication"] = "Fjärrinloggning";
$a->strings["Enter your channel address (e.g. channel@example.com)"] = "Ange din kanaladress (t.ex. kanal@example.com)";
$a->strings["Authenticate"] = "Autentisera";
-$a->strings["Like/Dislike"] = "Gilla/ogilla";
-$a->strings["This action is restricted to members."] = "Den här åtgärden fungerar bara för medlemmar.";
-$a->strings["Please <a href=\"rmagic\">login with your RedMatrix ID</a> or <a href=\"register\">register as a new RedMatrix member</a> to continue."] = "<a href=\"rmagic\">Logga in med ditt RedMatrix-ID</a> eller <a href=\"register\">registrera dig som ny RedMatrix medlem</a> för att fortsätta.";
-$a->strings["Invalid request."] = "Ogiltig begäran.";
-$a->strings["thing"] = "sak";
-$a->strings["Channel unavailable."] = "Kanalen kan ej nås.";
-$a->strings["Previous action reversed."] = "Föregående åtgärd återställdes.";
-$a->strings["Action completed."] = "Åtgärden slutfördes.";
-$a->strings["Thank you."] = "Tack.";
-$a->strings["Remote authentication blocked. You are logged into this site locally. Please logout and retry."] = "Fjärrinloggning blockerades. Du är inloggad på den här servern lokalt. Logga ut och försök igen.";
-$a->strings["Welcome %s. Remote authentication successful."] = "Välkommen %s. Fjärrinloggning lyckades.";
+$a->strings["No valid account found."] = "Inget giltigt konto hittades.";
+$a->strings["Password reset request issued. Check your email."] = "Lösenordsåterställning har skickats. Kontrollera din e-post.";
+$a->strings["Site Member (%s)"] = "Servermedlem (%s)";
+$a->strings["Password reset requested at %s"] = "Lösenordsåterställning begärd på %s";
+$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "Begäran kunde inte bekräftas. (Du kan ha skickat den tidigare.) Lösenordsåterställningen misslyckades.";
+$a->strings["Password Reset"] = "Lösenordsåterställning";
+$a->strings["Your password has been reset as requested."] = "Ditt lösenord har återställts som begärt.";
+$a->strings["Your new password is"] = "Ditt nya lösenord är";
+$a->strings["Save or copy your new password - and then"] = "Spara eller kopiera ditt nya lösenord - ";
+$a->strings["click here to login"] = "klicka sedan här för att logga in";
+$a->strings["Your password may be changed from the <em>Settings</em> page after successful login."] = "Ditt lösenord kan bytas från sidan <em>Inställningar</em> när du är inloggad.";
+$a->strings["Your password has changed at %s"] = "Ditt lösenord byttes på %s";
+$a->strings["Forgot your Password?"] = "Glömt lösenordet?";
+$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Ange din e-postadress och skicka för att återställa ditt lösenord. Kontrollera sedan din e-post för vidare instruktioner.";
+$a->strings["Email Address"] = "E-postadress";
+$a->strings["Reset"] = "Återställ";
$a->strings["Could not access contact record."] = "Kunde inte komma åt kontaktuppgifter.";
$a->strings["Could not locate selected profile."] = "Kunde inte hitta vald profil.";
$a->strings["Connection updated."] = "Kontakt uppdaterad.";
@@ -1278,8 +1306,9 @@ $a->strings["%1\$s [%2\$s]"] = "%1\$s [%2\$s]";
$a->strings["Edit connection"] = "Redigera kontakt";
$a->strings["Search your connections"] = "Sök bland dina kontakter";
$a->strings["Finding: "] = "Sökning efter: ";
-$a->strings["OpenID protocol error. No ID returned."] = "Protokollfel för OpenID. Inget ID returnerades.";
-$a->strings["Edit post"] = "Redigera inlägg";
+$a->strings["sent you a private message"] = "skickade ett privat meddelande till dig";
+$a->strings["added your channel"] = "lade till din kanal";
+$a->strings["posted an event"] = "skapade en händelse";
$a->strings["is now connected to"] = "har nu kontakt med";
$a->strings["Could not access address book record."] = "Kunde inte komma åt adressboksuppgifter.";
$a->strings["Refresh failed - channel is currently unavailable."] = "Uppdatering misslyckades - kanalen är inte tillgänglig.";
@@ -1353,6 +1382,113 @@ $a->strings["Currently archived"] = "Arkiverad";
$a->strings["Currently pending"] = "Inväntar svar";
$a->strings["Hide this contact from others"] = "Dölj den här kontakten för andra";
$a->strings["Replies/likes to your public posts <strong>may</strong> still be visible"] = "Svar/gilla-reaktioner på dina offentliga inlägg <strong>kan</strong> fortfarande synas";
+$a->strings["Unable to lookup recipient."] = "Kunde inte hitta mottagare.";
+$a->strings["Unable to communicate with requested channel."] = "Kunde inte kommunicera med den begärda kanalen.";
+$a->strings["Cannot verify requested channel."] = "Kan inte bekräfta den begärda kanalen.";
+$a->strings["Selected channel has private message restrictions. Send failed."] = "Den valda kanalen har restriktioner för privata meddelanden. Misslyckades att skicka.";
+$a->strings["Message deleted."] = "Meddelande borttaget.";
+$a->strings["Message recalled."] = "Meddelande återkallat.";
+$a->strings["Send Private Message"] = "Skicka privat meddelande.";
+$a->strings["To:"] = "Till:";
+$a->strings["Subject:"] = "Ämne:";
+$a->strings["Your message:"] = "Ditt meddelande:";
+$a->strings["Send"] = "Skicka";
+$a->strings["Message not found."] = "Meddelandet hittades inte.";
+$a->strings["Delete message"] = "Ta bort meddelande";
+$a->strings["Recall message"] = "Återkalla meddelande";
+$a->strings["Message has been recalled."] = "Meddelandet har återkallats.";
+$a->strings["Private Conversation"] = "Privat konversation";
+$a->strings["Delete conversation"] = "Ta bort konversation";
+$a->strings["No secure communications available. You <strong>may</strong> be able to respond from the sender's profile page."] = "Ingen säker kommunikationskanal tillgänglig. Du kan <strong>möjligtvis</strong> svara från avsändarens profilsida.";
+$a->strings["Send Reply"] = "Skicka svar";
+$a->strings["Page owner information could not be retrieved."] = "Information om sidans ägare kunde inte hittas.";
+$a->strings["Album not found."] = "Albumet hittades inte.";
+$a->strings["Delete Album"] = "Ta bort album";
+$a->strings["Delete Photo"] = "Ta bort foto";
+$a->strings["No photos selected"] = "Inga foton valda";
+$a->strings["Access to this item is restricted."] = "Åtkomst till den här posten är begränsat.";
+$a->strings["%1$.2f MB of %2$.2f MB photo storage used."] = "%1$.2f MB av %2$.2f MB fotolagring använt.";
+$a->strings["%1$.2f MB photo storage used."] = "%1$.2f MB fotolagring använt.";
+$a->strings["Upload Photos"] = "Ladda upp foton";
+$a->strings["Enter a new album name"] = "Ange ett nytt albumnamn";
+$a->strings["or select an existing one (doubleclick)"] = "eller välj ett befintligt (dubbelklicka)";
+$a->strings["Do not show a status post for this upload"] = "Visa inte en statusuppdatering för den här uppladdningen";
+$a->strings["Album name could not be decoded"] = "Albumnamn kunde inte tolkas";
+$a->strings["Contact Photos"] = "Kontaktfoton";
+$a->strings["Show Newest First"] = "Visa nyast först";
+$a->strings["Show Oldest First"] = "Visa äldst först";
+$a->strings["View Photo"] = "Visa foto";
+$a->strings["Edit Album"] = "Redigera album";
+$a->strings["Permission denied. Access to this item may be restricted."] = "Behörighet saknas. Åtkomst till den här posten kan vara begränsat.";
+$a->strings["Photo not available"] = "Foto inte tillgängligt";
+$a->strings["Use as profile photo"] = "Använd som profilfoto";
+$a->strings["Private Photo"] = "Privat foto";
+$a->strings["View Full Size"] = "Visa fullstorlek";
+$a->strings["Edit photo"] = "Redigera foto";
+$a->strings["Rotate CW (right)"] = "Rotera medurs (höger)";
+$a->strings["Rotate CCW (left)"] = "Rotera moturs (vänster)";
+$a->strings["Caption"] = "Bildtext";
+$a->strings["Add a Tag"] = "Lägg till en tagg";
+$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com"] = "Exempel: @bob, @Barbara_Jensen, @jim@example.com";
+$a->strings["Flag as adult in album view"] = "Flagga som olämpligt för barn i albumvyn";
+$a->strings["In This Photo:"] = "På fotot:";
+$a->strings["View Album"] = "Visa album";
+$a->strings["Recent Photos"] = "Nya foton";
+$a->strings["Bookmark added"] = "Bokmärke tillagt";
+$a->strings["My Bookmarks"] = "Mina bokmärken";
+$a->strings["My Connections Bookmarks"] = "Mina kontakters bokmärken";
+$a->strings["This site is not a directory server"] = "Den här servern är inte en katalogserver";
+$a->strings["RedMatrix - Guests: Username: {your email address}, Password: +++"] = "RedMatrix - Gäster: Användarnamn {din e-postadress}, Lösenord: +++";
+$a->strings["network"] = "nätverk";
+$a->strings["Block Name"] = "Blocknamn";
+$a->strings["Edit Block"] = "Redigera block";
+$a->strings["Delete block?"] = "Ta bort block?";
+$a->strings["Delete Block"] = "Ta bort block";
+$a->strings["Layout updated."] = "Layout uppdaterad.";
+$a->strings["Edit System Page Description"] = "Redigera systemsidbeskrivning";
+$a->strings["Layout not found."] = "Layout hittas inte.";
+$a->strings["Module Name:"] = "Modulnamn:";
+$a->strings["Layout Help"] = "Layouthjälp";
+$a->strings["Edit Layout"] = "Redigera layout";
+$a->strings["Delete layout?"] = "Ta bort layout?";
+$a->strings["Delete Layout"] = "Ta bort layout";
+$a->strings["Red Matrix - &quot;The Network&quot;"] = "Red Matrix - &quot;Nätverket&quot;";
+$a->strings["Welcome to %s"] = "Välkommen till %s";
+$a->strings["Edit Webpage"] = "Redigera webbsida";
+$a->strings["Delete webpage?"] = "Ta bort webbsida?";
+$a->strings["Delete Webpage"] = "Ta bort webbsida";
+$a->strings["webpage"] = "webbsida";
+$a->strings["block"] = "block";
+$a->strings["layout"] = "layout";
+$a->strings["%s element installed"] = "%selement installerat";
+$a->strings["Image uploaded but image cropping failed."] = "Bilden laddades upp men beskärning misslyckades.";
+$a->strings["Image resize failed."] = "Ändring av bildstorlek misslyckades.";
+$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = "Shift-uppdatera sidan eller rensa webbläsarcachen om det nya fotot inte visas direkt.";
+$a->strings["Image exceeds size limit of %d"] = "Bilden överskrider storleksbegränsningen %d";
+$a->strings["Unable to process image."] = "Kunde inte behandla bilden.";
+$a->strings["Photo not available."] = "Fotot är inte tillgängligt.";
+$a->strings["Upload File:"] = "Ladda upp fil:";
+$a->strings["Select a profile:"] = "Välj en profil:";
+$a->strings["Upload Profile Photo"] = "Ladda upp profilfoto";
+$a->strings["skip this step"] = "hoppa över det här steget";
+$a->strings["select a photo from your photo albums"] = "välj ett foto från dina fotoalbum";
+$a->strings["Crop Image"] = "Beskär bild";
+$a->strings["Please adjust the image cropping for optimum viewing."] = "Justera bildens beskärning för bästa utseende.";
+$a->strings["Done Editing"] = "Klar med redigering";
+$a->strings["Image uploaded successfully."] = "Bilduppladdning lyckades.";
+$a->strings["Image upload failed."] = "Bilduppladdning misslyckades.";
+$a->strings["Image size reduction [%s] failed."] = "Krympning av bilden [%s] misslyckades.";
+$a->strings["Like/Dislike"] = "Gilla/ogilla";
+$a->strings["This action is restricted to members."] = "Den här åtgärden fungerar bara för medlemmar.";
+$a->strings["Please <a href=\"rmagic\">login with your RedMatrix ID</a> or <a href=\"register\">register as a new RedMatrix member</a> to continue."] = "<a href=\"rmagic\">Logga in med ditt RedMatrix-ID</a> eller <a href=\"register\">registrera dig som ny RedMatrix medlem</a> för att fortsätta.";
+$a->strings["Invalid request."] = "Ogiltig begäran.";
+$a->strings["thing"] = "sak";
+$a->strings["Channel unavailable."] = "Kanalen kan ej nås.";
+$a->strings["Previous action reversed."] = "Föregående åtgärd återställdes.";
+$a->strings["Action completed."] = "Åtgärden slutfördes.";
+$a->strings["Thank you."] = "Tack.";
+$a->strings["Help:"] = "Hjälp:";
+$a->strings["Not Found"] = "Hittas inte";
$a->strings["Thing updated"] = "Föremål uppdaterat";
$a->strings["Object store: failed"] = "Objektlagring: misslyckades";
$a->strings["Thing added"] = "Föremål tillagt";
@@ -1367,27 +1503,66 @@ $a->strings["Name of thing e.g. something"] = "Namn på föremål, t.ex. någont
$a->strings["URL of thing (optional)"] = "URL för föremål (frivilligt)";
$a->strings["URL for photo of thing (optional)"] = "URL för foto på föremål (frivilligt)";
$a->strings["Add Thing to your Profile"] = "Lägg till föremål till din profil";
-$a->strings["No valid account found."] = "Inget giltigt konto hittades.";
-$a->strings["Password reset request issued. Check your email."] = "Lösenordsåterställning har skickats. Kontrollera din e-post.";
-$a->strings["Site Member (%s)"] = "Servermedlem (%s)";
-$a->strings["Password reset requested at %s"] = "Lösenordsåterställning begärd på %s";
-$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "Begäran kunde inte bekräftas. (Du kan ha skickat den tidigare.) Lösenordsåterställningen misslyckades.";
-$a->strings["Password Reset"] = "Lösenordsåterställning";
-$a->strings["Your password has been reset as requested."] = "Ditt lösenord har återställts som begärt.";
-$a->strings["Your new password is"] = "Ditt nya lösenord är";
-$a->strings["Save or copy your new password - and then"] = "Spara eller kopiera ditt nya lösenord - ";
-$a->strings["click here to login"] = "klicka sedan här för att logga in";
-$a->strings["Your password may be changed from the <em>Settings</em> page after successful login."] = "Ditt lösenord kan bytas från sidan <em>Inställningar</em> när du är inloggad.";
-$a->strings["Your password has changed at %s"] = "Ditt lösenord byttes på %s";
-$a->strings["Forgot your Password?"] = "Glömt lösenordet?";
-$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Ange din e-postadress och skicka för att återställa ditt lösenord. Kontrollera sedan din e-post för vidare instruktioner.";
-$a->strings["Email Address"] = "E-postadress";
-$a->strings["Reset"] = "Återställ";
-$a->strings["Bookmark added"] = "Bokmärke tillagt";
-$a->strings["My Bookmarks"] = "Mina bokmärken";
-$a->strings["My Connections Bookmarks"] = "Mina kontakters bokmärken";
-$a->strings["This site is not a directory server"] = "Den här servern är inte en katalogserver";
-$a->strings["RedMatrix - Guests: Username: {your email address}, Password: +++"] = "RedMatrix - Gäster: Användarnamn {din e-postadress}, Lösenord: +++";
+$a->strings["Contact not found."] = "Kontakten hittades inte.";
+$a->strings["Friend suggestion sent."] = "Vänförfrågan skickad.";
+$a->strings["Suggest Friends"] = "Föreslå vänner";
+$a->strings["Suggest a friend for %s"] = "Föreslå en vän för %s";
+$a->strings["Permission Denied."] = "Behörighet saknas.";
+$a->strings["File not found."] = "Filen hittas inte.";
+$a->strings["Edit file permissions"] = "Redigera filrättigheter";
+$a->strings["Set/edit permissions"] = "Ställ in/ändra behörigheter";
+$a->strings["Include all files and sub folders"] = "Inkludera alla filer och underkataloger";
+$a->strings["Return to file list"] = "Återgå till fillistan";
+$a->strings["Copy/paste this code to attach file to a post"] = "Kopiera/klistra in den här koden för att bifoga filen i ett inlägg";
+$a->strings["Copy/paste this URL to link file from a web page"] = "Kopiera/klistra in den här URL:en för att länka till filen från en webbsida";
+$a->strings["Continue"] = "Fortsätt";
+$a->strings["Premium Channel Setup"] = "Inställning av premiumkanal";
+$a->strings["Enable premium channel connection restrictions"] = "Aktivera kontaktrestriktioner för premiumkanal";
+$a->strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = "Ange dina restriktioner och villkor, som Paypal-kvitto, användarriktlinjer, etc.";
+$a->strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = "Den här kanalen kan kräva ytterligare steg eller godkännande av följande villkor innan anslutning:";
+$a->strings["Potential connections will then see the following text before proceeding:"] = "Potentiella kontakter kommer sedan att se följande text innan de går vidare:";
+$a->strings["By continuing, I certify that I have complied with any instructions provided on this page."] = "Genom att fortsätta intygar jag att jag har följt alla instruktioner som ges på den här sidan.";
+$a->strings["(No specific instructions have been provided by the channel owner.)"] = "(Inga specifika instruktioner har givits av kanalägaren.)";
+$a->strings["Restricted or Premium Channel"] = "Begränsad kanal eller premiumkanal";
+$a->strings["- select -"] = "- välj -";
+$a->strings["Location not found."] = "Platsen hittades inte.";
+$a->strings["Primary location cannot be removed."] = "Huvudplatsen kan inte tas bort.";
+$a->strings["No locations found."] = "Inga platser hittades.";
+$a->strings["Manage Channel Locations"] = "Hantera kanalplatser";
+$a->strings["Location (address)"] = "Plats (adress)";
+$a->strings["Primary Location"] = "Huvudplats";
+$a->strings["Drop location"] = "Ta bort plats";
+$a->strings["Channel added."] = "Kanal tillagd.";
+$a->strings["Your service plan only allows %d channels."] = "Din tjänstenivå tillåter bara %d kanaler.";
+$a->strings["Nothing to import."] = "Inget att importera.";
+$a->strings["Unable to download data from old server"] = "Kunde inte ladda ner data från den gamla servern";
+$a->strings["Imported file is empty."] = "Den importerade filen är tom.";
+$a->strings["Cannot create a duplicate channel identifier on this system. Import failed."] = "Kan inte skapa ett dubblerat kanal-ID på det här systemet. Import misslyckades.";
+$a->strings["Unable to create a unique channel address. Import failed."] = "Kan inte skapa en unik kanaladress. Import misslyckades.";
+$a->strings["Channel clone failed. Import failed."] = "Kloning av kanalen misslyckades. Import misslyckades.";
+$a->strings["Cloned channel not found. Import failed."] = "Den klonade kanalen hittas inte. Import misslyckades.";
+$a->strings["Import completed."] = "Import slutförd.";
+$a->strings["You must be logged in to use this feature."] = "Du måste vara inloggad för att kunna använda den här funktionen.";
+$a->strings["Import Channel"] = "Importera kanal";
+$a->strings["Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file. Only identity and connections/relationships will be imported. Importation of content is not yet available."] = "Använd det här formuläret för att importera en befintlig kanal från en annan server/hubb. Du kan få kanal-ID:t från den gamla servern/hubben över nätverket eller tillhandahålla en exportfil. Endast identitet och kontakter/relationer kommer att importeras. Import av innehåll stöds ännu inte.";
+$a->strings["File to Upload"] = "Fil att ladda upp";
+$a->strings["Or provide the old server/hub details"] = "Eller ge uppgifter om den gamla servern/hubben";
+$a->strings["Your old identity address (xyz@example.com)"] = "Din gamla identitetsadress (xyz@example.com)";
+$a->strings["Your old login email address"] = "Din gamla e-postadress för inloggning";
+$a->strings["Your old login password"] = "Ditt gamla inloggningslösenord";
+$a->strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = "Ange i bägge fallen om den här hubben ska vara din nya primära adress eller om den gamla platsen ska fortsätta att ha den rollen. Du kommer att kunna posta från båda platser, men bara en kan vara primärt utrymme för filer, foton och media.";
+$a->strings["Make this hub my primary location"] = "Gör den här hubben till min primära plats";
+$a->strings["Import existing posts if possible"] = "Importera befintliga inlägg om möjligt";
+$a->strings["Unable to locate original post."] = "Kunde inte hitta originalinlägget.";
+$a->strings["Empty post discarded."] = "Tomt inlägg förkastat.";
+$a->strings["Executable content type not permitted to this channel."] = "Körbart innehåll tillåts inte i den här kanalen.";
+$a->strings["System error. Post not saved."] = "Systemfel. Inlägget inte sparat.";
+$a->strings["You have reached your limit of %1$.0f top level posts."] = "Du har nått din gräns på %1$.0f toppnivåinlägg.";
+$a->strings["You have reached your limit of %1$.0f webpages."] = "Du har nått din gräns på %1$.0f webbsidor.";
+$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = "Inga förslag tillgängliga. Om det här är en ny server, försök igen om 24 timmar.";
+$a->strings["Help with this feature"] = "Hjälp för den här funktionen";
+$a->strings["Layout Name"] = "Layoutnamn";
+$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s taggade%2\$ss %3\$s med %4\$s";
$a->strings["Profile not found."] = "Profil hittades inte.";
$a->strings["Profile deleted."] = "Profil borttagen.";
$a->strings["Profile-"] = "Profil-";
@@ -1452,113 +1627,6 @@ $a->strings["Age: "] = "Ålder:";
$a->strings["Edit/Manage Profiles"] = "Redigera/hantera profiler";
$a->strings["Add profile things"] = "Lägg till profilsaker";
$a->strings["Include desirable objects in your profile"] = "Inkludera fina prylar i din profil";
-$a->strings["Item not found"] = "Posten hittas inte";
-$a->strings["Edit Block"] = "Redigera block";
-$a->strings["Delete block?"] = "Ta bort block?";
-$a->strings["Insert YouTube video"] = "Infoga Youtube-video";
-$a->strings["Insert Vorbis [.ogg] video"] = "Infoga Vorbis [.ogg]-video";
-$a->strings["Insert Vorbis [.ogg] audio"] = "Infoga Vorbis [.ogg]-ljud";
-$a->strings["Delete Block"] = "Ta bort block";
-$a->strings["Layout updated."] = "Layout uppdaterad.";
-$a->strings["Edit System Page Description"] = "Redigera systemsidbeskrivning";
-$a->strings["Layout not found."] = "Layout hittas inte.";
-$a->strings["Module Name:"] = "Modulnamn:";
-$a->strings["Layout Help"] = "Layouthjälp";
-$a->strings["Edit Layout"] = "Redigera layout";
-$a->strings["Delete layout?"] = "Ta bort layout?";
-$a->strings["Delete Layout"] = "Ta bort layout";
-$a->strings["Item is not editable"] = "Posten går ej att redigera";
-$a->strings["Delete item?"] = "Ta bort posten?";
-$a->strings["Edit Webpage"] = "Redigera webbsida";
-$a->strings["Delete webpage?"] = "Ta bort webbsida?";
-$a->strings["Delete Webpage"] = "Ta bort webbsida";
-$a->strings["webpage"] = "webbsida";
-$a->strings["block"] = "block";
-$a->strings["layout"] = "layout";
-$a->strings["%s element installed"] = "%selement installerat";
-$a->strings["Image uploaded but image cropping failed."] = "Bilden laddades upp men beskärning misslyckades.";
-$a->strings["Image resize failed."] = "Ändring av bildstorlek misslyckades.";
-$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = "Shift-uppdatera sidan eller rensa webbläsarcachen om det nya fotot inte visas direkt.";
-$a->strings["Image exceeds size limit of %d"] = "Bilden överskrider storleksbegränsningen %d";
-$a->strings["Unable to process image."] = "Kunde inte behandla bilden.";
-$a->strings["Photo not available."] = "Fotot är inte tillgängligt.";
-$a->strings["Upload File:"] = "Ladda upp fil:";
-$a->strings["Select a profile:"] = "Välj en profil:";
-$a->strings["Upload Profile Photo"] = "Ladda upp profilfoto";
-$a->strings["skip this step"] = "hoppa över det här steget";
-$a->strings["select a photo from your photo albums"] = "välj ett foto från dina fotoalbum";
-$a->strings["Crop Image"] = "Beskär bild";
-$a->strings["Please adjust the image cropping for optimum viewing."] = "Justera bildens beskärning för bästa utseende.";
-$a->strings["Done Editing"] = "Klar med redigering";
-$a->strings["Image uploaded successfully."] = "Bilduppladdning lyckades.";
-$a->strings["Image upload failed."] = "Bilduppladdning misslyckades.";
-$a->strings["Image size reduction [%s] failed."] = "Krympning av bilden [%s] misslyckades.";
-$a->strings["Unable to locate original post."] = "Kunde inte hitta originalinlägget.";
-$a->strings["Empty post discarded."] = "Tomt inlägg förkastat.";
-$a->strings["Executable content type not permitted to this channel."] = "Körbart innehåll tillåts inte i den här kanalen.";
-$a->strings["System error. Post not saved."] = "Systemfel. Inlägget inte sparat.";
-$a->strings["You have reached your limit of %1$.0f top level posts."] = "Du har nått din gräns på %1$.0f toppnivåinlägg.";
-$a->strings["You have reached your limit of %1$.0f webpages."] = "Du har nått din gräns på %1$.0f webbsidor.";
-$a->strings["Contact not found."] = "Kontakten hittades inte.";
-$a->strings["Friend suggestion sent."] = "Vänförfrågan skickad.";
-$a->strings["Suggest Friends"] = "Föreslå vänner";
-$a->strings["Suggest a friend for %s"] = "Föreslå en vän för %s";
-$a->strings["Permission Denied."] = "Behörighet saknas.";
-$a->strings["File not found."] = "Filen hittas inte.";
-$a->strings["Edit file permissions"] = "Redigera filrättigheter";
-$a->strings["Set/edit permissions"] = "Ställ in/ändra behörigheter";
-$a->strings["Include all files and sub folders"] = "Inkludera alla filer och underkataloger";
-$a->strings["Return to file list"] = "Återgå till fillistan";
-$a->strings["Copy/paste this code to attach file to a post"] = "Kopiera/klistra in den här koden för att bifoga filen i ett inlägg";
-$a->strings["Copy/paste this URL to link file from a web page"] = "Kopiera/klistra in den här URL:en för att länka till filen från en webbsida";
-$a->strings["Help:"] = "Hjälp:";
-$a->strings["Not Found"] = "Hittas inte";
-$a->strings["network"] = "nätverk";
-$a->strings["No potential page delegates located."] = "Inga potentiella sid-ombud funna.";
-$a->strings["Delegate Page Management"] = "Delegera sidhantering";
-$a->strings["Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely."] = "Ombud kan hantera alla aspekter av det här kontot/den här sidan förutom grundläggande kontoinställningar. Delegera inte ditt personliga konto till någon som du inte litar fullständigt på.";
-$a->strings["Existing Page Managers"] = "Befintliga sid-ansvariga";
-$a->strings["Existing Page Delegates"] = "Befintliga sid-ombud";
-$a->strings["Potential Delegates"] = "Potentiella ombud";
-$a->strings["Remove"] = "Ta bort";
-$a->strings["Add"] = "Lägg till";
-$a->strings["No entries."] = "Inga poster.";
-$a->strings["Channel added."] = "Kanal tillagd.";
-$a->strings["Collection created."] = "Krets skapad.";
-$a->strings["Could not create collection."] = "Kunde inte skapa krets.";
-$a->strings["Collection updated."] = "Kretsen uppdaterad.";
-$a->strings["Create a collection of channels."] = "Skapa en krets av kanaler.";
-$a->strings["Collection Name: "] = "Namn på krets: ";
-$a->strings["Members are visible to other channels"] = "Medlemmar kan ses av andra kanaler";
-$a->strings["Collection removed."] = "Krets borttagen.";
-$a->strings["Unable to remove collection."] = "Kunde inte ta bort krets.";
-$a->strings["Collection Editor"] = "Redigera krets";
-$a->strings["Members"] = "Medlemmar";
-$a->strings["All Connected Channels"] = "Alla anslutna kanaler";
-$a->strings["Click on a channel to add or remove."] = "Klicka på en kanal för att lägga till eller ta bort.";
-$a->strings["Red Matrix - &quot;The Network&quot;"] = "Red Matrix - &quot;Nätverket&quot;";
-$a->strings["Welcome to %s"] = "Välkommen till %s";
-$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = "Inga förslag tillgängliga. Om det här är en ny server, försök igen om 24 timmar.";
-$a->strings["Your service plan only allows %d channels."] = "Din tjänstenivå tillåter bara %d kanaler.";
-$a->strings["Nothing to import."] = "Inget att importera.";
-$a->strings["Unable to download data from old server"] = "Kunde inte ladda ner data från den gamla servern";
-$a->strings["Imported file is empty."] = "Den importerade filen är tom.";
-$a->strings["Cannot create a duplicate channel identifier on this system. Import failed."] = "Kan inte skapa ett dubblerat kanal-ID på det här systemet. Import misslyckades.";
-$a->strings["Channel clone failed. Import failed."] = "Kloning av kanalen misslyckades. Import misslyckades.";
-$a->strings["Cloned channel not found. Import failed."] = "Den klonade kanalen hittas inte. Import misslyckades.";
-$a->strings["Import completed."] = "Import slutförd.";
-$a->strings["You must be logged in to use this feature."] = "Du måste vara inloggad för att kunna använda den här funktionen.";
-$a->strings["Import Channel"] = "Importera kanal";
-$a->strings["Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file. Only identity and connections/relationships will be imported. Importation of content is not yet available."] = "Använd det här formuläret för att importera en befintlig kanal från en annan server/hubb. Du kan få kanal-ID:t från den gamla servern/hubben över nätverket eller tillhandahålla en exportfil. Endast identitet och kontakter/relationer kommer att importeras. Import av innehåll stöds ännu inte.";
-$a->strings["File to Upload"] = "Fil att ladda upp";
-$a->strings["Or provide the old server/hub details"] = "Eller ge uppgifter om den gamla servern/hubben";
-$a->strings["Your old identity address (xyz@example.com)"] = "Din gamla identitetsadress (xyz@example.com)";
-$a->strings["Your old login email address"] = "Din gamla e-postadress för inloggning";
-$a->strings["Your old login password"] = "Ditt gamla inloggningslösenord";
-$a->strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = "Ange i bägge fallen om den här hubben ska vara din nya primära adress eller om den gamla platsen ska fortsätta att ha den rollen. Du kommer att kunna posta från båda platser, men bara en kan vara primärt utrymme för filer, foton och media.";
-$a->strings["Make this hub my primary location"] = "Gör den här hubben till min primära plats";
-$a->strings["Import existing posts if possible"] = "Importera befintliga inlägg om möjligt";
-$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s taggade%2\$ss %3\$s med %4\$s";
$a->strings["Tag removed"] = "Tagg borttagen";
$a->strings["Remove Item Tag"] = "Ta bort innehållstagg";
$a->strings["Select a tag to remove: "] = "Välj en tagg att ta bort: ";
@@ -1582,7 +1650,6 @@ $a->strings["Pending registrations"] = "Pågående registreringar";
$a->strings["Version"] = "Version";
$a->strings["Active plugins"] = "Aktiva tillägg";
$a->strings["Site settings updated."] = "Serverinställningar uppdaterade.";
-$a->strings["mobile"] = "mobilt";
$a->strings["experimental"] = "experimentellt";
$a->strings["unsupported"] = "stöds ej";
$a->strings["Yes - with approval"] = "Ja - med godkännande";
@@ -1719,32 +1786,34 @@ $a->strings["Help text"] = "Hjälptext";
$a->strings["Additional info (optional)"] = "Ytterligare info (frivilligt)";
$a->strings["Field definition not found"] = "Fältdefinition hittades inte";
$a->strings["Edit Profile Field"] = "Redigera profilfält";
-$a->strings["Location not found."] = "Platsen hittades inte.";
-$a->strings["Primary location cannot be removed."] = "Huvudplatsen kan inte tas bort.";
-$a->strings["No locations found."] = "Inga platser hittades.";
-$a->strings["Manage Channel Locations"] = "Hantera kanalplatser";
-$a->strings["Location (address)"] = "Plats (adress)";
-$a->strings["Primary Location"] = "Huvudplats";
-$a->strings["Drop location"] = "Ta bort plats";
-$a->strings["Unable to lookup recipient."] = "Kunde inte hitta mottagare.";
-$a->strings["Unable to communicate with requested channel."] = "Kunde inte kommunicera med den begärda kanalen.";
-$a->strings["Cannot verify requested channel."] = "Kan inte bekräfta den begärda kanalen.";
-$a->strings["Selected channel has private message restrictions. Send failed."] = "Den valda kanalen har restriktioner för privata meddelanden. Misslyckades att skicka.";
-$a->strings["Message deleted."] = "Meddelande borttaget.";
-$a->strings["Message recalled."] = "Meddelande återkallat.";
-$a->strings["Send Private Message"] = "Skicka privat meddelande.";
-$a->strings["To:"] = "Till:";
-$a->strings["Subject:"] = "Ämne:";
-$a->strings["Your message:"] = "Ditt meddelande:";
-$a->strings["Send"] = "Skicka";
-$a->strings["Message not found."] = "Meddelandet hittades inte.";
-$a->strings["Delete message"] = "Ta bort meddelande";
-$a->strings["Recall message"] = "Återkalla meddelande";
-$a->strings["Message has been recalled."] = "Meddelandet har återkallats.";
-$a->strings["Private Conversation"] = "Privat konversation";
-$a->strings["Delete conversation"] = "Ta bort konversation";
-$a->strings["No secure communications available. You <strong>may</strong> be able to respond from the sender's profile page."] = "Ingen säker kommunikationskanal tillgänglig. Du kan <strong>möjligtvis</strong> svara från avsändarens profilsida.";
-$a->strings["Send Reply"] = "Skicka svar";
+$a->strings["You have created %1$.0f of %2$.0f allowed channels."] = "Du har skapat %1$.0f av %2$.0f tillåtna kanaler.";
+$a->strings["Create a new channel"] = "Skapa en ny kanal";
+$a->strings["Current Channel"] = "Nuvarande kanal";
+$a->strings["Attach to one of your channels by selecting it."] = "Anslut till en av dina kanaler genom att välja den.";
+$a->strings["Default Channel"] = "Standardkanal";
+$a->strings["Make Default"] = "Gör till standard";
+$a->strings["Menu updated."] = "Meny uppdaterad.";
+$a->strings["Unable to update menu."] = "Kunde inte uppdatera meny.";
+$a->strings["Menu created."] = "Meny skapad.";
+$a->strings["Unable to create menu."] = "Kunde inte skapa meny.";
+$a->strings["Manage Menus"] = "Hantera menyer";
+$a->strings["Drop"] = "Ta bort";
+$a->strings["Bookmarks allowed"] = "Bokmärken tillåtna";
+$a->strings["Create a new menu"] = "Skapa en ny meny";
+$a->strings["Delete this menu"] = "Ta bort den här menyn";
+$a->strings["Edit menu contents"] = "Redigera menyinnehåll";
+$a->strings["Edit this menu"] = "Redigera den här menyn";
+$a->strings["New Menu"] = "Ny meny";
+$a->strings["Menu name"] = "Menynamn";
+$a->strings["Must be unique, only seen by you"] = "Måste vara unikt, ses endast av dig";
+$a->strings["Menu title"] = "Menytitel";
+$a->strings["Menu title as seen by others"] = "Menytitel som andra ser den";
+$a->strings["Allow bookmarks"] = "Tillåt bokmärken";
+$a->strings["Menu may be used to store saved bookmarks"] = "Menyn kan användas för att spara bokmärken";
+$a->strings["Menu deleted."] = "Meny borttagen.";
+$a->strings["Menu could not be deleted."] = "Menyn kunde inte tas bort.";
+$a->strings["Edit Menu"] = "Redigera meny";
+$a->strings["Add or remove entries to this menu"] = "Lägg till eller ta bort menyval";
$a->strings["Total invitation limit exceeded."] = "Gränsen för totalt antal inbjudningar överskriden.";
$a->strings["%s : Not a valid email address."] = "%s: Inte en giltig e-postadress.";
$a->strings["Please join us on Red"] = "Gå med oss i Red";
@@ -1763,15 +1832,17 @@ $a->strings["1. Register at any RedMatrix location (they are all inter-connected
$a->strings["2. Enter my RedMatrix network address into the site searchbar."] = "2. Ange min RedMatrix-adress i webbplatsens sökruta.";
$a->strings["or visit "] = "eller besök ";
$a->strings["3. Click [Connect]"] = "3. Klicka [Ta kontakt]";
-$a->strings["You have created %1$.0f of %2$.0f allowed channels."] = "Du har skapat %1$.0f av %2$.0f tillåtna kanaler.";
-$a->strings["Create a new channel"] = "Skapa en ny kanal";
-$a->strings["Current Channel"] = "Nuvarande kanal";
-$a->strings["Attach to one of your channels by selecting it."] = "Anslut till en av dina kanaler genom att välja den.";
-$a->strings["Default Channel"] = "Standardkanal";
-$a->strings["Make Default"] = "Gör till standard";
+$a->strings["No such group"] = "Ingen sådan grupp";
+$a->strings["Search Results For:"] = "Sökresultat för:";
+$a->strings["Collection is empty"] = "Kretsen är tom";
+$a->strings["Collection: "] = "Krets: ";
+$a->strings["Connection: "] = "Kontakt:";
+$a->strings["Invalid connection."] = "Ogiltig kontakt.";
+$a->strings["Invalid request identifier."] = "Ogiltigt ID på förfrågan.";
+$a->strings["Discard"] = "Förkasta";
+$a->strings["No more system notifications."] = "Inga fler systemnotifieringar.";
+$a->strings["System Notifications"] = "Systemnotifieringar";
$a->strings["[Embedded content - reload page to view]"] = "[Inbäddat innehåll - ladda om sidan för att visa]";
-$a->strings["Help with this feature"] = "Hjälp för den här funktionen";
-$a->strings["Layout Name"] = "Layoutnamn";
$a->strings["Remote privacy information not available."] = "Icke-lokal integritetsinformation är inte tillgänglig";
$a->strings["Visible to:"] = "Kan ses av:";
$a->strings["No connections."] = "Inga kontakter.";
@@ -1780,39 +1851,13 @@ $a->strings["View Connnections"] = "Visa kontakter";
$a->strings["Hub not found."] = "Hubb hittades inte.";
$a->strings["Total votes"] = "Totalt antal röster";
$a->strings["Average Rating"] = "Genomsnittsbetyg";
-$a->strings["No such group"] = "Ingen sådan grupp";
-$a->strings["Search Results For:"] = "Sökresultat för:";
-$a->strings["Collection is empty"] = "Kretsen är tom";
-$a->strings["Collection: "] = "Krets: ";
-$a->strings["Connection: "] = "Kontakt:";
-$a->strings["Invalid connection."] = "Ogiltig kontakt.";
+$a->strings["OpenID protocol error. No ID returned."] = "Protokollfel för OpenID. Inget ID returnerades.";
+$a->strings["Welcome %s. Remote authentication successful."] = "Välkommen %s. Fjärrinloggning lyckades.";
$a->strings["Wall Photos"] = "Väggfoton";
$a->strings["Profile Match"] = "Profilträff";
$a->strings["No keywords to match. Please add keywords to your default profile."] = "Inga nyckelord att matcha mot. Lägg till några nyckelord i din standardprofil.";
$a->strings["is interested in:"] = "är intresserad av:";
$a->strings["No matches"] = "Inga träffar";
-$a->strings["Menu updated."] = "Meny uppdaterad.";
-$a->strings["Unable to update menu."] = "Kunde inte uppdatera meny.";
-$a->strings["Menu created."] = "Meny skapad.";
-$a->strings["Unable to create menu."] = "Kunde inte skapa meny.";
-$a->strings["Manage Menus"] = "Hantera menyer";
-$a->strings["Drop"] = "Ta bort";
-$a->strings["Bookmarks allowed"] = "Bokmärken tillåtna";
-$a->strings["Create a new menu"] = "Skapa en ny meny";
-$a->strings["Delete this menu"] = "Ta bort den här menyn";
-$a->strings["Edit menu contents"] = "Redigera menyinnehåll";
-$a->strings["Edit this menu"] = "Redigera den här menyn";
-$a->strings["New Menu"] = "Ny meny";
-$a->strings["Menu name"] = "Menynamn";
-$a->strings["Must be unique, only seen by you"] = "Måste vara unikt, ses endast av dig";
-$a->strings["Menu title"] = "Menytitel";
-$a->strings["Menu title as seen by others"] = "Menytitel som andra ser den";
-$a->strings["Allow bookmarks"] = "Tillåt bokmärken";
-$a->strings["Menu may be used to store saved bookmarks"] = "Menyn kan användas för att spara bokmärken";
-$a->strings["Menu deleted."] = "Meny borttagen.";
-$a->strings["Menu could not be deleted."] = "Menyn kunde inte tas bort.";
-$a->strings["Edit Menu"] = "Redigera meny";
-$a->strings["Add or remove entries to this menu"] = "Lägg till eller ta bort menyval";
$a->strings["Conversation removed."] = "Konversation borttagen.";
$a->strings["No messages."] = "Inga meddelanden.";
$a->strings["D, d M Y - g:i A"] = "D, j M Y - H:i";
@@ -1823,11 +1868,9 @@ $a->strings["Choose a short nickname"] = "Välj ett kort smeknamn";
$a->strings["Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others."] = "Ditt smeknamn används för att skapa en kanaladress som är lätt att komma ihåg (som en e-postadress) som du kan dela med andra.";
$a->strings["Or <a href=\"import\">import an existing channel</a> from another location"] = "Eller <a href=\"import\">importera en befintlig kanal</a> från en annan plats";
$a->strings["Channel Type"] = "Kanaltyp";
+$a->strings["?"] = "?";
+$a->strings["What is this?"] = "Vad är detta?";
$a->strings["Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you"] = "Välj en kanaltyp (som till exempel socialt nätverkande eller gemenskapsforum) och integritetskrav, så kan vi välja de bästa behörigheterna åt dig";
-$a->strings["Invalid request identifier."] = "Ogiltigt ID på förfrågan.";
-$a->strings["Discard"] = "Förkasta";
-$a->strings["No more system notifications."] = "Inga fler systemnotifieringar.";
-$a->strings["System Notifications"] = "Systemnotifieringar";
$a->strings["Xchan Lookup"] = "Xchan-sökning";
$a->strings["Lookup xchan beginning with (or webbie): "] = "Sök efter xchan som börjar med (eller webbie): ";
$a->strings["invalid target signature"] = "ogiltig målsignatur";
@@ -1844,42 +1887,7 @@ $a->strings["Finding:"] = "Sökning efter:";
$a->strings["next page"] = "nästa sida";
$a->strings["previous page"] = "föregående sida";
$a->strings["No entries (some entries may be hidden)."] = "Inga resultat (vissa resultat kan vara dolda).";
-$a->strings["Page owner information could not be retrieved."] = "Information om sidans ägare kunde inte hittas.";
-$a->strings["Album not found."] = "Albumet hittades inte.";
-$a->strings["Delete Album"] = "Ta bort album";
-$a->strings["Delete Photo"] = "Ta bort foto";
-$a->strings["No photos selected"] = "Inga foton valda";
-$a->strings["Access to this item is restricted."] = "Åtkomst till den här posten är begränsat.";
-$a->strings["%1$.2f MB of %2$.2f MB photo storage used."] = "%1$.2f MB av %2$.2f MB fotolagring använt.";
-$a->strings["%1$.2f MB photo storage used."] = "%1$.2f MB fotolagring använt.";
-$a->strings["Upload Photos"] = "Ladda upp foton";
-$a->strings["Enter a new album name"] = "Ange ett nytt albumnamn";
-$a->strings["or select an existing one (doubleclick)"] = "eller välj ett befintligt (dubbelklicka)";
-$a->strings["Do not show a status post for this upload"] = "Visa inte en statusuppdatering för den här uppladdningen";
-$a->strings["Album name could not be decoded"] = "Albumnamn kunde inte tolkas";
-$a->strings["Contact Photos"] = "Kontaktfoton";
-$a->strings["Show Newest First"] = "Visa nyast först";
-$a->strings["Show Oldest First"] = "Visa äldst först";
-$a->strings["View Photo"] = "Visa foto";
-$a->strings["Edit Album"] = "Redigera album";
-$a->strings["Permission denied. Access to this item may be restricted."] = "Behörighet saknas. Åtkomst till den här posten kan vara begränsat.";
-$a->strings["Photo not available"] = "Foto inte tillgängligt";
-$a->strings["Use as profile photo"] = "Använd som profilfoto";
-$a->strings["Private Photo"] = "Privat foto";
-$a->strings["View Full Size"] = "Visa fullstorlek";
-$a->strings["Edit photo"] = "Redigera foto";
-$a->strings["Rotate CW (right)"] = "Rotera medurs (höger)";
-$a->strings["Rotate CCW (left)"] = "Rotera moturs (vänster)";
-$a->strings["Caption"] = "Bildtext";
-$a->strings["Add a Tag"] = "Lägg till en tagg";
-$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com"] = "Exempel: @bob, @Barbara_Jensen, @jim@example.com";
-$a->strings["Flag as adult in album view"] = "Flagga som olämpligt för barn i albumvyn";
-$a->strings["In This Photo:"] = "På fotot:";
-$a->strings["View Album"] = "Visa album";
-$a->strings["Recent Photos"] = "Nya foton";
-$a->strings["sent you a private message"] = "skickade ett privat meddelande till dig";
-$a->strings["added your channel"] = "lade till din kanal";
-$a->strings["posted an event"] = "skapade en händelse";
+$a->strings["Remote authentication blocked. You are logged into this site locally. Please logout and retry."] = "Fjärrinloggning blockerades. Du är inloggad på den här servern lokalt. Logga ut och försök igen.";
$a->strings["App installed."] = "App installerad.";
$a->strings["Malformed app."] = "Felaktig app.";
$a->strings["Embed code"] = "Bädda in kod";
diff --git a/view/theme/redbasic/css/style.css b/view/theme/redbasic/css/style.css
index 60760509d..61acc8ec7 100644
--- a/view/theme/redbasic/css/style.css
+++ b/view/theme/redbasic/css/style.css
@@ -301,14 +301,14 @@ footer {
#main-login #id_remember {
float: left;
padding: 0;
- margin-top: 15px;
margin-bottom: 0;
margin-left: 0;
width: 20px;
}
-#main-login .field.checkbox label {
- margin-top: 15px;
+/* first-of-type needed to style switches */
+#main-login .field.checkbox label.mainlabel,
+#main-login .field.checkbox label:first-of-type {
margin-bottom: 0;
float: left;
width: 100px;
@@ -373,13 +373,16 @@ footer {
font-weight: bold;
}
-#profile-edit-wrapper .field label {
+#profile-edit-wrapper .field {
margin-top: 20px;
+}
+/* first-of-type needed to style switches */
+#profile-edit-wrapper .field label.mainlabel,
+#profile-edit-wrapper .field label:first-of-type {
width: 175px;
}
#profile-edit-wrapper .field input[type="text"] {
- margin-top: 20px;
width: 220px;
}
@@ -1242,7 +1245,9 @@ footer {
width: 100%
}
-.field label {
+/* first-of-type needed to style switches */
+.field label.mainlabel,
+.field label:first-of-type {
float: left;
width: 350px;
}
@@ -1296,6 +1301,8 @@ footer {
.hidden { display: none!important; }
.field.radio .field_help { margin-left: 0px; }
+.field.checkbox .field_help { display: inline; margin-left: 10px; }
+
/**
* OAuth
@@ -2350,3 +2357,70 @@ aside .nav > li > a:hover, aside .nav > li > a:focus {
.jothidden .bootstrap-tagsinput:hover, .jothidden .bootstrap-tagsinput:focus {
border: 1px solid #cccccc;
}
+
+/* Hide the placeholder label which is used for styling switches */
+/* Many places give a width to all labels, so need to specifically set these to 0 width */
+/* This should probably be moved to core */
+.field.checkbox label.switchlabel,
+.field.checkbox label:nth-of-type(2) {
+ width: 0px;
+ margin: 0px;
+ float: none;
+}
+
+/* Turn checkboxes into switches */
+/* Doesn't work with IE<9. */
+.field.checkbox input {
+ position: absolute;
+ margin-left: -9999px;
+ visibility: hidden;
+}
+.field.checkbox input + label.switchlabel,
+.field.checkbox input + label:nth-of-type(2) {
+ display: block;
+ position: relative;
+ cursor: pointer;
+ outline: none;
+ user-select: none;
+
+ padding: 2px;
+ width: 60px;
+ height: 24px;
+ background-color: #dddddd;
+ border-radius: 60px;
+ transition: background 0.4s;
+
+ float:left;
+}
+
+.field.checkbox input + label:before,
+.field.checkbox input + label:after {
+ display: block;
+ position: absolute;
+ content: "";
+}
+.field.checkbox input + label:before {
+ top: 2px;
+ left: 2px;
+ bottom: 2px;
+ right: 2px;
+ background-color: #fff;
+ border-radius: 30px;
+ transition: background 0.4s;
+}
+.field.checkbox input + label:after {
+ top: 4px;
+ left: 4px;
+ bottom: 4px;
+ width: 30px;
+ background-color: #dddddd;
+ border-radius: 30px;
+ transition: margin 0.4s, background 0.4s;
+}
+.field.checkbox input:checked + label {
+ background-color: #8ce196;
+}
+.field.checkbox input:checked + label:after {
+ margin-left: 22px;
+ background-color: #8ce196;
+}
diff --git a/view/tpl/event_head.tpl b/view/tpl/event_head.tpl
index bcb1e07f6..03ea833f9 100755
--- a/view/tpl/event_head.tpl
+++ b/view/tpl/event_head.tpl
@@ -24,6 +24,11 @@
eventClick: function(calEvent, jsEvent, view) {
showEvent(calEvent.id);
},
+ loading: function(isLoading, view) {
+ if(!isLoading) {
+ $('td.fc-day').dblclick(function() { window.location.href='https://caterva.eu/events/new?start='+$(this).data('date'); });
+ }
+ },
eventRender: function(event, element, view) {
//console.log(view.name);
diff --git a/view/tpl/field_acheckbox.tpl b/view/tpl/field_acheckbox.tpl
index 89de170b7..816af2a65 100755
--- a/view/tpl/field_acheckbox.tpl
+++ b/view/tpl/field_acheckbox.tpl
@@ -1,6 +1,6 @@
<tr>
<td>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
</td>
<td class="abook-them">
<input type="checkbox" name='them_{{$field.0}}' id='them_id_{{$field.0}}' value="1" disabled="disabled" {{if $field.2}}checked="checked"{{/if}} />
diff --git a/view/tpl/field_checkbox.tpl b/view/tpl/field_checkbox.tpl
index 51d56f69c..5c7f58ad1 100755
--- a/view/tpl/field_checkbox.tpl
+++ b/view/tpl/field_checkbox.tpl
@@ -1,5 +1,4 @@
<div class='field checkbox'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
- <input type="checkbox" name='{{$field.0}}' id='id_{{$field.0}}' value="1" {{if $field.2}}checked="checked"{{/if}}>
- <span class='field_help'>{{$field.3}}</span>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
+ <input type="checkbox" name='{{$field.0}}' id='id_{{$field.0}}' value="1" {{if $field.2}}checked="checked"{{/if}}><label class="switchlabel" for='id_{{$field.0}}'></label><span class='field_help'>{{$field.3}}</span>
</div>
diff --git a/view/tpl/field_colorinput.tpl b/view/tpl/field_colorinput.tpl
index a68781698..a1e912186 100644
--- a/view/tpl/field_colorinput.tpl
+++ b/view/tpl/field_colorinput.tpl
@@ -1,5 +1,5 @@
<div class='field input color'>
- <label for='id_{{$field.0}}' id='label_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}' id='label_{{$field.0}}'>{{$field.1}}</label>
<input class='color' name='{{$field.0}}' id='id_{{$field.0}}' type="text" value="{{$field.2}}">{{if $field.4}} <span class="required">{{$field.4}}</span> {{/if}}
<span id='help_{{$field.0}}' class='field_help'>{{$field.3}}</span>
<div id='end_{{$field.0}}' class='field_end'></div>
diff --git a/view/tpl/field_combobox.tpl b/view/tpl/field_combobox.tpl
index 1f9218954..337c60673 100755
--- a/view/tpl/field_combobox.tpl
+++ b/view/tpl/field_combobox.tpl
@@ -1,5 +1,5 @@
<div class='field combobox'>
- <label for='id_{{$field.0}}' id='id_{{$field.0}}_label'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}' id='id_{{$field.0}}_label'>{{$field.1}}</label>
{{* html5 don't work on Chrome, Safari and IE9 see https://github.com/thgreasi/datalist-polyfill
<input id="id_{{$field.0}}" type="text" list="data_{{$field.0}}" >
<datalist id="data_{{$field.0}}" >
diff --git a/view/tpl/field_custom.tpl b/view/tpl/field_custom.tpl
index a6b49f6da..754f5b2f4 100755
--- a/view/tpl/field_custom.tpl
+++ b/view/tpl/field_custom.tpl
@@ -1,5 +1,5 @@
<div class='field custom'>
- <label for='{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='{{$field.0}}'>{{$field.1}}</label>
{{$field.2}}
<span class='field_help'>{{$field.3}}</span>
</div>
diff --git a/view/tpl/field_input.tpl b/view/tpl/field_input.tpl
index a584f95e7..be6e3f047 100755
--- a/view/tpl/field_input.tpl
+++ b/view/tpl/field_input.tpl
@@ -1,5 +1,5 @@
<div class='field input'>
- <label for='id_{{$field.0}}' id='label_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}' id='label_{{$field.0}}'>{{$field.1}}</label>
<input name='{{$field.0}}' id='id_{{$field.0}}' type="text" value="{{$field.2}}">{{if $field.4}} <span class="required">{{$field.4}}</span> {{/if}}
<span id='help_{{$field.0}}' class='field_help'>{{$field.3}}</span>
<div id='end_{{$field.0}}' class='field_end'></div>
diff --git a/view/tpl/field_intcheckbox.tpl b/view/tpl/field_intcheckbox.tpl
index d9a8d7289..1d0bd9175 100755
--- a/view/tpl/field_intcheckbox.tpl
+++ b/view/tpl/field_intcheckbox.tpl
@@ -1,5 +1,4 @@
<div class='field checkbox'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
- <input type="checkbox" name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.3}}" {{if $field.2}}checked="true"{{/if}}>
- <span class='field_help'>{{$field.4}}</span>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
+ <input type="checkbox" name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.3}}" {{if $field.2}}checked="true"{{/if}}><label class="switchlabel" for='id_{{$field.0}}'></label><span class='field_help'>{{$field.4}}</span>
</div>
diff --git a/view/tpl/field_password.tpl b/view/tpl/field_password.tpl
index 23058f8a6..38ecf3d07 100755
--- a/view/tpl/field_password.tpl
+++ b/view/tpl/field_password.tpl
@@ -1,5 +1,5 @@
<div class='field password'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
<input type='password' name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.2}}">
<span class='field_help'>{{$field.3}}</span>
</div>
diff --git a/view/tpl/field_radio.tpl b/view/tpl/field_radio.tpl
index 147b6b834..a92324cad 100755
--- a/view/tpl/field_radio.tpl
+++ b/view/tpl/field_radio.tpl
@@ -1,5 +1,5 @@
<div class='field radio'>
- <label for='id_{{$field.0}}_{{$field.2}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}_{{$field.2}}'>{{$field.1}}</label>
<input type="radio" name='{{$field.0}}' id='id_{{$field.0}}_{{$field.2}}' value="{{$field.2}}" {{if $field.4}}checked="true"{{/if}}>
<span class='field_help'>{{$field.3}}</span>
</div>
diff --git a/view/tpl/field_richtext.tpl b/view/tpl/field_richtext.tpl
index c8639cf10..378e02a62 100755
--- a/view/tpl/field_richtext.tpl
+++ b/view/tpl/field_richtext.tpl
@@ -1,5 +1,5 @@
<div class='field richtext'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
<textarea name='{{$field.0}}' id='id_{{$field.0}}' class="fieldRichtext">{{$field.2}}</textarea>
<span class='field_help'>{{$field.3}}</span>
</div>
diff --git a/view/tpl/field_select.tpl b/view/tpl/field_select.tpl
index 9aca26e7b..95d1855d6 100755
--- a/view/tpl/field_select.tpl
+++ b/view/tpl/field_select.tpl
@@ -1,5 +1,5 @@
<div class='field select'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
<select name='{{$field.0}}' id='id_{{$field.0}}'>
{{foreach $field.4 as $opt=>$val}}<option value="{{$opt}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
</select>
diff --git a/view/tpl/field_select_disabled.tpl b/view/tpl/field_select_disabled.tpl
index f0090cf98..e241be895 100644
--- a/view/tpl/field_select_disabled.tpl
+++ b/view/tpl/field_select_disabled.tpl
@@ -1,5 +1,5 @@
<div class='field select'>
- <label style="font-weight: normal;" for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" style="font-weight: normal;" for='id_{{$field.0}}'>{{$field.1}}</label>
<select disabled="true" name='{{$field.0}}' id='id_{{$field.0}}'>
{{foreach $field.4 as $opt=>$val}}<option value="{{$opt}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
</select>
diff --git a/view/tpl/field_select_grouped.tpl b/view/tpl/field_select_grouped.tpl
new file mode 100644
index 000000000..c7fb4f322
--- /dev/null
+++ b/view/tpl/field_select_grouped.tpl
@@ -0,0 +1,12 @@
+ <div class='field select'>
+ <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <select name='{{$field.0}}' id='id_{{$field.0}}'>
+ {{foreach $field.4 as $group=>$opts}}
+ <optgroup label='{{$group}}'>
+ {{foreach $opts as $opt=>$val}}
+ <option value="{{$opt}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
+ {{/foreach}}
+ </optgroup>
+ </select>
+ <span class='field_help'>{{$field.3}}</span>
+ </div>
diff --git a/view/tpl/field_select_raw.tpl b/view/tpl/field_select_raw.tpl
index 861be3201..74d575bd0 100755
--- a/view/tpl/field_select_raw.tpl
+++ b/view/tpl/field_select_raw.tpl
@@ -1,5 +1,5 @@
<div class='field select'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
<select name='{{$field.0}}' id='id_{{$field.0}}'>
{{$field.4}}
</select>
diff --git a/view/tpl/field_textarea.tpl b/view/tpl/field_textarea.tpl
index b454045c0..dad89a145 100755
--- a/view/tpl/field_textarea.tpl
+++ b/view/tpl/field_textarea.tpl
@@ -1,5 +1,5 @@
<div class='field textarea'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
<textarea name='{{$field.0}}' id='id_{{$field.0}}' {{if $field.4}}{{$field.4}}{{/if}} >{{$field.2}}</textarea>
<span class='field_help'>{{$field.3}}</span>
</div>
diff --git a/view/tpl/field_themeselect.tpl b/view/tpl/field_themeselect.tpl
index a0e454bf5..120727478 100755
--- a/view/tpl/field_themeselect.tpl
+++ b/view/tpl/field_themeselect.tpl
@@ -1,6 +1,6 @@
<script>$(document).ready(function(){ previewTheme($("#id_{{$field.0}}")[0]); });</script>
<div class='field select'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
<select name='{{$field.0}}' id='id_{{$field.0}}' {{if $field.5=='preview'}}onchange="previewTheme(this);"{{/if}} >
{{foreach $field.4 as $opt=>$val}}<option value="{{$opt}}" {{if $opt==$field.2}}selected="selected"{{/if}}>{{$val}}</option>{{/foreach}}
</select>
diff --git a/view/tpl/field_yesno.tpl b/view/tpl/field_yesno.tpl
index e36e775c7..f5a909833 100755
--- a/view/tpl/field_yesno.tpl
+++ b/view/tpl/field_yesno.tpl
@@ -1,5 +1,5 @@
<div class='field yesno'>
- <label for='id_{{$field.0}}'>{{$field.1}}</label>
+ <label class="mainlabel" for='id_{{$field.0}}'>{{$field.1}}</label>
<div class='onoff' id="id_{{$field.0}}_onoff">
<input type="hidden" name='{{$field.0}}' id='id_{{$field.0}}' value="{{$field.2}}">
<a href="#" class='off'>
diff --git a/view/tpl/install_settings.tpl b/view/tpl/install_settings.tpl
index f4fd82fdb..62dcbb8b3 100755
--- a/view/tpl/install_settings.tpl
+++ b/view/tpl/install_settings.tpl
@@ -20,7 +20,7 @@
{{include file="field_input.tpl" field=$adminmail}}
{{include file="field_input.tpl" field=$siteurl}}
-{{$timezone}}
+{{include file="field_select_grouped.tpl" field=$timezone}}
<input id="install-submit" type="submit" name="submit" value="{{$submit}}" />
diff --git a/view/tpl/new_channel.tpl b/view/tpl/new_channel.tpl
index 241846eb4..ff2011181 100755
--- a/view/tpl/new_channel.tpl
+++ b/view/tpl/new_channel.tpl
@@ -5,10 +5,7 @@
<div id="newchannel-desc" class="descriptive-paragraph">{{$desc}}</div>
<div id="newchannel-role-help" class="descriptive-paragraph">{{$help_role}}</div>
-
- <label for="newchannel-role" id="label-newchannel-role" class="newchannel-label" >{{$label_role}}</label>
- {{$role_select}}
- <div class="newchannel-role-morehelp"><a href="help/roles" title="{{$what_is_role}}" target="_blank">{{$questionmark}}</a></div>
+ {{include file="field_select_grouped.tpl" field=$role}}
<div id="newchannel-role-end" class="newchannel-field-end"></div>
diff --git a/view/tpl/profile_hide_friends.tpl b/view/tpl/profile_hide_friends.tpl
index 1d748cd4e..4ed6782bb 100644
--- a/view/tpl/profile_hide_friends.tpl
+++ b/view/tpl/profile_hide_friends.tpl
@@ -1,3 +1,6 @@
+{{include file="field_checkbox.tpl"}}
+
+{{*
<p id="hide-friends-text">
{{$desc}}
</p>
@@ -14,4 +17,4 @@
<div id="hide-friends-end"></div>
</div>
-
+*}}
diff --git a/view/tpl/select_timezone.tpl b/view/tpl/select_timezone.tpl
new file mode 100644
index 000000000..2820a54f4
--- /dev/null
+++ b/view/tpl/select_timezone.tpl
@@ -0,0 +1,11 @@
+{{* TODO: Make id configurabel *}}
+<select id='timezone_select' name='timezone'>
+{{foreach $continents as $continent => $cities}}
+<optgroup label="{{$continent}}">
+{{foreach $cities as $city => $value}}
+<option value='{{$value}}' {{if $value == $selected}}selected='selected'{{/if}}>{{$city}}</option>
+{{/foreach}}
+</optgroup>
+{{/foreach}}
+</select>
+
diff --git a/view/tpl/settings.tpl b/view/tpl/settings.tpl
index 47d85d8e4..894f0fe83 100755
--- a/view/tpl/settings.tpl
+++ b/view/tpl/settings.tpl
@@ -9,7 +9,7 @@
<h3 class="settings-heading">{{$h_basic}}</h3>
{{include file="field_input.tpl" field=$username}}
-{{include file="field_custom.tpl" field=$timezone}}
+{{include file="field_select_grouped.tpl" field=$timezone}}
{{include file="field_input.tpl" field=$defloc}}
{{include file="field_checkbox.tpl" field=$allowloc}}
@@ -22,10 +22,7 @@
<h3 class="settings-heading">{{$h_prv}}</h3>
-<div class="field custom">
-<label for="privacy-role-select">{{$role_lbl}}</label>
-{{$role_select}}
-</div>
+{{include file="field_select_grouped.tpl" field=$role}}
<div id="advanced-perm" style="display:{{if $permissions_set}}none{{else}}block{{/if}};">
{{include file="field_checkbox.tpl" field=$hide_presence}}
@@ -62,7 +59,7 @@
{{$suggestme}}
-{{include file="field_yesno.tpl" field=$blocktags}}
+{{include file="field_checkbox.tpl" field=$blocktags}}
{{include file="field_input.tpl" field=$expire}}
diff --git a/view/tpl/settings_features.tpl b/view/tpl/settings_features.tpl
index 3291162fa..3ede4c76d 100755
--- a/view/tpl/settings_features.tpl
+++ b/view/tpl/settings_features.tpl
@@ -9,7 +9,7 @@
<h3 class="settings-heading">{{$f.0}}</h3>
{{foreach $f.1 as $fcat}}
- {{include file="{{$field_yesno}}" field=$fcat}}
+ {{include file="field_checkbox.tpl" field=$fcat}}
{{/foreach}}
{{/foreach}}